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 me 0x00000004
00028
00029
00030 BOOLEAN
00031 CcCopyRead (
00032 IN
PFILE_OBJECT FileObject,
00033 IN PLARGE_INTEGER FileOffset,
00034 IN ULONG Length,
00035 IN BOOLEAN Wait,
00036 OUT PVOID Buffer,
00037 OUT PIO_STATUS_BLOCK IoStatus
00038 )
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
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
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 {
00101
PSHARED_CACHE_MAP SharedCacheMap;
00102
PPRIVATE_CACHE_MAP PrivateCacheMap;
00103 PVOID CacheBuffer;
00104 LARGE_INTEGER FOffset;
00105
PVACB Vacb;
00106
PBCB Bcb;
00107
PVACB ActiveVacb;
00108 ULONG ActivePage;
00109 ULONG PageIsDirty;
00110 ULONG SavedState;
00111 ULONG PagesToGo;
00112 ULONG MoveLength;
00113 ULONG LengthToGo;
00114 KIRQL OldIrql;
00115
NTSTATUS Status;
00116 ULONG OriginalLength = Length;
00117 ULONG PageCount =
COMPUTE_PAGES_SPANNED((ULongToPtr(FileOffset->LowPart)), Length);
00118
PETHREAD Thread =
PsGetCurrentThread();
00119 ULONG GotAMiss = 0;
00120
00121
DebugTrace(+1,
me,
"CcCopyRead\n", 0 );
00122
00123
MmSavePageFaultReadAhead( Thread, &SavedState );
00124
00125
00126
00127
00128
00129 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
00130 PrivateCacheMap = FileObject->PrivateCacheMap;
00131
00132
00133
00134
00135
00136
ASSERT( ( FileOffset->QuadPart + (LONGLONG)Length) <= SharedCacheMap->
FileSize.QuadPart );
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
if (PrivateCacheMap->
ReadAheadEnabled && (PrivateCacheMap->
ReadAheadLength[1] == 0)) {
00147
CcScheduleReadAhead( FileObject, FileOffset, Length );
00148 }
00149
00150 FOffset = *FileOffset;
00151
00152
00153
00154
00155
00156
if (Wait) {
00157
HOT_STATISTIC(
CcCopyReadWait) += 1;
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
CcMissCounter = &
CcCopyReadWaitMiss;
00168
00169 }
else {
00170
HOT_STATISTIC(
CcCopyReadNoWait) += 1;
00171 }
00172
00173
00174
00175
00176
00177
GetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
00178
00179
if (ActiveVacb !=
NULL) {
00180
00181
if ((ULONG)(FOffset.QuadPart >>
VACB_OFFSET_SHIFT) == (ActivePage >> (
VACB_OFFSET_SHIFT -
PAGE_SHIFT))) {
00182
00183 ULONG LengthToCopy =
VACB_MAPPING_GRANULARITY - (FOffset.LowPart & (
VACB_MAPPING_GRANULARITY - 1));
00184
00185
if (SharedCacheMap->
NeedToZero !=
NULL) {
00186
CcFreeActiveVacb( SharedCacheMap,
NULL, 0,
FALSE );
00187 }
00188
00189
00190
00191
00192
00193 CacheBuffer = (PVOID)((PCHAR)ActiveVacb->
BaseAddress +
00194 (FOffset.LowPart & (
VACB_MAPPING_GRANULARITY - 1)));
00195
00196
00197
00198
00199
00200
if (LengthToCopy > Length) {
00201 LengthToCopy = Length;
00202 }
00203
00204
00205
00206
00207
00208
00209 PagesToGo =
COMPUTE_PAGES_SPANNED( CacheBuffer,
00210 LengthToCopy ) - 1;
00211
00212
00213
00214
00215
00216
try {
00217
00218
if (PagesToGo != 0) {
00219
00220 LengthToGo = LengthToCopy;
00221
00222
while (LengthToGo != 0) {
00223
00224 MoveLength = (ULONG)((PCHAR)(
ROUND_TO_PAGES(((PCHAR)CacheBuffer + 1))) -
00225 (PCHAR)CacheBuffer);
00226
00227
if (MoveLength > LengthToGo) {
00228 MoveLength = LengthToGo;
00229 }
00230
00231
00232
00233
00234
00235
00236
00237
MmSetPageFaultReadAhead( Thread, PagesToGo );
00238 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00239
00240 RtlCopyBytes(
Buffer, CacheBuffer, MoveLength );
00241
00242 PagesToGo -= 1;
00243
00244 LengthToGo -= MoveLength;
00245
Buffer = (PCHAR)
Buffer + MoveLength;
00246 CacheBuffer = (PCHAR)CacheBuffer + MoveLength;
00247 }
00248
00249
00250
00251
00252
00253 }
else {
00254
00255
00256
00257
00258
00259
00260
00261
MmSetPageFaultReadAhead( Thread, 0 );
00262 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00263
00264 RtlCopyBytes(
Buffer, CacheBuffer, LengthToCopy );
00265
00266
Buffer = (PCHAR)
Buffer + LengthToCopy;
00267 }
00268
00269 } except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
00270 &
Status ) ) {
00271
00272
MmResetPageFaultReadAhead( Thread, SavedState );
00273
00274
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
00275
00276
00277
00278
00279
00280
00281
00282
if (
Status == STATUS_ACCESS_VIOLATION) {
00283
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
00284 }
00285
else {
00286
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status,
00287 STATUS_UNEXPECTED_IO_ERROR ));
00288 }
00289 }
00290
00291
00292
00293
00294
00295 FOffset.QuadPart = FOffset.QuadPart + (LONGLONG)LengthToCopy;
00296 Length -= LengthToCopy;
00297
00298 }
00299
00300
00301
00302
00303
00304
if (Length == 0) {
00305
00306
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
00307
00308
00309
00310
00311
00312 }
else {
00313
00314
CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty );
00315 }
00316 }
00317
00318
00319
00320
00321
00322
00323
while (Length != 0) {
00324
00325 ULONG ReceivedLength;
00326 LARGE_INTEGER BeyondLastByte;
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
if (Wait) {
00341
00342 CacheBuffer =
CcGetVirtualAddress( SharedCacheMap,
00343 FOffset,
00344 &Vacb,
00345 &ReceivedLength );
00346
00347 BeyondLastByte.QuadPart = FOffset.QuadPart + (LONGLONG)ReceivedLength;
00348
00349 }
else if (!
CcPinFileData( FileObject,
00350 &FOffset,
00351 Length,
00352
TRUE,
00353
FALSE,
00354
FALSE,
00355 &Bcb,
00356 &CacheBuffer,
00357 &BeyondLastByte )) {
00358
00359
DebugTrace(-1,
me,
"CcCopyRead -> FALSE\n", 0 );
00360
00361
HOT_STATISTIC(
CcCopyReadNoWaitMiss) += 1;
00362
00363
00364
00365
00366
00367 PrivateCacheMap->
ReadAheadEnabled =
TRUE;
00368
00369
return FALSE;
00370
00371 }
else {
00372
00373
00374
00375
00376
00377
00378 ReceivedLength = (ULONG)(BeyondLastByte.QuadPart - FOffset.QuadPart);
00379 }
00380
00381
00382
00383
00384
00385
00386
if (ReceivedLength > Length) {
00387 ReceivedLength = Length;
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
try {
00400
00401 PagesToGo =
COMPUTE_PAGES_SPANNED( CacheBuffer,
00402 ReceivedLength ) - 1;
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
if (PagesToGo != 0) {
00423
00424 LengthToGo = ReceivedLength;
00425
00426
while (LengthToGo != 0) {
00427
00428 MoveLength = (ULONG)((PCHAR)(
ROUND_TO_PAGES(((PCHAR)CacheBuffer + 1))) -
00429 (PCHAR)CacheBuffer);
00430
00431
if (MoveLength > LengthToGo) {
00432 MoveLength = LengthToGo;
00433 }
00434
00435
00436
00437
00438
00439
00440
00441
MmSetPageFaultReadAhead( Thread, PagesToGo );
00442 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00443
00444 RtlCopyBytes(
Buffer, CacheBuffer, MoveLength );
00445
00446 PagesToGo -= 1;
00447
00448 LengthToGo -= MoveLength;
00449
Buffer = (PCHAR)
Buffer + MoveLength;
00450 CacheBuffer = (PCHAR)CacheBuffer + MoveLength;
00451 }
00452
00453
00454
00455
00456
00457 }
else {
00458
00459
00460
00461
00462
00463
00464
00465
MmSetPageFaultReadAhead( Thread, 0 );
00466 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00467
00468 RtlCopyBytes(
Buffer, CacheBuffer, ReceivedLength );
00469
00470
Buffer = (PCHAR)
Buffer + ReceivedLength;
00471 }
00472
00473 }
00474 except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
00475 &
Status ) ) {
00476
00477
CcMissCounter = &
CcThrowAway;
00478
00479
00480
00481
00482
00483
00484
MmResetPageFaultReadAhead( Thread, SavedState );
00485
00486
00487
if (Wait) {
00488
CcFreeVirtualAddress( Vacb );
00489 }
else {
00490
CcUnpinFileData( Bcb,
TRUE,
UNPIN );
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
if (
Status == STATUS_ACCESS_VIOLATION) {
00500
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
00501 }
00502
else {
00503
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status,
00504 STATUS_UNEXPECTED_IO_ERROR ));
00505 }
00506 }
00507
00508
00509
00510
00511
00512 Length -= ReceivedLength;
00513
00514
00515
00516
00517
00518
if (Wait) {
00519
00520
00521
00522
00523
00524
if (Length != 0) {
00525
00526
CcFreeVirtualAddress( Vacb );
00527
00528
00529
00530
00531
00532 }
else {
00533
00534
SetActiveVacb( SharedCacheMap, OldIrql, Vacb, (ULONG)(FOffset.QuadPart >>
PAGE_SHIFT), 0 );
00535
break;
00536 }
00537
00538 }
else {
00539
CcUnpinFileData( Bcb,
TRUE,
UNPIN );
00540 }
00541
00542
00543
00544
00545
00546
00547 FOffset = BeyondLastByte;
00548 }
00549
00550
MmResetPageFaultReadAhead( Thread, SavedState );
00551
00552
CcMissCounter = &
CcThrowAway;
00553
00554
00555
00556
00557
00558
00559
if (GotAMiss &&
00560 !
FlagOn( FileObject->Flags,
FO_RANDOM_ACCESS ) &&
00561 !PrivateCacheMap->
ReadAheadEnabled) {
00562
00563 PrivateCacheMap->
ReadAheadEnabled =
TRUE;
00564
CcScheduleReadAhead( FileObject, FileOffset, OriginalLength );
00565 }
00566
00567
00568
00569
00570
00571
00572 PrivateCacheMap->
FileOffset1 = PrivateCacheMap->
FileOffset2;
00573 PrivateCacheMap->
BeyondLastByte1 = PrivateCacheMap->
BeyondLastByte2;
00574 PrivateCacheMap->
FileOffset2 = *FileOffset;
00575 PrivateCacheMap->
BeyondLastByte2.QuadPart =
00576 FileOffset->QuadPart + (LONGLONG)OriginalLength;
00577
00578 IoStatus->Status = STATUS_SUCCESS;
00579 IoStatus->Information = OriginalLength;
00580
00581
DebugTrace(-1,
me,
"CcCopyRead -> TRUE\n", 0 );
00582
00583
return TRUE;
00584 }
00585
00586
00587
VOID
00588 CcFastCopyRead (
00589 IN
PFILE_OBJECT FileObject,
00590 IN ULONG FileOffset,
00591 IN ULONG Length,
00592 IN ULONG PageCount,
00593 OUT PVOID Buffer,
00594 OUT PIO_STATUS_BLOCK IoStatus
00595 )
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 {
00638
PSHARED_CACHE_MAP SharedCacheMap;
00639
PPRIVATE_CACHE_MAP PrivateCacheMap;
00640 PVOID CacheBuffer;
00641 LARGE_INTEGER FOffset;
00642
PVACB Vacb;
00643
PVACB ActiveVacb;
00644 ULONG ActivePage;
00645 ULONG PageIsDirty;
00646 ULONG SavedState;
00647 ULONG PagesToGo;
00648 ULONG MoveLength;
00649 ULONG LengthToGo;
00650 KIRQL OldIrql;
00651
NTSTATUS Status;
00652 LARGE_INTEGER OriginalOffset;
00653 ULONG OriginalLength = Length;
00654
PETHREAD Thread =
PsGetCurrentThread();
00655 ULONG GotAMiss = 0;
00656
00657
DebugTrace(+1,
me,
"CcFastCopyRead\n", 0 );
00658
00659
MmSavePageFaultReadAhead( Thread, &SavedState );
00660
00661
00662
00663
00664
00665 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
00666 PrivateCacheMap = FileObject->PrivateCacheMap;
00667
00668
00669
00670
00671
00672
ASSERT( (FileOffset + Length) <= SharedCacheMap->
FileSize.LowPart );
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 OriginalOffset.LowPart = FileOffset;
00683 OriginalOffset.HighPart = 0;
00684
00685
if (PrivateCacheMap->
ReadAheadEnabled && (PrivateCacheMap->
ReadAheadLength[1] == 0)) {
00686
CcScheduleReadAhead( FileObject, &OriginalOffset, Length );
00687 }
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
CcMissCounter = &
CcCopyReadWaitMiss;
00698
00699
00700
00701
00702
00703
HOT_STATISTIC(
CcCopyReadWait) += 1;
00704
00705
00706
00707
00708
00709
GetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
00710
00711
if (ActiveVacb !=
NULL) {
00712
00713
if ((FileOffset >>
VACB_OFFSET_SHIFT) == (ActivePage >> (
VACB_OFFSET_SHIFT -
PAGE_SHIFT))) {
00714
00715 ULONG LengthToCopy =
VACB_MAPPING_GRANULARITY - (FileOffset & (
VACB_MAPPING_GRANULARITY - 1));
00716
00717
if (SharedCacheMap->
NeedToZero !=
NULL) {
00718
CcFreeActiveVacb( SharedCacheMap,
NULL, 0,
FALSE );
00719 }
00720
00721
00722
00723
00724
00725 CacheBuffer = (PVOID)((PCHAR)ActiveVacb->
BaseAddress +
00726 (FileOffset & (
VACB_MAPPING_GRANULARITY - 1)));
00727
00728
00729
00730
00731
00732
if (LengthToCopy > Length) {
00733 LengthToCopy = Length;
00734 }
00735
00736
00737
00738
00739
00740
00741 PagesToGo =
COMPUTE_PAGES_SPANNED( CacheBuffer,
00742 LengthToCopy ) - 1;
00743
00744
00745
00746
00747
00748
try {
00749
00750
if (PagesToGo != 0) {
00751
00752 LengthToGo = LengthToCopy;
00753
00754
while (LengthToGo != 0) {
00755
00756 MoveLength = (ULONG)((PCHAR)(
ROUND_TO_PAGES(((PCHAR)CacheBuffer + 1))) -
00757 (PCHAR)CacheBuffer);
00758
00759
if (MoveLength > LengthToGo) {
00760 MoveLength = LengthToGo;
00761 }
00762
00763
00764
00765
00766
00767
00768
00769
MmSetPageFaultReadAhead( Thread, PagesToGo );
00770 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00771
00772 RtlCopyBytes(
Buffer, CacheBuffer, MoveLength );
00773
00774 PagesToGo -= 1;
00775
00776 LengthToGo -= MoveLength;
00777
Buffer = (PCHAR)
Buffer + MoveLength;
00778 CacheBuffer = (PCHAR)CacheBuffer + MoveLength;
00779 }
00780
00781
00782
00783
00784
00785 }
else {
00786
00787
00788
00789
00790
00791
00792
00793
MmSetPageFaultReadAhead( Thread, 0 );
00794 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00795
00796 RtlCopyBytes(
Buffer, CacheBuffer, LengthToCopy );
00797
00798
Buffer = (PCHAR)
Buffer + LengthToCopy;
00799 }
00800
00801 } except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
00802 &
Status ) ) {
00803
00804
MmResetPageFaultReadAhead( Thread, SavedState );
00805
00806
00807
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
00808
00809
00810
00811
00812
00813
00814
00815
if (
Status == STATUS_ACCESS_VIOLATION) {
00816
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
00817 }
00818
else {
00819
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status,
00820 STATUS_UNEXPECTED_IO_ERROR ));
00821 }
00822 }
00823
00824
00825
00826
00827
00828 FileOffset += LengthToCopy;
00829 Length -= LengthToCopy;
00830 }
00831
00832
00833
00834
00835
00836
if (Length == 0) {
00837
00838
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
00839
00840
00841
00842
00843
00844 }
else {
00845
00846
CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty );
00847 }
00848 }
00849
00850
00851
00852
00853
00854
00855 FOffset.HighPart = 0;
00856 FOffset.LowPart = FileOffset;
00857
00858
while (Length != 0) {
00859
00860 ULONG ReceivedLength;
00861 ULONG BeyondLastByte;
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875 CacheBuffer =
CcGetVirtualAddress( SharedCacheMap,
00876 FOffset,
00877 &Vacb,
00878 &ReceivedLength );
00879
00880 BeyondLastByte = FOffset.LowPart + ReceivedLength;
00881
00882
00883
00884
00885
00886
00887
if (ReceivedLength > Length) {
00888 ReceivedLength = Length;
00889 }
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
try {
00901
00902 PagesToGo =
COMPUTE_PAGES_SPANNED( CacheBuffer,
00903 ReceivedLength ) - 1;
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
if (PagesToGo != 0) {
00924
00925 LengthToGo = ReceivedLength;
00926
00927
while (LengthToGo != 0) {
00928
00929 MoveLength = (ULONG)((PCHAR)(
ROUND_TO_PAGES(((PCHAR)CacheBuffer + 1))) -
00930 (PCHAR)CacheBuffer);
00931
00932
if (MoveLength > LengthToGo) {
00933 MoveLength = LengthToGo;
00934 }
00935
00936
00937
00938
00939
00940
00941
00942
MmSetPageFaultReadAhead( Thread, PagesToGo );
00943 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00944
00945 RtlCopyBytes(
Buffer, CacheBuffer, MoveLength );
00946
00947 PagesToGo -= 1;
00948
00949 LengthToGo -= MoveLength;
00950
Buffer = (PCHAR)
Buffer + MoveLength;
00951 CacheBuffer = (PCHAR)CacheBuffer + MoveLength;
00952 }
00953
00954
00955
00956
00957
00958 }
else {
00959
00960
00961
00962
00963
00964
00965
00966
MmSetPageFaultReadAhead( Thread, 0 );
00967 GotAMiss |= !
MmCheckCachedPageState( CacheBuffer,
FALSE );
00968
00969 RtlCopyBytes(
Buffer, CacheBuffer, ReceivedLength );
00970
00971
Buffer = (PCHAR)
Buffer + ReceivedLength;
00972 }
00973 }
00974 except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
00975 &
Status ) ) {
00976
00977
CcMissCounter = &
CcThrowAway;
00978
00979
00980
00981
00982
00983
00984
MmResetPageFaultReadAhead( Thread, SavedState );
00985
00986
00987
CcFreeVirtualAddress( Vacb );
00988
00989
00990
00991
00992
00993
00994
00995
if (
Status == STATUS_ACCESS_VIOLATION) {
00996
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
00997 }
00998
else {
00999
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status,
01000 STATUS_UNEXPECTED_IO_ERROR ));
01001 }
01002 }
01003
01004
01005
01006
01007
01008 Length -= ReceivedLength;
01009
01010
01011
01012
01013
01014
if (Length != 0) {
01015
01016
01017
01018
01019
01020
CcFreeVirtualAddress( Vacb );
01021
01022 }
else {
01023
01024
01025
01026
01027
01028
SetActiveVacb( SharedCacheMap, OldIrql, Vacb, (FOffset.LowPart >>
PAGE_SHIFT), 0 );
01029
break;
01030 }
01031
01032
01033
01034
01035
01036
01037 FOffset.LowPart = BeyondLastByte;
01038 }
01039
01040
MmResetPageFaultReadAhead( Thread, SavedState );
01041
01042
CcMissCounter = &
CcThrowAway;
01043
01044
01045
01046
01047
01048
01049
if (GotAMiss &&
01050 !
FlagOn( FileObject->Flags,
FO_RANDOM_ACCESS ) &&
01051 !PrivateCacheMap->
ReadAheadEnabled) {
01052
01053 PrivateCacheMap->
ReadAheadEnabled =
TRUE;
01054
CcScheduleReadAhead( FileObject, &OriginalOffset, OriginalLength );
01055 }
01056
01057
01058
01059
01060
01061
01062 PrivateCacheMap->
FileOffset1.LowPart = PrivateCacheMap->
FileOffset2.LowPart;
01063 PrivateCacheMap->
BeyondLastByte1.LowPart = PrivateCacheMap->
BeyondLastByte2.LowPart;
01064 PrivateCacheMap->
FileOffset2.LowPart = OriginalOffset.LowPart;
01065 PrivateCacheMap->
BeyondLastByte2.LowPart = OriginalOffset.LowPart + OriginalLength;
01066
01067 IoStatus->Status = STATUS_SUCCESS;
01068 IoStatus->Information = OriginalLength;
01069
01070
DebugTrace(-1,
me,
"CcFastCopyRead -> VOID\n", 0 );
01071 }
01072
01073
01074 BOOLEAN
01075 CcCopyWrite (
01076 IN
PFILE_OBJECT FileObject,
01077 IN PLARGE_INTEGER FileOffset,
01078 IN ULONG Length,
01079 IN BOOLEAN Wait,
01080 IN PVOID Buffer
01081 )
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 {
01141
PSHARED_CACHE_MAP SharedCacheMap;
01142
PFSRTL_ADVANCED_FCB_HEADER FcbHeader;
01143
PVACB ActiveVacb;
01144 ULONG ActivePage;
01145 PVOID ActiveAddress;
01146 ULONG PageIsDirty;
01147 KIRQL OldIrql;
01148
NTSTATUS Status;
01149 PVOID CacheBuffer;
01150 LARGE_INTEGER FOffset;
01151
PBCB Bcb;
01152 ULONG ZeroFlags;
01153 LARGE_INTEGER Temp;
01154
01155
DebugTrace(+1,
me,
"CcCopyWrite\n", 0 );
01156
01157
01158
01159
01160
01161
01162
if ((FileObject->Flags &
FO_WRITE_THROUGH) && !Wait) {
01163
01164
DebugTrace(-1,
me,
"CcCopyWrite->FALSE (WriteThrough && !Wait)\n", 0 );
01165
01166
return FALSE;
01167 }
01168
01169
01170
01171
01172
01173 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
01174 FOffset = *FileOffset;
01175
01176
01177
01178
01179
01180
GetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
01181
01182
if (ActiveVacb !=
NULL) {
01183
01184
01185
01186
01187
01188
01189
01190
if (((ULONG)(FOffset.QuadPart >>
PAGE_SHIFT) == ActivePage) && (Length != 0) &&
01191 !
FlagOn( FileObject->Flags,
FO_WRITE_THROUGH )) {
01192
01193 ULONG LengthToCopy =
PAGE_SIZE - (FOffset.LowPart & (
PAGE_SIZE - 1));
01194
01195
01196
01197
01198
01199
if (LengthToCopy > Length) {
01200 LengthToCopy = Length;
01201 }
01202
01203
01204
01205
01206
01207
try {
01208
01209
01210
01211
01212
01213
01214
01215 OldIrql = 0xFF;
01216
01217 CacheBuffer = (PVOID)((PCHAR)ActiveVacb->
BaseAddress +
01218 (FOffset.LowPart & (
VACB_MAPPING_GRANULARITY - 1)));
01219
01220
if (SharedCacheMap->
NeedToZero !=
NULL) {
01221
01222
01223
01224
01225
01226 OldIrql = 0;
01227
01228 ExAcquireFastLock( &SharedCacheMap->
ActiveVacbSpinLock, &OldIrql );
01229
01230
01231
01232
01233
01234
01235 ActiveAddress = SharedCacheMap->
NeedToZero;
01236
if ((ActiveAddress !=
NULL) &&
01237 (ActiveVacb == SharedCacheMap->
NeedToZeroVacb) &&
01238 (((PCHAR)CacheBuffer + LengthToCopy) > (PCHAR)ActiveAddress)) {
01239
01240
01241
01242
01243
01244
01245
if ((PCHAR)CacheBuffer > (PCHAR)ActiveAddress) {
01246
01247 RtlZeroMemory( ActiveAddress, (PCHAR)CacheBuffer - (PCHAR)ActiveAddress );
01248 }
01249 SharedCacheMap->
NeedToZero = (PVOID)((PCHAR)CacheBuffer + LengthToCopy);
01250 }
01251
01252 ExReleaseFastLock( &SharedCacheMap->
ActiveVacbSpinLock, OldIrql );
01253 }
01254
01255 RtlCopyBytes( CacheBuffer,
Buffer, LengthToCopy );
01256
01257 } except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
01258 &
Status ) ) {
01259
01260
01261
01262
01263
01264
01265
if (OldIrql != 0xFF) {
01266 RtlZeroBytes( CacheBuffer, LengthToCopy );
01267 }
01268
01269
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage,
ACTIVE_PAGE_IS_DIRTY );
01270
01271
01272
01273
01274
01275
01276
01277
if (
Status == STATUS_ACCESS_VIOLATION) {
01278
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
01279 }
01280
else {
01281
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status,
01282 STATUS_UNEXPECTED_IO_ERROR ));
01283 }
01284 }
01285
01286
01287
01288
01289
01290
Buffer = (PVOID)((PCHAR)
Buffer + LengthToCopy);
01291 FOffset.QuadPart = FOffset.QuadPart + (LONGLONG)LengthToCopy;
01292 Length -= LengthToCopy;
01293
01294
01295
01296
01297
01298
if (Length == 0) {
01299
01300
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage,
ACTIVE_PAGE_IS_DIRTY );
01301
return TRUE;
01302 }
01303
01304
01305
01306
01307
01308 PageIsDirty |=
ACTIVE_PAGE_IS_DIRTY;
01309 }
01310
01311
CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty );
01312
01313
01314
01315
01316
01317
01318 }
else if (SharedCacheMap->
NeedToZero !=
NULL) {
01319
01320
CcFreeActiveVacb( SharedCacheMap,
NULL, 0,
FALSE );
01321 }
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331 ZeroFlags =
ZERO_MIDDLE_PAGES;
01332
01333
if (((FOffset.LowPart & (
PAGE_SIZE - 1)) == 0) &&
01334 (Length >=
PAGE_SIZE)) {
01335 ZeroFlags |=
ZERO_FIRST_PAGE;
01336 }
01337
01338
if (((FOffset.LowPart + Length) & (
PAGE_SIZE - 1)) == 0) {
01339 ZeroFlags |=
ZERO_LAST_PAGE;
01340 }
01341
01342 Temp = FOffset;
01343 Temp.LowPart &= ~(
PAGE_SIZE -1);
01344
01345
01346
01347
01348
01349
01350
01351 FcbHeader = (
PFSRTL_ADVANCED_FCB_HEADER)FileObject->FsContext;
01352
if (
FlagOn(FcbHeader->Flags,
FSRTL_FLAG_ADVANCED_HEADER)) {
01353 ExAcquireFastMutex( FcbHeader->FastMutex );
01354 Temp.QuadPart = ((
PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->ValidDataLength.QuadPart -
01355 Temp.QuadPart;
01356 ExReleaseFastMutex( FcbHeader->FastMutex );
01357 }
else {
01358 Temp.QuadPart = ((
PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->ValidDataLength.QuadPart -
01359 Temp.QuadPart;
01360 }
01361
01362
if (Temp.QuadPart <= 0) {
01363 ZeroFlags |=
ZERO_FIRST_PAGE |
ZERO_MIDDLE_PAGES |
ZERO_LAST_PAGE;
01364 }
else if ((Temp.HighPart == 0) && (Temp.LowPart <=
PAGE_SIZE)) {
01365 ZeroFlags |=
ZERO_MIDDLE_PAGES |
ZERO_LAST_PAGE;
01366 }
01367
01368
01369
01370
01371
01372
if (Wait) {
01373
01374
CcMapAndCopy( SharedCacheMap,
01375
Buffer,
01376 &FOffset,
01377 Length,
01378 ZeroFlags,
01379
BooleanFlagOn( FileObject->Flags,
FO_WRITE_THROUGH ));
01380
01381
return TRUE;
01382 }
01383
01384
01385
01386
01387
01388
01389
01390
01391
while (Length != 0) {
01392
01393 ULONG ReceivedLength;
01394 LARGE_INTEGER BeyondLastByte;
01395
01396
if (!
CcPinFileData( FileObject,
01397 &FOffset,
01398 Length,
01399
FALSE,
01400
TRUE,
01401
FALSE,
01402 &Bcb,
01403 &CacheBuffer,
01404 &BeyondLastByte )) {
01405
01406
DebugTrace(-1,
me,
"CcCopyWrite -> FALSE\n", 0 );
01407
01408
return FALSE;
01409
01410 }
else {
01411
01412
01413
01414
01415
01416
01417 ReceivedLength = (ULONG)(BeyondLastByte.QuadPart - FOffset.QuadPart);
01418
01419
01420
01421
01422
01423
01424
if (ReceivedLength > Length) {
01425 ReceivedLength = Length;
01426 }
01427 }
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
try {
01439
01440 RtlCopyBytes( CacheBuffer,
Buffer, ReceivedLength );
01441
01442
CcSetDirtyPinnedData( Bcb,
NULL );
01443
CcUnpinFileData( Bcb,
FALSE,
UNPIN );
01444 }
01445 except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
01446 &
Status ) ) {
01447
01448
CcUnpinFileData( Bcb,
TRUE,
UNPIN );
01449
01450
01451
01452
01453
01454
01455
01456
if (
Status == STATUS_ACCESS_VIOLATION) {
01457
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
01458 }
01459
else {
01460
01461
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status, STATUS_UNEXPECTED_IO_ERROR ));
01462 }
01463 }
01464
01465
01466
01467
01468
01469
01470 FOffset = BeyondLastByte;
01471
Buffer = (PCHAR)
Buffer + ReceivedLength;
01472 Length -= ReceivedLength;
01473 }
01474
01475
DebugTrace(-1,
me,
"CcCopyWrite -> TRUE\n", 0 );
01476
01477
return TRUE;
01478 }
01479
01480
01481
VOID
01482 CcFastCopyWrite (
01483 IN
PFILE_OBJECT FileObject,
01484 IN ULONG FileOffset,
01485 IN ULONG Length,
01486 IN PVOID Buffer
01487 )
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524 {
01525
PSHARED_CACHE_MAP SharedCacheMap;
01526 PVOID CacheBuffer;
01527
PVACB ActiveVacb;
01528 ULONG ActivePage;
01529 PVOID ActiveAddress;
01530 ULONG PageIsDirty;
01531 KIRQL OldIrql;
01532
NTSTATUS Status;
01533 ULONG ZeroFlags;
01534 ULONG ValidDataLength;
01535 LARGE_INTEGER FOffset;
01536
01537
DebugTrace(+1,
me,
"CcFastCopyWrite\n", 0 );
01538
01539
01540
01541
01542
01543 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
01544
01545
01546
01547
01548
01549
GetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty );
01550
01551
if (ActiveVacb !=
NULL) {
01552
01553
01554
01555
01556
01557
01558
01559
if (((FileOffset >>
PAGE_SHIFT) == ActivePage) && (Length != 0) &&
01560 !
FlagOn( FileObject->Flags,
FO_WRITE_THROUGH )) {
01561
01562 ULONG LengthToCopy =
PAGE_SIZE - (FileOffset & (
PAGE_SIZE - 1));
01563
01564
01565
01566
01567
01568
if (LengthToCopy > Length) {
01569 LengthToCopy = Length;
01570 }
01571
01572
01573
01574
01575
01576
try {
01577
01578
01579
01580
01581
01582
01583
01584 OldIrql = 0xFF;
01585
01586 CacheBuffer = (PVOID)((PCHAR)ActiveVacb->
BaseAddress +
01587 (FileOffset & (
VACB_MAPPING_GRANULARITY - 1)));
01588
01589
if (SharedCacheMap->
NeedToZero !=
NULL) {
01590
01591
01592
01593
01594
01595 OldIrql = 0;
01596
01597 ExAcquireFastLock( &SharedCacheMap->
ActiveVacbSpinLock, &OldIrql );
01598
01599
01600
01601
01602
01603
01604 ActiveAddress = SharedCacheMap->
NeedToZero;
01605
if ((ActiveAddress !=
NULL) &&
01606 (ActiveVacb == SharedCacheMap->
NeedToZeroVacb) &&
01607 (((PCHAR)CacheBuffer + LengthToCopy) > (PCHAR)ActiveAddress)) {
01608
01609
01610
01611
01612
01613
01614
if ((PCHAR)CacheBuffer > (PCHAR)ActiveAddress) {
01615
01616 RtlZeroMemory( ActiveAddress, (PCHAR)CacheBuffer - (PCHAR)ActiveAddress );
01617 }
01618 SharedCacheMap->
NeedToZero = (PVOID)((PCHAR)CacheBuffer + LengthToCopy);
01619 }
01620
01621 ExReleaseFastLock( &SharedCacheMap->
ActiveVacbSpinLock, OldIrql );
01622 }
01623
01624 RtlCopyBytes( CacheBuffer,
Buffer, LengthToCopy );
01625
01626 } except(
CcCopyReadExceptionFilter( GetExceptionInformation(),
01627 &
Status ) ) {
01628
01629
01630
01631
01632
01633
01634
if (OldIrql != 0xFF) {
01635 RtlZeroBytes( CacheBuffer, LengthToCopy );
01636 }
01637
01638
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage,
ACTIVE_PAGE_IS_DIRTY );
01639
01640
01641
01642
01643
01644
01645
01646
if (
Status == STATUS_ACCESS_VIOLATION) {
01647
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
01648 }
01649
else {
01650
ExRaiseStatus(
FsRtlNormalizeNtstatus(
Status,
01651 STATUS_UNEXPECTED_IO_ERROR ));
01652 }
01653 }
01654
01655
01656
01657
01658
01659
Buffer = (PVOID)((PCHAR)
Buffer + LengthToCopy);
01660 FileOffset += LengthToCopy;
01661 Length -= LengthToCopy;
01662
01663
01664
01665
01666
01667
if (Length == 0) {
01668
01669
SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage,
ACTIVE_PAGE_IS_DIRTY );
01670
return;
01671 }
01672
01673
01674
01675
01676
01677 PageIsDirty |=
ACTIVE_PAGE_IS_DIRTY;
01678 }
01679
01680
CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty );
01681
01682
01683
01684
01685
01686
01687 }
else if (SharedCacheMap->
NeedToZero !=
NULL) {
01688
01689
CcFreeActiveVacb( SharedCacheMap,
NULL, 0,
FALSE );
01690 }
01691
01692
01693
01694
01695
01696 FOffset.LowPart = FileOffset;
01697 FOffset.HighPart = 0;
01698
01699 ValidDataLength = ((
PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->ValidDataLength.LowPart;
01700
01701
ASSERT((ValidDataLength == MAXULONG) ||
01702 (((
PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->ValidDataLength.HighPart == 0));
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714 ZeroFlags =
ZERO_MIDDLE_PAGES;
01715
01716
if (((FileOffset & (
PAGE_SIZE - 1)) == 0) &&
01717 (Length >=
PAGE_SIZE)) {
01718 ZeroFlags |=
ZERO_FIRST_PAGE;
01719 }
01720
01721
if (((FileOffset + Length) & (
PAGE_SIZE - 1)) == 0) {
01722 ZeroFlags |=
ZERO_LAST_PAGE;
01723 }
01724
01725
if ((FileOffset & ~(
PAGE_SIZE - 1)) >= ValidDataLength) {
01726 ZeroFlags |=
ZERO_FIRST_PAGE |
ZERO_MIDDLE_PAGES |
ZERO_LAST_PAGE;
01727 }
else if (((FileOffset & ~(
PAGE_SIZE - 1)) +
PAGE_SIZE) >= ValidDataLength) {
01728 ZeroFlags |=
ZERO_MIDDLE_PAGES |
ZERO_LAST_PAGE;
01729 }
01730
01731
01732
01733
01734
01735
CcMapAndCopy( SharedCacheMap,
01736
Buffer,
01737 &FOffset,
01738 Length,
01739 ZeroFlags,
01740
BooleanFlagOn( FileObject->Flags,
FO_WRITE_THROUGH ));
01741
01742
DebugTrace(-1,
me,
"CcFastCopyWrite -> VOID\n", 0 );
01743 }
01744
01745
01746 LONG
01747 CcCopyReadExceptionFilter(
01748 IN PEXCEPTION_POINTERS ExceptionPointer,
01749 IN PNTSTATUS ExceptionCode
01750 )
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774 {
01775 *ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
01776
01777
if ( (*ExceptionCode == STATUS_IN_PAGE_ERROR) &&
01778 (ExceptionPointer->ExceptionRecord->NumberParameters >= 3) ) {
01779
01780 *ExceptionCode = (
NTSTATUS) ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
01781 }
01782
01783
ASSERT( !
NT_SUCCESS(*ExceptionCode) );
01784
01785
return EXCEPTION_EXECUTE_HANDLER;
01786 }
01787
01788
01789 BOOLEAN
01790 CcCanIWrite (
01791 IN
PFILE_OBJECT FileObject,
01792 IN ULONG BytesToWrite,
01793 IN BOOLEAN Wait,
01794 IN UCHAR Retrying
01795 )
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835 {
01836
PSHARED_CACHE_MAP SharedCacheMap;
01837
KEVENT Event;
01838 KIRQL OldIrql;
01839 ULONG PagesToWrite;
01840 BOOLEAN ExceededPerFileThreshold;
01841
DEFERRED_WRITE DeferredWrite;
01842
PSECTION_OBJECT_POINTERS SectionObjectPointers;
01843
01844
01845
01846
01847
01848
01849 ExceededPerFileThreshold =
FALSE;
01850
01851 PagesToWrite = ((BytesToWrite <
WRITE_CHARGE_THRESHOLD ?
01852 BytesToWrite :
WRITE_CHARGE_THRESHOLD) + (
PAGE_SIZE - 1)) /
PAGE_SIZE;
01853
01854
01855
01856
01857
01858
01859
if ((Retrying >= MAXUCHAR - 1) ||
01860
01861
FlagOn(((
PFSRTL_COMMON_FCB_HEADER)(FileObject->FsContext))->Flags,
01862
FSRTL_FLAG_LIMIT_MODIFIED_PAGES)) {
01863
01864
if (Retrying != MAXUCHAR) {
01865
CcAcquireMasterLock( &OldIrql );
01866 }
01867
01868
if (((SectionObjectPointers = FileObject->SectionObjectPointer) !=
NULL) &&
01869 ((SharedCacheMap = SectionObjectPointers->
SharedCacheMap) !=
NULL) &&
01870 (SharedCacheMap->
DirtyPageThreshold != 0) &&
01871 (SharedCacheMap->
DirtyPages != 0) &&
01872 ((PagesToWrite + SharedCacheMap->
DirtyPages) >
01873 SharedCacheMap->
DirtyPageThreshold)) {
01874
01875 ExceededPerFileThreshold =
TRUE;
01876 }
01877
01878
if (Retrying != MAXUCHAR) {
01879
CcReleaseMasterLock( OldIrql );
01880 }
01881 }
01882
01883
01884
01885
01886
01887
if ((Retrying || IsListEmpty(&
CcDeferredWrites))
01888
01889 &&
01890
01891 (
CcTotalDirtyPages + PagesToWrite <
CcDirtyPageThreshold)
01892
01893 &&
01894
01895
MmEnoughMemoryForWrite()
01896
01897 &&
01898
01899 !ExceededPerFileThreshold) {
01900
01901
return TRUE;
01902 }
01903
01904
01905
01906
01907
01908
if (IsListEmpty(&
CcDeferredWrites) ) {
01909
01910
01911
01912
01913
01914
KeSetTimer( &
LazyWriter.
ScanTimer,
CcNoDelay, &
LazyWriter.
ScanDpc );
01915 }
01916
01917
if (Wait) {
01918
01919
KeInitializeEvent( &
Event, NotificationEvent,
FALSE );
01920
01921
01922
01923
01924
01925
01926
01927 DeferredWrite.
NodeTypeCode =
CACHE_NTC_DEFERRED_WRITE;
01928 DeferredWrite.
NodeByteSize =
sizeof(
DEFERRED_WRITE);
01929 DeferredWrite.
FileObject = FileObject;
01930 DeferredWrite.
BytesToWrite = BytesToWrite;
01931 DeferredWrite.
Event = &
Event;
01932 DeferredWrite.
LimitModifiedPages =
BooleanFlagOn(((
PFSRTL_COMMON_FCB_HEADER)(FileObject->FsContext))->Flags,
01933
FSRTL_FLAG_LIMIT_MODIFIED_PAGES);
01934
01935
01936
01937
01938
01939
if (Retrying) {
01940
ExInterlockedInsertHeadList( &
CcDeferredWrites,
01941 &DeferredWrite.
DeferredWriteLinks,
01942 &
CcDeferredWriteSpinLock );
01943 }
else {
01944
ExInterlockedInsertTailList( &
CcDeferredWrites,
01945 &DeferredWrite.
DeferredWriteLinks,
01946 &
CcDeferredWriteSpinLock );
01947 }
01948
01949
while (
TRUE) {
01950
01951
01952
01953
01954
01955
01956
01957
CcPostDeferredWrites();
01958
01959
01960
01961
01962
01963
01964
if (
KeWaitForSingleObject( &
Event,
01965
Executive,
01966
KernelMode,
01967
FALSE,
01968 &
CcIdleDelay ) == STATUS_SUCCESS) {
01969
01970
01971
return TRUE;
01972 }
01973 }
01974
01975 }
else {
01976
return FALSE;
01977 }
01978 }
01979
01980
01981
VOID
01982 CcDeferWrite (
01983 IN
PFILE_OBJECT FileObject,
01984 IN PCC_POST_DEFERRED_WRITE PostRoutine,
01985 IN PVOID Context1,
01986 IN PVOID Context2,
01987 IN ULONG BytesToWrite,
01988 IN BOOLEAN Retrying
01989 )
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026 {
02027
PDEFERRED_WRITE DeferredWrite;
02028 KIRQL OldIrql;
02029
02030
02031
02032
02033
02034
02035
02036 DeferredWrite =
ExAllocatePoolWithTag(
NonPagedPool,
sizeof(
DEFERRED_WRITE), 'wDcC' );
02037
02038
if (DeferredWrite ==
NULL) {
02039 (*PostRoutine)(
Context1,
Context2 );
02040
return;
02041 }
02042
02043
02044
02045
02046
02047 DeferredWrite->
NodeTypeCode =
CACHE_NTC_DEFERRED_WRITE;
02048 DeferredWrite->
NodeByteSize =
sizeof(
DEFERRED_WRITE);
02049 DeferredWrite->
FileObject = FileObject;
02050 DeferredWrite->
BytesToWrite = BytesToWrite;
02051 DeferredWrite->
Event =
NULL;
02052 DeferredWrite->
PostRoutine = PostRoutine;
02053 DeferredWrite->
Context1 =
Context1;
02054 DeferredWrite->
Context2 =
Context2;
02055 DeferredWrite->
LimitModifiedPages =
BooleanFlagOn(((
PFSRTL_COMMON_FCB_HEADER)(FileObject->FsContext))->Flags,
02056
FSRTL_FLAG_LIMIT_MODIFIED_PAGES);
02057
02058
02059
02060
02061
02062
if (Retrying) {
02063
ExInterlockedInsertHeadList( &
CcDeferredWrites,
02064 &DeferredWrite->
DeferredWriteLinks,
02065 &
CcDeferredWriteSpinLock );
02066 }
else {
02067
ExInterlockedInsertTailList( &
CcDeferredWrites,
02068 &DeferredWrite->
DeferredWriteLinks,
02069 &
CcDeferredWriteSpinLock );
02070 }
02071
02072
02073
02074
02075
02076
02077
02078
CcPostDeferredWrites();
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
CcAcquireMasterLock( &OldIrql);
02089
02090
if (!
LazyWriter.
ScanActive) {
02091
CcScheduleLazyWriteScan();
02092 }
02093
02094
CcReleaseMasterLock( OldIrql);
02095 }
02096
02097
02098
VOID
02099 CcPostDeferredWrites (
02100 )
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121 {
02122
PDEFERRED_WRITE DeferredWrite;
02123 ULONG TotalBytesLetLoose = 0;
02124 KIRQL OldIrql;
02125
02126
do {
02127
02128
02129
02130
02131
02132
02133 DeferredWrite =
NULL;
02134
02135 ExAcquireSpinLock( &
CcDeferredWriteSpinLock, &OldIrql );
02136
02137
02138
02139
02140
02141
if (!IsListEmpty(&
CcDeferredWrites)) {
02142
02143 PLIST_ENTRY Entry;
02144
02145 Entry =
CcDeferredWrites.Flink;
02146
02147
while (Entry != &
CcDeferredWrites) {
02148
02149 DeferredWrite = CONTAINING_RECORD( Entry,
02150
DEFERRED_WRITE,
02151 DeferredWriteLinks );
02152
02153
02154
02155
02156
02157
02158 TotalBytesLetLoose += DeferredWrite->
BytesToWrite;
02159
02160
if (TotalBytesLetLoose < DeferredWrite->
BytesToWrite) {
02161
02162 DeferredWrite =
NULL;
02163
break;
02164 }
02165
02166
02167
02168
02169
02170
02171
if (
CcCanIWrite( DeferredWrite->
FileObject,
02172 TotalBytesLetLoose,
02173
FALSE,
02174 MAXUCHAR - 1 )) {
02175
02176 RemoveEntryList( &DeferredWrite->
DeferredWriteLinks );
02177
break;
02178
02179
02180
02181
02182
02183
02184
02185 }
else {
02186
02187
02188
02189
02190
02191
02192
if (DeferredWrite->
LimitModifiedPages) {
02193
02194 Entry = Entry->Flink;
02195 TotalBytesLetLoose -= DeferredWrite->
BytesToWrite;
02196 DeferredWrite =
NULL;
02197
continue;
02198
02199 }
else {
02200
02201 DeferredWrite =
NULL;
02202
02203
break;
02204 }
02205 }
02206 }
02207 }
02208
02209 ExReleaseSpinLock( &
CcDeferredWriteSpinLock, OldIrql );
02210
02211
02212
02213
02214
02215
02216
if (DeferredWrite !=
NULL) {
02217
02218
if (DeferredWrite->
Event !=
NULL) {
02219
02220
KeSetEvent( DeferredWrite->
Event, 0,
FALSE );
02221
02222 }
else {
02223
02224 (*DeferredWrite->
PostRoutine)( DeferredWrite->
Context1,
02225 DeferredWrite->
Context2 );
02226
ExFreePool( DeferredWrite );
02227 }
02228 }
02229
02230
02231
02232
02233
02234 }
while (DeferredWrite !=
NULL);
02235 }