00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "cc.h"
00022
00023
00024
00025
00026
00027 #define BugCheckFileId (CACHE_BUG_CHECK_LAZYRITE)
00028
00029
00030
00031
00032
00033 #define me 0x00000020
00034
00035
00036
00037
00038
00039
PWORK_QUEUE_ENTRY
00040
CcReadWorkQueue (
00041 );
00042
00043
VOID
00044
CcLazyWriteScan (
00045 );
00046
00047
00048
VOID
00049 CcScheduleLazyWriteScan (
00050 )
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 {
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
if (
LazyWriter.
ScanActive) {
00087
00088
KeSetTimer( &
LazyWriter.
ScanTimer,
CcIdleDelay, &
LazyWriter.
ScanDpc );
00089
00090 }
else {
00091
00092
LazyWriter.
ScanActive =
TRUE;
00093
KeSetTimer( &
LazyWriter.
ScanTimer,
CcFirstDelay, &
LazyWriter.
ScanDpc );
00094 }
00095 }
00096
00097
00098
VOID
00099 CcScanDpc (
00100 IN
PKDPC Dpc,
00101 IN PVOID DeferredContext,
00102 IN PVOID SystemArgument1,
00103 IN PVOID SystemArgument2
00104 )
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 {
00124
PWORK_QUEUE_ENTRY WorkQueueEntry;
00125
00126 UNREFERENCED_PARAMETER(Dpc);
00127 UNREFERENCED_PARAMETER(DeferredContext);
00128 UNREFERENCED_PARAMETER(SystemArgument1);
00129 UNREFERENCED_PARAMETER(SystemArgument2);
00130
00131 WorkQueueEntry =
CcAllocateWorkQueueEntry();
00132
00133
00134
00135
00136
00137
00138
00139
00140
if (WorkQueueEntry ==
NULL) {
00141
00142
LazyWriter.
ScanActive =
FALSE;
00143
00144 }
else {
00145
00146
00147
00148
00149
00150 WorkQueueEntry->
Function = (UCHAR)
LazyWriteScan;
00151
00152
CcPostWorkQueue( WorkQueueEntry, &
CcRegularWorkQueue );
00153 }
00154 }
00155
00156
00157
NTSTATUS
00158 CcWaitForCurrentLazyWriterActivity (
00159 )
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 {
00184 KIRQL OldIrql;
00185
KEVENT Event;
00186
PWORK_QUEUE_ENTRY WorkQueueEntry;
00187
00188 WorkQueueEntry =
CcAllocateWorkQueueEntry();
00189
00190
if (WorkQueueEntry ==
NULL) {
00191
return STATUS_INSUFFICIENT_RESOURCES;
00192 }
00193
00194 WorkQueueEntry->
Function = (UCHAR)
EventSet;
00195
KeInitializeEvent( &
Event, NotificationEvent,
FALSE );
00196 WorkQueueEntry->
Parameters.Event.Event = &
Event;
00197
00198
00199
00200
00201
00202
00203
00204
CcAcquireMasterLock( &OldIrql );
00205
00206 InsertTailList( &
CcPostTickWorkQueue, &WorkQueueEntry->
WorkQueueLinks );
00207
00208
LazyWriter.
OtherWork =
TRUE;
00209
if (!
LazyWriter.
ScanActive) {
00210
CcScheduleLazyWriteScan();
00211 }
00212
00213
CcReleaseMasterLock( OldIrql );
00214
00215
return KeWaitForSingleObject( &
Event,
Executive,
KernelMode,
FALSE,
NULL );
00216 }
00217
00218
00219
00220
VOID
00221 CcLazyWriteScan (
00222 )
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 {
00243 ULONG PagesToWrite, ForegroundRate, EstimatedDirtyNextInterval;
00244
PSHARED_CACHE_MAP SharedCacheMap, FirstVisited;
00245 KIRQL OldIrql;
00246 ULONG LoopsWithLockHeld = 0;
00247 BOOLEAN AlreadyMoved =
FALSE;
00248
00249 LIST_ENTRY PostTickWorkQueue;
00250
00251
00252
00253
00254
00255
try {
00256
00257
00258
00259
00260
00261
CcAcquireMasterLock( &OldIrql );
00262
00263
if ((
CcTotalDirtyPages == 0) && !
LazyWriter.
OtherWork) {
00264
00265
00266
00267
00268
00269
00270
00271
00272
if (IsListEmpty(&
CcDeferredWrites)) {
00273
00274
LazyWriter.
ScanActive =
FALSE;
00275
CcReleaseMasterLock( OldIrql );
00276
00277 }
else {
00278
00279
CcReleaseMasterLock( OldIrql );
00280
00281
00282
00283
00284
00285
CcPostDeferredWrites();
00286
CcScheduleLazyWriteScan();
00287 }
00288
00289
return;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299 InitializeListHead( &PostTickWorkQueue );
00300
while (!IsListEmpty( &
CcPostTickWorkQueue )) {
00301
00302 PLIST_ENTRY Entry = RemoveHeadList( &
CcPostTickWorkQueue );
00303 InsertTailList( &PostTickWorkQueue, Entry );
00304 }
00305
00306
00307
00308
00309
00310
00311
LazyWriter.
OtherWork =
FALSE;
00312
00313
00314
00315
00316
00317
00318
00319 PagesToWrite =
CcTotalDirtyPages;
00320
if (PagesToWrite >
LAZY_WRITER_MAX_AGE_TARGET) {
00321 PagesToWrite /=
LAZY_WRITER_MAX_AGE_TARGET;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 ForegroundRate = 0;
00333
00334
if ((
CcTotalDirtyPages +
CcPagesWrittenLastTime) >
CcDirtyPagesLastScan) {
00335 ForegroundRate = (
CcTotalDirtyPages +
CcPagesWrittenLastTime) -
00336
CcDirtyPagesLastScan;
00337 }
00338
00339
00340
00341
00342
00343
00344 EstimatedDirtyNextInterval =
CcTotalDirtyPages - PagesToWrite + ForegroundRate;
00345
00346
if (EstimatedDirtyNextInterval >
CcDirtyPageTarget) {
00347 PagesToWrite += EstimatedDirtyNextInterval -
CcDirtyPageTarget;
00348 }
00349
00350
00351
00352
00353
00354
00355
CcDirtyPagesLastScan =
CcTotalDirtyPages;
00356
CcPagesYetToWrite =
CcPagesWrittenLastTime = PagesToWrite;
00357
00358
00359
00360
00361
00362
00363 SharedCacheMap = CONTAINING_RECORD(
CcLazyWriterCursor.
SharedCacheMapLinks.Flink,
00364
SHARED_CACHE_MAP,
00365 SharedCacheMapLinks );
00366
00367
DebugTrace( 0,
me,
"Start of Lazy Writer Scan\n", 0 );
00368
00369
00370
00371
00372
00373
00374
00375
00376 FirstVisited =
NULL;
00377
while ((SharedCacheMap != FirstVisited) &&
00378 (&SharedCacheMap->
SharedCacheMapLinks != &
CcLazyWriterCursor.
SharedCacheMapLinks)) {
00379
00380
if (FirstVisited ==
NULL) {
00381 FirstVisited = SharedCacheMap;
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
if (!
FlagOn(SharedCacheMap->
Flags,
WRITE_QUEUED |
IS_CURSOR)
00404
00405 &&
00406
00407 (((PagesToWrite != 0) && (SharedCacheMap->
DirtyPages != 0) &&
00408 (((++SharedCacheMap->
LazyWritePassCount & 0xF) == 0) ||
00409 !
FlagOn(SharedCacheMap->
Flags,
MODIFIED_WRITE_DISABLED) ||
00410 (
CcCapturedSystemSize ==
MmSmallSystem) ||
00411 (SharedCacheMap->
DirtyPages >= (4 * (
MAX_WRITE_BEHIND /
PAGE_SIZE)))) &&
00412 (!
FlagOn(SharedCacheMap->
FileObject->
Flags,
FO_TEMPORARY_FILE) ||
00413 !
CcCanIWrite(SharedCacheMap->
FileObject,
WRITE_CHARGE_THRESHOLD,
FALSE, MAXUCHAR)))
00414
00415 ||
00416
00417 ((SharedCacheMap->
OpenCount == 0) &&
00418 ((SharedCacheMap->
DirtyPages == 0) ||
00419 (SharedCacheMap->
FileSize.QuadPart == 0))))) {
00420
00421
PWORK_QUEUE_ENTRY WorkQueueEntry;
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 SharedCacheMap->
PagesToWrite = SharedCacheMap->
DirtyPages;
00434
00435
if (
FlagOn(SharedCacheMap->
Flags,
MODIFIED_WRITE_DISABLED) &&
00436 (SharedCacheMap->
PagesToWrite >= (4 * (
MAX_WRITE_BEHIND /
PAGE_SIZE))) &&
00437 (
CcCapturedSystemSize !=
MmSmallSystem)) {
00438
00439 SharedCacheMap->
PagesToWrite /= 8;
00440 }
00441
00442
00443
00444
00445
00446
if (!AlreadyMoved) {
00447
00448
00449
00450
00451
00452
00453
if (SharedCacheMap->
PagesToWrite >= PagesToWrite) {
00454
00455
00456
00457
00458
00459
00460 RemoveEntryList( &
CcLazyWriterCursor.
SharedCacheMapLinks );
00461
00462
00463
00464
00465
00466
00467
if (
FlagOn(SharedCacheMap->
Flags,
MODIFIED_WRITE_DISABLED)) {
00468 InsertHeadList( &SharedCacheMap->
SharedCacheMapLinks, &
CcLazyWriterCursor.
SharedCacheMapLinks );
00469
00470
00471
00472
00473
00474
00475 }
else {
00476 InsertTailList( &SharedCacheMap->
SharedCacheMapLinks, &
CcLazyWriterCursor.
SharedCacheMapLinks );
00477 }
00478
00479 PagesToWrite = 0;
00480 AlreadyMoved =
TRUE;
00481
00482 }
else {
00483
00484 PagesToWrite -= SharedCacheMap->
PagesToWrite;
00485 }
00486 }
00487
00488
00489
00490
00491
00492
00493
SetFlag(SharedCacheMap->
Flags,
WRITE_QUEUED);
00494 SharedCacheMap->
DirtyPages += 1;
00495
00496
CcReleaseMasterLock( OldIrql );
00497
00498
00499
00500
00501
00502 WorkQueueEntry =
CcAllocateWorkQueueEntry();
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
if (WorkQueueEntry ==
NULL) {
00514
00515
CcAcquireMasterLock( &OldIrql );
00516
ClearFlag(SharedCacheMap->
Flags,
WRITE_QUEUED);
00517 SharedCacheMap->
DirtyPages -= 1;
00518
break;
00519 }
00520
00521 WorkQueueEntry->
Function = (UCHAR)
WriteBehind;
00522 WorkQueueEntry->
Parameters.Write.SharedCacheMap = SharedCacheMap;
00523
00524
00525
00526
00527
00528
CcAcquireMasterLock( &OldIrql );
00529 SharedCacheMap->
DirtyPages -= 1;
00530
CcPostWorkQueue( WorkQueueEntry, &
CcRegularWorkQueue );
00531
00532 LoopsWithLockHeld = 0;
00533
00534
00535
00536
00537
00538
00539 }
else if ((++LoopsWithLockHeld >= 20) &&
00540 !
FlagOn(SharedCacheMap->
Flags,
WRITE_QUEUED |
IS_CURSOR)) {
00541
00542
SetFlag(SharedCacheMap->
Flags,
WRITE_QUEUED);
00543 SharedCacheMap->
DirtyPages += 1;
00544
CcReleaseMasterLock( OldIrql );
00545 LoopsWithLockHeld = 0;
00546
CcAcquireMasterLock( &OldIrql );
00547
ClearFlag(SharedCacheMap->
Flags,
WRITE_QUEUED);
00548 SharedCacheMap->
DirtyPages -= 1;
00549 }
00550
00551
00552
00553
00554
00555 SharedCacheMap =
00556 CONTAINING_RECORD( SharedCacheMap->
SharedCacheMapLinks.Flink,
00557
SHARED_CACHE_MAP,
00558 SharedCacheMapLinks );
00559 }
00560
00561
DebugTrace( 0,
me,
"End of Lazy Writer Scan\n", 0 );
00562
00563
00564
00565
00566
00567
while (!IsListEmpty( &PostTickWorkQueue )) {
00568
00569 PLIST_ENTRY Entry = RemoveHeadList( &PostTickWorkQueue );
00570
CcPostWorkQueue( CONTAINING_RECORD( Entry,
WORK_QUEUE_ENTRY, WorkQueueLinks ),
00571 &
CcRegularWorkQueue );
00572 }
00573
00574
00575
00576
00577
00578
CcReleaseMasterLock( OldIrql );
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
if (!IsListEmpty(&
CcDeferredWrites)) {
00590
00591
CcPostDeferredWrites();
00592 }
00593
00594
00595
00596
00597
00598
CcScheduleLazyWriteScan();
00599
00600
00601
00602
00603
00604
00605
00606
00607 } except(
CcExceptionFilter( GetExceptionCode() )) {
00608
00609
CcBugCheck( GetExceptionCode(), 0, 0 );
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00618 LONG
00619 CcExceptionFilter (
00620 IN NTSTATUS ExceptionCode
00621 )
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 {
00642
DebugTrace(0, 0,
"CcExceptionFilter %08lx\n", ExceptionCode);
00643
00644
if (
FsRtlIsNtstatusExpected( ExceptionCode )) {
00645
00646
return EXCEPTION_EXECUTE_HANDLER;
00647
00648 }
else {
00649
00650
return EXCEPTION_CONTINUE_SEARCH;
00651 }
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
VOID
00661
FASTCALL
00662 CcPostWorkQueue (
00663 IN
PWORK_QUEUE_ENTRY WorkQueueEntry,
00664 IN PLIST_ENTRY WorkQueue
00665 )
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685 {
00686 KIRQL OldIrql;
00687 PLIST_ENTRY WorkerThreadEntry =
NULL;
00688
00689
ASSERT(FIELD_OFFSET(
WORK_QUEUE_ITEM,
List) == 0);
00690
00691
DebugTrace(+1,
me,
"CcPostWorkQueue:\n", 0 );
00692
DebugTrace( 0,
me,
" WorkQueueEntry = %08lx\n", WorkQueueEntry );
00693
00694
00695
00696
00697
00698 ExAcquireFastLock( &
CcWorkQueueSpinlock, &OldIrql );
00699 InsertTailList( WorkQueue, &WorkQueueEntry->WorkQueueLinks );
00700
00701
00702
00703
00704
00705
00706
if (!
CcQueueThrottle && !IsListEmpty(&
CcIdleWorkerThreadList)) {
00707 WorkerThreadEntry = RemoveHeadList( &
CcIdleWorkerThreadList );
00708
CcNumberActiveWorkerThreads += 1;
00709 }
00710 ExReleaseFastLock( &
CcWorkQueueSpinlock, OldIrql );
00711
00712
if (WorkerThreadEntry !=
NULL) {
00713
00714
00715
00716
00717
00718
00719 ((
PWORK_QUEUE_ITEM)WorkerThreadEntry)->List.Flink =
NULL;
00720
ExQueueWorkItem( (
PWORK_QUEUE_ITEM)WorkerThreadEntry,
CriticalWorkQueue );
00721 }
00722
00723
00724
00725
00726
00727
DebugTrace(-1,
me,
"CcPostWorkQueue -> VOID\n", 0 );
00728
00729
return;
00730 }
00731
00732
00733
00734
00735
00736
00737
VOID
00738 CcWorkerThread (
00739 PVOID ExWorkQueueItem
00740 )
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 {
00760 KIRQL OldIrql;
00761 PLIST_ENTRY WorkQueue;
00762
PWORK_QUEUE_ENTRY WorkQueueEntry;
00763 BOOLEAN RescanOk =
FALSE;
00764 BOOLEAN DropThrottle =
FALSE;
00765 IO_STATUS_BLOCK IoStatus;
00766
00767 IoStatus.Status = STATUS_SUCCESS;
00768 IoStatus.Information = 0;
00769
00770
ASSERT(FIELD_OFFSET(
WORK_QUEUE_ENTRY, WorkQueueLinks) == 0);
00771
00772
while (
TRUE) {
00773
00774 ExAcquireFastLock( &
CcWorkQueueSpinlock, &OldIrql );
00775
00776
00777
00778
00779
00780
if (DropThrottle) {
00781
00782 DropThrottle =
CcQueueThrottle =
FALSE;
00783 }
00784
00785
00786
00787
00788
00789
if (IoStatus.Information ==
CC_REQUEUE) {
00790
00791 InsertTailList( WorkQueue, &WorkQueueEntry->
WorkQueueLinks );
00792 IoStatus.Information = 0;
00793 }
00794
00795
00796
00797
00798
00799
if (!IsListEmpty(&
CcExpressWorkQueue)) {
00800 WorkQueue = &
CcExpressWorkQueue;
00801
00802
00803
00804
00805
00806 }
else if (!IsListEmpty(&
CcRegularWorkQueue)) {
00807 WorkQueue = &
CcRegularWorkQueue;
00808
00809
00810
00811
00812
00813 }
else {
00814
00815
break;
00816 }
00817
00818 WorkQueueEntry = CONTAINING_RECORD( WorkQueue->Flink,
WORK_QUEUE_ENTRY, WorkQueueLinks );
00819
00820
00821
00822
00823
00824
00825
if (WorkQueueEntry->
Function ==
EventSet &&
CcNumberActiveWorkerThreads > 1) {
00826
00827
CcQueueThrottle =
TRUE;
00828
break;
00829 }
00830
00831
00832
00833
00834
00835 RemoveHeadList( WorkQueue );
00836
00837 ExReleaseFastLock( &
CcWorkQueueSpinlock, OldIrql );
00838
00839
00840
00841
00842
00843
00844
try {
00845
00846
switch (WorkQueueEntry->
Function) {
00847
00848
00849
00850
00851
00852
case ReadAhead:
00853
00854
DebugTrace( 0,
me,
"CcWorkerThread Read Ahead FileObject = %08lx\n",
00855 WorkQueueEntry->
Parameters.Read.FileObject );
00856
00857
CcPerformReadAhead( WorkQueueEntry->
Parameters.Read.FileObject );
00858
00859
break;
00860
00861
00862
00863
00864
00865
case WriteBehind:
00866
00867
DebugTrace( 0,
me,
"CcWorkerThread WriteBehind SharedCacheMap = %08lx\n",
00868 WorkQueueEntry->
Parameters.Write.SharedCacheMap );
00869
00870
CcWriteBehind( WorkQueueEntry->
Parameters.Write.SharedCacheMap, &IoStatus );
00871 RescanOk = (BOOLEAN)
NT_SUCCESS(IoStatus.Status);
00872
break;
00873
00874
00875
00876
00877
00878
00879
case EventSet:
00880
00881
DebugTrace( 0,
me,
"CcWorkerThread SetEvent Event = %08lx\n",
00882 WorkQueueEntry->
Parameters.Event.Event );
00883
00884
KeSetEvent( WorkQueueEntry->
Parameters.Event.Event, 0,
FALSE );
00885 DropThrottle =
TRUE;
00886
break;
00887
00888
00889
00890
00891
00892
case LazyWriteScan:
00893
00894
DebugTrace( 0,
me,
"CcWorkerThread Lazy Write Scan\n", 0 );
00895
00896
CcLazyWriteScan();
00897
break;
00898 }
00899
00900 }
00901 except(
CcExceptionFilter( GetExceptionCode() )) {
00902
00903 NOTHING;
00904 }
00905
00906
00907
00908
00909
00910
if (IoStatus.Information !=
CC_REQUEUE) {
00911
00912
CcFreeWorkQueueEntry( WorkQueueEntry );
00913 }
00914 }
00915
00916
00917
00918
00919
00920 InsertTailList( &
CcIdleWorkerThreadList,
00921 &((
PWORK_QUEUE_ITEM)ExWorkQueueItem)->
List );
00922
CcNumberActiveWorkerThreads -= 1;
00923
00924 ExReleaseFastLock( &
CcWorkQueueSpinlock, OldIrql );
00925
00926
if (!IsListEmpty(&
CcDeferredWrites) && (
CcTotalDirtyPages >= 20) && RescanOk) {
00927
CcLazyWriteScan();
00928 }
00929
00930
return;
00931 }