ReactOS 0.4.15-dev-8100-g1887773
lazywrite.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/lazywrite.c
5 * PURPOSE: Cache manager
6 *
7 * PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
8 */
9
10/* INCLUDES *****************************************************************/
11
12#include <ntoskrnl.h>
13#define NDEBUG
14#include <debug.h>
15
16/* Counters:
17 * - Amount of pages flushed by lazy writer
18 * - Number of times lazy writer ran
19 */
22
23/* Internal vars (MS):
24 * - Lazy writer status structure
25 * - Lookaside list where to allocate work items
26 * - Queue for high priority work items (read ahead)
27 * - Queue for regular work items
28 * - Available worker threads
29 * - Queue for stuff to be queued after lazy writer is done
30 * - Marker for throttling queues
31 * - Number of ongoing workers
32 * - Three seconds delay for lazy writer
33 * - One second delay for lazy writer
34 * - Zero delay for lazy writer
35 * - Number of worker threads
36 */
49
50/* FUNCTIONS *****************************************************************/
51
52VOID
56{
58 PWORK_QUEUE_ITEM ThreadToSpawn;
59
60 /* First of all, insert the item in the queue */
62 InsertTailList(WorkQueue, &WorkItem->WorkQueueLinks);
63
64 /* Now, define whether we have to spawn a new work thread
65 * We will spawn a new one if:
66 * - There's no throttle in action
67 * - There's still at least one idle thread
68 */
69 ThreadToSpawn = NULL;
71 {
72 PLIST_ENTRY ListEntry;
73
74 /* Get the idle thread */
76 ThreadToSpawn = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
77
78 /* We're going to have one more! */
80 }
81
83
84 /* If we have a thread to spawn, do it! */
85 if (ThreadToSpawn != NULL)
86 {
87 /* We NULLify it to be consistent with initialization */
88 ThreadToSpawn->List.Flink = NULL;
89 ExQueueWorkItem(ThreadToSpawn, CriticalWorkQueue);
90 }
91}
92
93VOID
96 IN PKDPC Dpc,
100{
102
103 /* Allocate a work item */
104 WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
105 if (WorkItem == NULL)
106 {
108 return;
109 }
110
111 /* And post it, it will be for lazy write */
112 WorkItem->Function = LazyScan;
114}
115
116VOID
118{
120
122 if (Target != 0)
123 {
124 /* Flush! */
125 DPRINT("Lazy writer starting (%d)\n", Target);
127
128 /* And update stats */
131 DPRINT("Lazy writer done (%d)\n", Count);
132 }
133
134 /* Make sure we're not throttling writes after this */
136 {
137 /* Break if we can't even find one to free */
139 {
140 break;
141 }
142 }
143}
144
145VOID
147{
150 PLIST_ENTRY ListEntry;
151 LIST_ENTRY ToPost;
153
154 /* Do we have entries to queue after we're done? */
155 InitializeListHead(&ToPost);
158 {
160 {
162 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
163 InsertTailList(&ToPost, &WorkItem->WorkQueueLinks);
164 }
166 }
168
169 /* Our target is one-eighth of the dirty pages */
171 if (Target != 0)
172 {
173 /* There is stuff to flush, schedule a write-behind operation */
174
175 /* Allocate a work item */
176 WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
177 if (WorkItem != NULL)
178 {
179 WorkItem->Function = WriteBehind;
181 }
182 }
183
184 /* Post items that were due for end of run */
185 while (!IsListEmpty(&ToPost))
186 {
187 ListEntry = RemoveHeadList(&ToPost);
188 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
190 }
191
192 /* If we have deferred writes, try them now! */
194 {
196 /* Reschedule immediately a lazy writer run
197 * Keep us active to have short idle delay
198 */
200 }
201 else
202 {
203 /* We're no longer active */
207 }
208}
209
211 IN BOOLEAN NoDelay)
212{
213 /* If no delay, immediately start lazy writer,
214 * no matter it was already started
215 */
216 if (NoDelay)
217 {
220 }
221 /* Otherwise, if it's not running, just wait three seconds to start it */
222 else if (!LazyWriter.ScanActive)
223 {
226 }
227 /* Finally, already running, so queue for the next second */
228 else
229 {
231 }
232}
233
234VOID
235NTAPI
238{
240 BOOLEAN DropThrottle, WritePerformed;
242#if DBG
244#endif
245
246 /* Get back our thread item */
247 Item = Parameter;
248 /* And by default, don't touch throttle */
249 DropThrottle = FALSE;
250 /* No write performed */
251 WritePerformed = FALSE;
252
253#if DBG
254 /* Top level IRP should be clean when started
255 * Save it to catch buggy drivers (or bugs!)
256 */
258 if (TopLevel != NULL)
259 {
260 DPRINT1("(%p) TopLevel IRP for this thread: %p\n", PsGetCurrentThread(), TopLevel);
261 }
262#endif
263
264 /* Loop till we have jobs */
265 while (TRUE)
266 {
268
269 /* Lock queues */
271
272 /* If we have to touch throttle, reset it now! */
273 if (DropThrottle)
274 {
276 DropThrottle = FALSE;
277 }
278
279 /* Check first if we have read ahead to do */
281 {
282 /* If not, check regular queue */
284 {
285 break;
286 }
287 else
288 {
290 }
291 }
292 else
293 {
295 }
296
297 /* Get our work item, if someone is waiting for us to finish
298 * and we're not the only thread in queue
299 * then, quit running to let the others do
300 * and throttle so that noone starts till current activity is over
301 */
302 if (WorkItem->Function == SetDone && CcNumberActiveWorkerThreads > 1)
303 {
305 break;
306 }
307
308 /* Otherwise, remove current entry */
309 RemoveEntryList(&WorkItem->WorkQueueLinks);
311
312 /* And handle it */
313 switch (WorkItem->Function)
314 {
315 case ReadAhead:
316 CcPerformReadAhead(WorkItem->Parameters.Read.FileObject);
317 break;
318
319 case WriteBehind:
320 PsGetCurrentThread()->MemoryMaker = 1;
322 PsGetCurrentThread()->MemoryMaker = 0;
323 WritePerformed = TRUE;
324 break;
325
326 case LazyScan:
328 break;
329
330 case SetDone:
331 KeSetEvent(WorkItem->Parameters.Event.Event, IO_NO_INCREMENT, FALSE);
332 DropThrottle = TRUE;
333 break;
334
335 default:
336 DPRINT1("Ignored item: %p (%d)\n", WorkItem, WorkItem->Function);
337 break;
338 }
339
340 /* And release the item */
341 ExFreeToNPagedLookasideList(&CcTwilightLookasideList, WorkItem);
342 }
343
344 /* Our thread is available again */
346 /* One less worker */
349
350 /* If there are pending write openations and we have at least 20 dirty pages */
352 {
353 /* And if we performed a write operation previously, then
354 * stress the system a bit and reschedule a scan to find
355 * stuff to write
356 */
357 if (WritePerformed)
358 {
360 }
361 }
362
363#if DBG
364 /* Top level shouldn't have changed */
365 if (TopLevel != IoGetTopLevelIrp())
366 {
367 DPRINT1("(%p) Mismatching TopLevel: %p, %p\n", PsGetCurrentThread(), TopLevel, IoGetTopLevelIrp());
368 }
369#endif
370}
371
372/*
373 * @implemented
374 */
376NTAPI
378 VOID)
379{
381 KEVENT WaitEvent;
383
384 /* Allocate a work item */
385 WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
386 if (WorkItem == NULL)
387 {
389 }
390
391 /* We want lazy writer to set our event */
392 WorkItem->Function = SetDone;
394 WorkItem->Parameters.Event.Event = &WaitEvent;
395
396 /* Use the post tick queue */
398 InsertTailList(&CcPostTickWorkQueue, &WorkItem->WorkQueueLinks);
399
400 /* Inform the lazy writer it will have to handle the post tick queue */
402 /* And if it's not running, queue a lazy writer run
403 * And start it NOW, we want the response now
404 */
406 {
408 }
409
411
412 /* And now, wait until lazy writer replies */
413 return KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL);
414}
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2417
VOID FASTCALL KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, IN KIRQL OldIrql)
Definition: spinlock.c:154
KIRQL FASTCALL KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber)
Definition: spinlock.c:108
NTSTATUS NTAPI CcWaitForCurrentLazyWriterActivity(VOID)
Definition: lazywrite.c:377
VOID CcWriteBehind(VOID)
Definition: lazywrite.c:117
NPAGED_LOOKASIDE_LIST CcTwilightLookasideList
Definition: lazywrite.c:38
LARGE_INTEGER CcFirstDelay
Definition: lazywrite.c:45
VOID NTAPI CcWorkerThread(IN PVOID Parameter)
Definition: lazywrite.c:236
ULONG CcLazyWritePages
Definition: lazywrite.c:20
LIST_ENTRY CcRegularWorkQueue
Definition: lazywrite.c:40
VOID CcPostWorkQueue(IN PWORK_QUEUE_ENTRY WorkItem, IN PLIST_ENTRY WorkQueue)
Definition: lazywrite.c:53
LARGE_INTEGER CcIdleDelay
Definition: lazywrite.c:46
LARGE_INTEGER CcNoDelay
Definition: lazywrite.c:47
LIST_ENTRY CcExpressWorkQueue
Definition: lazywrite.c:39
ULONG CcNumberActiveWorkerThreads
Definition: lazywrite.c:44
VOID CcScheduleLazyWriteScan(IN BOOLEAN NoDelay)
Definition: lazywrite.c:210
LIST_ENTRY CcPostTickWorkQueue
Definition: lazywrite.c:42
LIST_ENTRY CcIdleWorkerThreadList
Definition: lazywrite.c:41
BOOLEAN CcQueueThrottle
Definition: lazywrite.c:43
VOID CcLazyWriteScan(VOID)
Definition: lazywrite.c:146
ULONG CcNumberWorkerThreads
Definition: lazywrite.c:48
LAZY_WRITER LazyWriter
Definition: lazywrite.c:37
ULONG CcLazyWriteIos
Definition: lazywrite.c:21
VOID NTAPI CcScanDpc(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: lazywrite.c:95
#define KernelMode
Definition: asm.h:34
#define RTL_CONSTANT_LARGE_INTEGER(quad_part)
Definition: rtltypes.h:418
int Count
Definition: noreturn.cpp:7
@ NotificationEvent
VOID CcPostDeferredWrites(VOID)
Definition: copy.c:73
VOID CcPerformReadAhead(IN PFILE_OBJECT FileObject)
Definition: copy.c:130
LIST_ENTRY CcDeferredWrites
Definition: view.c:57
BOOLEAN CcRosFreeOneUnusedVacb(VOID)
Definition: view.c:737
ULONG CcTotalDirtyPages
Definition: view.c:56
NTSTATUS CcRosFlushDirtyPages(ULONG Target, PULONG Count, BOOLEAN Wait, BOOLEAN CalledFromLazy)
Definition: view.c:308
@ SetDone
Definition: cc.h:281
@ LazyScan
Definition: cc.h:280
@ WriteBehind
Definition: cc.h:279
@ ReadAhead
Definition: cc.h:278
ULONG MmThrottleTop
Definition: mminit.c:396
PFN_NUMBER MmAvailablePages
Definition: freelist.c:26
PIRP NTAPI IoGetTopLevelIrp(VOID)
Definition: irp.c:1843
#define DPRINT
Definition: sndvol32.h:73
Definition: ketypes.h:699
BOOLEAN OtherWork
Definition: cc.h:247
KDPC ScanDpc
Definition: cc.h:244
KTIMER ScanTimer
Definition: cc.h:245
BOOLEAN ScanActive
Definition: cc.h:246
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: cc.h:252
LIST_ENTRY List
Definition: extypes.h:203
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
int64_t LONGLONG
Definition: typedefs.h:68
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFCOLLECTION _In_ WDFOBJECT Item
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:723
LIST_ENTRY WorkQueue
Definition: workqueue.c:16
@ CriticalWorkQueue
Definition: extypes.h:189
struct LOOKASIDE_ALIGN _NPAGED_LOOKASIDE_LIST NPAGED_LOOKASIDE_LIST
#define IO_NO_INCREMENT
Definition: iotypes.h:598
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ Executive
Definition: ketypes.h:415
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:687
@ LockQueueWorkQueueLock
Definition: ketypes.h:666
@ LockQueueMasterLock
Definition: ketypes.h:663
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:323