ReactOS 0.4.15-dev-5893-g1bb4167
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
135VOID
137{
140 PLIST_ENTRY ListEntry;
141 LIST_ENTRY ToPost;
143
144 /* Do we have entries to queue after we're done? */
145 InitializeListHead(&ToPost);
148 {
150 {
152 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
153 InsertTailList(&ToPost, &WorkItem->WorkQueueLinks);
154 }
156 }
158
159 /* Our target is one-eighth of the dirty pages */
161 if (Target != 0)
162 {
163 /* There is stuff to flush, schedule a write-behind operation */
164
165 /* Allocate a work item */
166 WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
167 if (WorkItem != NULL)
168 {
169 WorkItem->Function = WriteBehind;
171 }
172 }
173
174 /* Post items that were due for end of run */
175 while (!IsListEmpty(&ToPost))
176 {
177 ListEntry = RemoveHeadList(&ToPost);
178 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
180 }
181
182 /* If we have deferred writes, try them now! */
184 {
186 /* Reschedule immediately a lazy writer run
187 * Keep us active to have short idle delay
188 */
190 }
191 else
192 {
193 /* We're no longer active */
197 }
198}
199
201 IN BOOLEAN NoDelay)
202{
203 /* If no delay, immediately start lazy writer,
204 * no matter it was already started
205 */
206 if (NoDelay)
207 {
210 }
211 /* Otherwise, if it's not running, just wait three seconds to start it */
212 else if (!LazyWriter.ScanActive)
213 {
216 }
217 /* Finally, already running, so queue for the next second */
218 else
219 {
221 }
222}
223
224VOID
225NTAPI
228{
230 BOOLEAN DropThrottle, WritePerformed;
232#if DBG
234#endif
235
236 /* Get back our thread item */
237 Item = Parameter;
238 /* And by default, don't touch throttle */
239 DropThrottle = FALSE;
240 /* No write performed */
241 WritePerformed = FALSE;
242
243#if DBG
244 /* Top level IRP should be clean when started
245 * Save it to catch buggy drivers (or bugs!)
246 */
248 if (TopLevel != NULL)
249 {
250 DPRINT1("(%p) TopLevel IRP for this thread: %p\n", PsGetCurrentThread(), TopLevel);
251 }
252#endif
253
254 /* Loop till we have jobs */
255 while (TRUE)
256 {
258
259 /* Lock queues */
261
262 /* If we have to touch throttle, reset it now! */
263 if (DropThrottle)
264 {
266 DropThrottle = FALSE;
267 }
268
269 /* Check first if we have read ahead to do */
271 {
272 /* If not, check regular queue */
274 {
275 break;
276 }
277 else
278 {
280 }
281 }
282 else
283 {
285 }
286
287 /* Get our work item, if someone is waiting for us to finish
288 * and we're not the only thread in queue
289 * then, quit running to let the others do
290 * and throttle so that noone starts till current activity is over
291 */
292 if (WorkItem->Function == SetDone && CcNumberActiveWorkerThreads > 1)
293 {
295 break;
296 }
297
298 /* Otherwise, remove current entry */
299 RemoveEntryList(&WorkItem->WorkQueueLinks);
301
302 /* And handle it */
303 switch (WorkItem->Function)
304 {
305 case ReadAhead:
306 CcPerformReadAhead(WorkItem->Parameters.Read.FileObject);
307 break;
308
309 case WriteBehind:
310 PsGetCurrentThread()->MemoryMaker = 1;
312 PsGetCurrentThread()->MemoryMaker = 0;
313 WritePerformed = TRUE;
314 break;
315
316 case LazyScan:
318 break;
319
320 case SetDone:
321 KeSetEvent(WorkItem->Parameters.Event.Event, IO_NO_INCREMENT, FALSE);
322 DropThrottle = TRUE;
323 break;
324
325 default:
326 DPRINT1("Ignored item: %p (%d)\n", WorkItem, WorkItem->Function);
327 break;
328 }
329
330 /* And release the item */
331 ExFreeToNPagedLookasideList(&CcTwilightLookasideList, WorkItem);
332 }
333
334 /* Our thread is available again */
336 /* One less worker */
339
340 /* If there are pending write openations and we have at least 20 dirty pages */
342 {
343 /* And if we performed a write operation previously, then
344 * stress the system a bit and reschedule a scan to find
345 * stuff to write
346 */
347 if (WritePerformed)
348 {
350 }
351 }
352
353#if DBG
354 /* Top level shouldn't have changed */
355 if (TopLevel != IoGetTopLevelIrp())
356 {
357 DPRINT1("(%p) Mismatching TopLevel: %p, %p\n", PsGetCurrentThread(), TopLevel, IoGetTopLevelIrp());
358 }
359#endif
360}
361
362/*
363 * @implemented
364 */
366NTAPI
368 VOID)
369{
371 KEVENT WaitEvent;
373
374 /* Allocate a work item */
375 WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
376 if (WorkItem == NULL)
377 {
379 }
380
381 /* We want lazy writer to set our event */
382 WorkItem->Function = SetDone;
384 WorkItem->Parameters.Event.Event = &WaitEvent;
385
386 /* Use the post tick queue */
388 InsertTailList(&CcPostTickWorkQueue, &WorkItem->WorkQueueLinks);
389
390 /* Inform the lazy writer it will have to handle the post tick queue */
392 /* And if it's not running, queue a lazy writer run
393 * And start it NOW, we want the response now
394 */
396 {
398 }
399
401
402 /* And now, wait until lazy writer replies */
403 return KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL);
404}
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:367
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:226
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:200
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:136
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
_In_ PVOID Parameter
Definition: ldrtypes.h:241
#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
ULONG CcTotalDirtyPages
Definition: view.c:56
NTSTATUS CcRosFlushDirtyPages(ULONG Target, PULONG Count, BOOLEAN Wait, BOOLEAN CalledFromLazy)
Definition: view.c:305
@ SetDone
Definition: cc.h:281
@ LazyScan
Definition: cc.h:280
@ WriteBehind
Definition: cc.h:279
@ ReadAhead
Definition: cc.h:278
PIRP NTAPI IoGetTopLevelIrp(VOID)
Definition: irp.c:1843
#define DPRINT
Definition: sndvol32.h:71
Definition: ketypes.h:687
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:792
@ Executive
Definition: ketypes.h:403
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:676
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675
@ LockQueueWorkQueueLock
Definition: ketypes.h:654
@ LockQueueMasterLock
Definition: ketypes.h:651
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:677