Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

copysup.c File Reference

#include "cc.h"

Go to the source code of this file.

Defines

#define me   0x00000004

Functions

BOOLEAN CcCopyRead (IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus)
VOID CcFastCopyRead (IN PFILE_OBJECT FileObject, IN ULONG FileOffset, IN ULONG Length, IN ULONG PageCount, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus)
BOOLEAN CcCopyWrite (IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN PVOID Buffer)
VOID CcFastCopyWrite (IN PFILE_OBJECT FileObject, IN ULONG FileOffset, IN ULONG Length, IN PVOID Buffer)
LONG CcCopyReadExceptionFilter (IN PEXCEPTION_POINTERS ExceptionPointer, IN PNTSTATUS ExceptionCode)
BOOLEAN CcCanIWrite (IN PFILE_OBJECT FileObject, IN ULONG BytesToWrite, IN BOOLEAN Wait, IN UCHAR Retrying)
VOID CcDeferWrite (IN PFILE_OBJECT FileObject, IN PCC_POST_DEFERRED_WRITE PostRoutine, IN PVOID Context1, IN PVOID Context2, IN ULONG BytesToWrite, IN BOOLEAN Retrying)
VOID CcPostDeferredWrites ()


Define Documentation

#define me   0x00000004
 

Definition at line 27 of file copysup.c.


Function Documentation

BOOLEAN CcCanIWrite IN PFILE_OBJECT  FileObject,
IN ULONG  BytesToWrite,
IN BOOLEAN  Wait,
IN UCHAR  Retrying
 

Definition at line 1790 of file copysup.c.

References BooleanFlagOn, _DEFERRED_WRITE::BytesToWrite, CACHE_NTC_DEFERRED_WRITE, CcAcquireMasterLock, CcDeferredWrites, CcDeferredWriteSpinLock, CcDirtyPageThreshold, CcIdleDelay, CcNoDelay, CcPostDeferredWrites(), CcReleaseMasterLock, CcTotalDirtyPages, _DEFERRED_WRITE::DeferredWriteLinks, _SHARED_CACHE_MAP::DirtyPages, _SHARED_CACHE_MAP::DirtyPageThreshold, _DEFERRED_WRITE::Event, Event(), Executive, ExInterlockedInsertHeadList(), ExInterlockedInsertTailList(), FALSE, _DEFERRED_WRITE::FileObject, FlagOn, FSRTL_FLAG_LIMIT_MODIFIED_PAGES, KeInitializeEvent, KernelMode, KeSetTimer(), KeWaitForSingleObject(), LazyWriter, _DEFERRED_WRITE::LimitModifiedPages, MmEnoughMemoryForWrite, _DEFERRED_WRITE::NodeByteSize, _DEFERRED_WRITE::NodeTypeCode, NULL, PAGE_SIZE, _LAZY_WRITER::ScanDpc, _LAZY_WRITER::ScanTimer, _SECTION_OBJECT_POINTERS::SharedCacheMap, TRUE, and WRITE_CHARGE_THRESHOLD.

01799 : 01800 01801 This routine tests whether it is ok to do a write to the cache 01802 or not, according to the Thresholds of dirty bytes and available 01803 pages. The first time this routine is called for a request (Retrying 01804 FALSE), we automatically make the new request queue if there are other 01805 requests in the queue. 01806 01807 Note that the ListEmpty test is important to prevent small requests from sneaking 01808 in and starving large requests. 01809 01810 Arguments: 01811 01812 FileObject - for the file to be written 01813 01814 BytesToWrite - Number of bytes caller wishes to write to the Cache. 01815 01816 Wait - TRUE if the caller owns no resources, and can block inside this routine 01817 until it is ok to write. 01818 01819 Retrying - Specified as FALSE when the request is first received, and 01820 otherwise specified as TRUE if this write has already entered 01821 the queue. Special non-zero value of MAXUCHAR indicates that 01822 we were called within the cache manager with a MasterSpinLock held, 01823 so do not attempt to acquire it here. MAXUCHAR - 1 means we 01824 were called within the Cache Manager with some other spinlock 01825 held. For either of these two special values, we do not touch 01826 the FsRtl header. 01827 01828 Return Value: 01829 01830 TRUE if it is ok to write. 01831 FALSE if the caller should defer the write via a call to CcDeferWrite. 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 // Do a special test here for file objects that keep track of dirty 01846 // pages on a per-file basis. This is used mainly for slow links. 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 // Don't dereference the FsContext field if we were called while holding 01856 // a spinlock. 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 // See if it is ok to do the write right now 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 // Otherwise, if our caller is synchronous, we will just wait here. 01906 // 01907 01908 if (IsListEmpty(&CcDeferredWrites) ) { 01909 01910 // 01911 // Get a write scan to occur NOW 01912 // 01913 01914 KeSetTimer( &LazyWriter.ScanTimer, CcNoDelay, &LazyWriter.ScanDpc ); 01915 } 01916 01917 if (Wait) { 01918 01919 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 01920 01921 // 01922 // Fill in the block. Note that we can access the Fsrtl Common Header 01923 // even if it's paged because Wait will be FALSE if called from 01924 // within the cache. 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 // Now insert at the appropriate end of the list 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 // Now since we really didn't synchronize anything but the insertion, 01953 // we call the post routine to make sure that in some wierd case we 01954 // do not leave anyone hanging with no dirty bytes for the Lazy Writer. 01955 // 01956 01957 CcPostDeferredWrites(); 01958 01959 // 01960 // Finally wait until the event is signalled and we can write 01961 // and return to tell the guy he can write. 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 }

BOOLEAN CcCopyRead IN PFILE_OBJECT  FileObject,
IN PLARGE_INTEGER  FileOffset,
IN ULONG  Length,
IN BOOLEAN  Wait,
OUT PVOID  Buffer,
OUT PIO_STATUS_BLOCK  IoStatus
 

Definition at line 31 of file copysup.c.

References ASSERT, _VACB::BaseAddress, _PRIVATE_CACHE_MAP::BeyondLastByte1, _PRIVATE_CACHE_MAP::BeyondLastByte2, Buffer, CcCopyReadExceptionFilter(), CcCopyReadNoWait, CcCopyReadNoWaitMiss, CcCopyReadWait, CcCopyReadWaitMiss, CcFreeActiveVacb(), CcFreeVirtualAddress(), CcGetVirtualAddress(), CcMissCounter, CcPinFileData(), CcScheduleReadAhead(), CcThrowAway, CcUnpinFileData(), COMPUTE_PAGES_SPANNED, DebugTrace, ExRaiseStatus(), FALSE, _PRIVATE_CACHE_MAP::FileOffset1, _PRIVATE_CACHE_MAP::FileOffset2, _SHARED_CACHE_MAP::FileSize, FlagOn, FO_RANDOM_ACCESS, FsRtlNormalizeNtstatus(), GetActiveVacb, HOT_STATISTIC, me, MmCheckCachedPageState(), MmResetPageFaultReadAhead, MmSavePageFaultReadAhead, MmSetPageFaultReadAhead, _SHARED_CACHE_MAP::NeedToZero, NTSTATUS(), NULL, PAGE_SHIFT, PsGetCurrentThread, _PRIVATE_CACHE_MAP::ReadAheadEnabled, _PRIVATE_CACHE_MAP::ReadAheadLength, ROUND_TO_PAGES, SetActiveVacb, Status, TRUE, UNPIN, VACB_MAPPING_GRANULARITY, and VACB_OFFSET_SHIFT.

Referenced by FsRtlCopyRead(), and UdfCommonRead().

00042 : 00043 00044 This routine attempts to copy the specified file data from the cache 00045 into the output buffer, and deliver the correct I/O status. It is *not* 00046 safe to call this routine from Dpc level. 00047 00048 If the caller does not want to block (such as for disk I/O), then 00049 Wait should be supplied as FALSE. If Wait was supplied as FALSE and 00050 it is currently impossible to supply all of the requested data without 00051 blocking, then this routine will return FALSE. However, if the 00052 data is immediately accessible in the cache and no blocking is 00053 required, this routine copies the data and returns TRUE. 00054 00055 If the caller supplies Wait as TRUE, then this routine is guaranteed 00056 to copy the data and return TRUE. If the data is immediately 00057 accessible in the cache, then no blocking will occur. Otherwise, 00058 the the data transfer from the file into the cache will be initiated, 00059 and the caller will be blocked until the data can be returned. 00060 00061 File system Fsd's should typically supply Wait = TRUE if they are 00062 processing a synchronous I/O requests, or Wait = FALSE if they are 00063 processing an asynchronous request. 00064 00065 File system or Server Fsp threads should supply Wait = TRUE. 00066 00067 Arguments: 00068 00069 FileObject - Pointer to the file object for a file which was 00070 opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for 00071 which CcInitializeCacheMap was called by the file system. 00072 00073 FileOffset - Byte offset in file for desired data. 00074 00075 Length - Length of desired data in bytes. 00076 00077 Wait - FALSE if caller may not block, TRUE otherwise (see description 00078 above) 00079 00080 Buffer - Pointer to output buffer to which data should be copied. 00081 00082 IoStatus - Pointer to standard I/O status block to receive the status 00083 for the transfer. (STATUS_SUCCESS guaranteed for cache 00084 hits, otherwise the actual I/O status is returned.) 00085 00086 Note that even if FALSE is returned, the IoStatus.Information 00087 field will return the count of any bytes successfully 00088 transferred before a blocking condition occured. The caller 00089 may either choose to ignore this information, or resume 00090 the copy later accounting for bytes transferred. 00091 00092 Return Value: 00093 00094 FALSE - if Wait was supplied as FALSE and the data was not delivered 00095 00096 TRUE - if the data is being delivered 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 // Get pointer to shared and private cache maps 00127 // 00128 00129 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 00130 PrivateCacheMap = FileObject->PrivateCacheMap; 00131 00132 // 00133 // Check for read past file size, the caller must filter this case out. 00134 // 00135 00136 ASSERT( ( FileOffset->QuadPart + (LONGLONG)Length) <= SharedCacheMap->FileSize.QuadPart ); 00137 00138 // 00139 // If read ahead is enabled, then do the read ahead here so it 00140 // overlaps with the copy (otherwise we will do it below). 00141 // Note that we are assuming that we will not get ahead of our 00142 // current transfer - if read ahead is working it should either 00143 // already be in memory or else underway. 00144 // 00145 00146 if (PrivateCacheMap->ReadAheadEnabled && (PrivateCacheMap->ReadAheadLength[1] == 0)) { 00147 CcScheduleReadAhead( FileObject, FileOffset, Length ); 00148 } 00149 00150 FOffset = *FileOffset; 00151 00152 // 00153 // Increment performance counters 00154 // 00155 00156 if (Wait) { 00157 HOT_STATISTIC(CcCopyReadWait) += 1; 00158 00159 // 00160 // This is not an exact solution, but when IoPageRead gets a miss, 00161 // it cannot tell whether it was CcCopyRead or CcMdlRead, but since 00162 // the miss should occur very soon, by loading the pointer here 00163 // probably the right counter will get incremented, and in any case, 00164 // we hope the errrors average out! 00165 // 00166 00167 CcMissCounter = &CcCopyReadWaitMiss; 00168 00169 } else { 00170 HOT_STATISTIC(CcCopyReadNoWait) += 1; 00171 } 00172 00173 // 00174 // See if we have an active Vacb, that we can just copy to. 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 // Get the starting point in the view. 00191 // 00192 00193 CacheBuffer = (PVOID)((PCHAR)ActiveVacb->BaseAddress + 00194 (FOffset.LowPart & (VACB_MAPPING_GRANULARITY - 1))); 00195 00196 // 00197 // Reduce LengthToCopy if it is greater than our caller's length. 00198 // 00199 00200 if (LengthToCopy > Length) { 00201 LengthToCopy = Length; 00202 } 00203 00204 // 00205 // Like the logic for the normal case below, we want to spin around 00206 // making sure Mm only reads the pages we will need. 00207 // 00208 00209 PagesToGo = COMPUTE_PAGES_SPANNED( CacheBuffer, 00210 LengthToCopy ) - 1; 00211 00212 // 00213 // Copy the data to the user buffer. 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 // Here's hoping that it is cheaper to call Mm to see if 00233 // the page is valid. If not let Mm know how many pages 00234 // we are after before doing the move. 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 // Handle the read here that stays on a single page. 00251 // 00252 00253 } else { 00254 00255 // 00256 // Here's hoping that it is cheaper to call Mm to see if 00257 // the page is valid. If not let Mm know how many pages 00258 // we are after before doing the move. 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 // If we got an access violation, then the user buffer went 00278 // away. Otherwise we must have gotten an I/O error trying 00279 // to bring the data in. 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 // Now adjust FOffset and Length by what we copied. 00293 // 00294 00295 FOffset.QuadPart = FOffset.QuadPart + (LONGLONG)LengthToCopy; 00296 Length -= LengthToCopy; 00297 00298 } 00299 00300 // 00301 // If that was all the data, then remember the Vacb 00302 // 00303 00304 if (Length == 0) { 00305 00306 SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty ); 00307 00308 // 00309 // Otherwise we must free it because we will map other vacbs below. 00310 // 00311 00312 } else { 00313 00314 CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty ); 00315 } 00316 } 00317 00318 // 00319 // Not all of the transfer will come back at once, so we have to loop 00320 // until the entire transfer is complete. 00321 // 00322 00323 while (Length != 0) { 00324 00325 ULONG ReceivedLength; 00326 LARGE_INTEGER BeyondLastByte; 00327 00328 // 00329 // Call local routine to Map or Access the file data, then move the data, 00330 // then call another local routine to free the data. If we cannot map 00331 // the data because of a Wait condition, return FALSE. 00332 // 00333 // Note that this call may result in an exception, however, if it 00334 // does no Bcb is returned and this routine has absolutely no 00335 // cleanup to perform. Therefore, we do not have a try-finally 00336 // and we allow the possibility that we will simply be unwound 00337 // without notice. 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 // Enable ReadAhead if we missed. 00365 // 00366 00367 PrivateCacheMap->ReadAheadEnabled = TRUE; 00368 00369 return FALSE; 00370 00371 } else { 00372 00373 // 00374 // Calculate how much data is described by Bcb starting at our desired 00375 // file offset. 00376 // 00377 00378 ReceivedLength = (ULONG)(BeyondLastByte.QuadPart - FOffset.QuadPart); 00379 } 00380 00381 // 00382 // If we got more than we need, make sure to only transfer 00383 // the right amount. 00384 // 00385 00386 if (ReceivedLength > Length) { 00387 ReceivedLength = Length; 00388 } 00389 00390 // 00391 // It is possible for the user buffer to become no longer accessible 00392 // since it was last checked by the I/O system. If we fail to access 00393 // the buffer we must raise a status that the caller's exception 00394 // filter considers as "expected". Also we unmap the Bcb here, since 00395 // we otherwise would have no other reason to put a try-finally around 00396 // this loop. 00397 // 00398 00399 try { 00400 00401 PagesToGo = COMPUTE_PAGES_SPANNED( CacheBuffer, 00402 ReceivedLength ) - 1; 00403 00404 // 00405 // We know exactly how much we want to read here, and we do not 00406 // want to read any more in case the caller is doing random access. 00407 // Our read ahead logic takes care of detecting sequential reads, 00408 // and tends to do large asynchronous read aheads. So far we have 00409 // only mapped the data and we have not forced any in. What we 00410 // do now is get into a loop where we copy a page at a time and 00411 // just prior to each move, we tell MM how many additional pages 00412 // we would like to have read in, in the event that we take a 00413 // fault. With this strategy, for cache hits we never make a single 00414 // expensive call to MM to guarantee that the data is in, yet if we 00415 // do take a fault, we are guaranteed to only take one fault because 00416 // we will read all of the data in for the rest of the transfer. 00417 // 00418 // We test first for the multiple page case, to keep the small 00419 // reads faster. 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 // Here's hoping that it is cheaper to call Mm to see if 00437 // the page is valid. If not let Mm know how many pages 00438 // we are after before doing the move. 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 // Handle the read here that stays on a single page. 00455 // 00456 00457 } else { 00458 00459 // 00460 // Here's hoping that it is cheaper to call Mm to see if 00461 // the page is valid. If not let Mm know how many pages 00462 // we are after before doing the move. 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 // If we get an exception, then we have to renable page fault 00481 // clustering and unmap on the way out. 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 // If we got an access violation, then the user buffer went 00495 // away. Otherwise we must have gotten an I/O error trying 00496 // to bring the data in. 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 // Update number of bytes transferred. 00510 // 00511 00512 Length -= ReceivedLength; 00513 00514 // 00515 // Unmap the data now, and calculate length left to transfer. 00516 // 00517 00518 if (Wait) { 00519 00520 // 00521 // If there is more to go, just free this vacb. 00522 // 00523 00524 if (Length != 0) { 00525 00526 CcFreeVirtualAddress( Vacb ); 00527 00528 // 00529 // Otherwise save it for the next time through. 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 // Assume we did not get all the data we wanted, and set FOffset 00544 // to the end of the returned data. 00545 // 00546 00547 FOffset = BeyondLastByte; 00548 } 00549 00550 MmResetPageFaultReadAhead( Thread, SavedState ); 00551 00552 CcMissCounter = &CcThrowAway; 00553 00554 // 00555 // Now enable read ahead if it looks like we got any misses, and do 00556 // the first one. 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 // Now that we have described our desired read ahead, let's 00569 // shift the read history down. 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 }

LONG CcCopyReadExceptionFilter IN PEXCEPTION_POINTERS  ExceptionPointer,
IN PNTSTATUS  ExceptionCode
 

Definition at line 1747 of file copysup.c.

References ASSERT, EXCEPTION_EXECUTE_HANDLER, NT_SUCCESS, and NTSTATUS().

Referenced by CcCopyRead(), CcCopyWrite(), CcFastCopyRead(), CcFastCopyWrite(), and CcMapAndCopy().

01754 : 01755 01756 This routine serves as a exception filter and has the special job of 01757 extracting the "real" I/O error when Mm raises STATUS_IN_PAGE_ERROR 01758 beneath us. 01759 01760 Arguments: 01761 01762 ExceptionPointer - A pointer to the exception record that contains 01763 the real Io Status. 01764 01765 ExceptionCode - A pointer to an NTSTATUS that is to receive the real 01766 status. 01767 01768 Return Value: 01769 01770 EXCEPTION_EXECUTE_HANDLER 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 }

BOOLEAN CcCopyWrite IN PFILE_OBJECT  FileObject,
IN PLARGE_INTEGER  FileOffset,
IN ULONG  Length,
IN BOOLEAN  Wait,
IN PVOID  Buffer
 

Definition at line 1075 of file copysup.c.

References ACTIVE_PAGE_IS_DIRTY, _SHARED_CACHE_MAP::ActiveVacbSpinLock, _VACB::BaseAddress, BooleanFlagOn, Buffer, CcCopyReadExceptionFilter(), CcFreeActiveVacb(), CcMapAndCopy(), CcPinFileData(), CcSetDirtyPinnedData(), CcUnpinFileData(), DebugTrace, ExRaiseStatus(), FALSE, FlagOn, FO_WRITE_THROUGH, FSRTL_FLAG_ADVANCED_HEADER, FsRtlNormalizeNtstatus(), GetActiveVacb, me, _SHARED_CACHE_MAP::NeedToZero, _SHARED_CACHE_MAP::NeedToZeroVacb, NTSTATUS(), NULL, PAGE_SHIFT, PAGE_SIZE, PFSRTL_ADVANCED_FCB_HEADER, SetActiveVacb, Status, TRUE, UNPIN, VACB_MAPPING_GRANULARITY, ZERO_FIRST_PAGE, ZERO_LAST_PAGE, and ZERO_MIDDLE_PAGES.

Referenced by FsRtlCopyWrite().

01085 : 01086 01087 This routine attempts to copy the specified file data from the specified 01088 buffer into the Cache, and deliver the correct I/O status. It is *not* 01089 safe to call this routine from Dpc level. 01090 01091 If the caller does not want to block (such as for disk I/O), then 01092 Wait should be supplied as FALSE. If Wait was supplied as FALSE and 01093 it is currently impossible to receive all of the requested data without 01094 blocking, then this routine will return FALSE. However, if the 01095 correct space is immediately accessible in the cache and no blocking is 01096 required, this routine copies the data and returns TRUE. 01097 01098 If the caller supplies Wait as TRUE, then this routine is guaranteed 01099 to copy the data and return TRUE. If the correct space is immediately 01100 accessible in the cache, then no blocking will occur. Otherwise, 01101 the necessary work will be initiated to read and/or free cache data, 01102 and the caller will be blocked until the data can be received. 01103 01104 File system Fsd's should typically supply Wait = TRUE if they are 01105 processing a synchronous I/O requests, or Wait = FALSE if they are 01106 processing an asynchronous request. 01107 01108 File system or Server Fsp threads should supply Wait = TRUE. 01109 01110 Arguments: 01111 01112 FileObject - Pointer to the file object for a file which was 01113 opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for 01114 which CcInitializeCacheMap was called by the file system. 01115 01116 FileOffset - Byte offset in file to receive the data. 01117 01118 Length - Length of data in bytes. 01119 01120 Wait - FALSE if caller may not block, TRUE otherwise (see description 01121 above) 01122 01123 Buffer - Pointer to input buffer from which data should be copied. 01124 01125 Return Value: 01126 01127 FALSE - if Wait was supplied as FALSE and the data was not copied. 01128 01129 TRUE - if the data has been copied. 01130 01131 Raises: 01132 01133 STATUS_INSUFFICIENT_RESOURCES - If a pool allocation failure occurs. 01134 This can only occur if Wait was specified as TRUE. (If Wait is 01135 specified as FALSE, and an allocation failure occurs, this 01136 routine simply returns FALSE.) 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 // If the caller specified Wait == FALSE, but the FileObject is WriteThrough, 01159 // then we need to just get out. 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 // Get pointer to shared cache map 01171 // 01172 01173 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 01174 FOffset = *FileOffset; 01175 01176 // 01177 // See if we have an active Vacb, that we can just copy to. 01178 // 01179 01180 GetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty ); 01181 01182 if (ActiveVacb != NULL) { 01183 01184 // 01185 // See if the request starts in the ActivePage. WriteThrough requests must 01186 // go the longer route through CcMapAndCopy, where WriteThrough flushes are 01187 // implemented. 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 // Reduce LengthToCopy if it is greater than our caller's length. 01197 // 01198 01199 if (LengthToCopy > Length) { 01200 LengthToCopy = Length; 01201 } 01202 01203 // 01204 // Copy the data to the user buffer. 01205 // 01206 01207 try { 01208 01209 // 01210 // If we are copying to a page that is locked down, then 01211 // we have to do it under our spinlock, and update the 01212 // NeedToZero field. 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 // The FastLock may not write our "flag". 01224 // 01225 01226 OldIrql = 0; 01227 01228 ExAcquireFastLock( &SharedCacheMap->ActiveVacbSpinLock, &OldIrql ); 01229 01230 // 01231 // Note that the NeedToZero could be cleared, since we 01232 // tested it without the spinlock. 01233 // 01234 01235 ActiveAddress = SharedCacheMap->NeedToZero; 01236 if ((ActiveAddress != NULL) && 01237 (ActiveVacb == SharedCacheMap->NeedToZeroVacb) && 01238 (((PCHAR)CacheBuffer + LengthToCopy) > (PCHAR)ActiveAddress)) { 01239 01240 // 01241 // If we are skipping some bytes in the page, then we need 01242 // to zero them. 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 // If we failed to overwrite the uninitialized data, 01262 // zero it now (we cannot safely restore NeedToZero). 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 // If we got an access violation, then the user buffer went 01273 // away. Otherwise we must have gotten an I/O error trying 01274 // to bring the data in. 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 // Now adjust FOffset and Length by what we copied. 01288 // 01289 01290 Buffer = (PVOID)((PCHAR)Buffer + LengthToCopy); 01291 FOffset.QuadPart = FOffset.QuadPart + (LONGLONG)LengthToCopy; 01292 Length -= LengthToCopy; 01293 01294 // 01295 // If that was all the data, then get outski... 01296 // 01297 01298 if (Length == 0) { 01299 01300 SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, ACTIVE_PAGE_IS_DIRTY ); 01301 return TRUE; 01302 } 01303 01304 // 01305 // Remember that the page is dirty now. 01306 // 01307 01308 PageIsDirty |= ACTIVE_PAGE_IS_DIRTY; 01309 } 01310 01311 CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty ); 01312 01313 // 01314 // Else someone else could have the active page, and may want to zero 01315 // the range we plan to write! 01316 // 01317 01318 } else if (SharedCacheMap->NeedToZero != NULL) { 01319 01320 CcFreeActiveVacb( SharedCacheMap, NULL, 0, FALSE ); 01321 } 01322 01323 // 01324 // At this point we can calculate the ZeroFlags. 01325 // 01326 01327 // 01328 // We can always zero middle pages, if any. 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 // If there is an advanced header, then we can acquire the FastMutex to 01347 // make capturing ValidDataLength atomic. Currently our other file systems 01348 // are either RO or do not really support 64-bits. 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 // Call a routine to map and copy the data in Mm and get out. 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 // The rest of this routine is the Wait == FALSE case. 01386 // 01387 // Not all of the transfer will come back at once, so we have to loop 01388 // until the entire transfer is complete. 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 // Calculate how much data is described by Bcb starting at our desired 01414 // file offset. 01415 // 01416 01417 ReceivedLength = (ULONG)(BeyondLastByte.QuadPart - FOffset.QuadPart); 01418 01419 // 01420 // If we got more than we need, make sure to only transfer 01421 // the right amount. 01422 // 01423 01424 if (ReceivedLength > Length) { 01425 ReceivedLength = Length; 01426 } 01427 } 01428 01429 // 01430 // It is possible for the user buffer to become no longer accessible 01431 // since it was last checked by the I/O system. If we fail to access 01432 // the buffer we must raise a status that the caller's exception 01433 // filter considers as "expected". Also we unmap the Bcb here, since 01434 // we otherwise would have no other reason to put a try-finally around 01435 // this loop. 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 // If we got an access violation, then the user buffer went 01452 // away. Otherwise we must have gotten an I/O error trying 01453 // to bring the data in. 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 // Assume we did not get all the data we wanted, and set FOffset 01467 // to the end of the returned data and adjust the Buffer and Length. 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 }

VOID CcDeferWrite IN PFILE_OBJECT  FileObject,
IN PCC_POST_DEFERRED_WRITE  PostRoutine,
IN PVOID  Context1,
IN PVOID  Context2,
IN ULONG  BytesToWrite,
IN BOOLEAN  Retrying
 

Definition at line 1982 of file copysup.c.

References BooleanFlagOn, _DEFERRED_WRITE::BytesToWrite, CACHE_NTC_DEFERRED_WRITE, CcAcquireMasterLock, CcDeferredWrites, CcDeferredWriteSpinLock, CcPostDeferredWrites(), CcReleaseMasterLock, CcScheduleLazyWriteScan(), Context1, _DEFERRED_WRITE::Context1, Context2, _DEFERRED_WRITE::Context2, DEFERRED_WRITE, _DEFERRED_WRITE::DeferredWriteLinks, _DEFERRED_WRITE::Event, ExAllocatePoolWithTag, ExInterlockedInsertHeadList(), ExInterlockedInsertTailList(), _DEFERRED_WRITE::FileObject, FSRTL_FLAG_LIMIT_MODIFIED_PAGES, LazyWriter, _DEFERRED_WRITE::LimitModifiedPages, _DEFERRED_WRITE::NodeByteSize, _DEFERRED_WRITE::NodeTypeCode, NonPagedPool, NULL, _DEFERRED_WRITE::PostRoutine, and _LAZY_WRITER::ScanActive.

01993 : 01994 01995 This routine may be called to have the Cache Manager defer posting 01996 of a write until the Lazy Writer makes some progress writing, or 01997 there are more available pages. A file system would normally call 01998 this routine after receiving FALSE from CcCanIWrite, and preparing 01999 the request to be posted. 02000 02001 Arguments: 02002 02003 FileObject - for the file to be written 02004 02005 PostRoutine - Address of the PostRoutine that the Cache Manager can 02006 call to post the request when conditions are right. Note 02007 that it is possible that this routine will be called 02008 immediately from this routine. 02009 02010 Context1 - First context parameter for the post routine. 02011 02012 Context2 - Secont parameter for the post routine. 02013 02014 BytesToWrite - Number of bytes that the request is trying to write 02015 to the cache. 02016 02017 Retrying - Supplied as FALSE if the request is being posted for the 02018 first time, TRUE otherwise. 02019 02020 Return Value: 02021 02022 None 02023 02024 --*/ 02025 02026 { 02027 PDEFERRED_WRITE DeferredWrite; 02028 KIRQL OldIrql; 02029 02030 // 02031 // Attempt to allocate a deferred write block, and if we do not get 02032 // one, just post it immediately rather than gobbling up must succeed 02033 // pool. 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 // Fill in the block. 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 // Now insert at the appropriate end of the list 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 // Now since we really didn't synchronize anything but the insertion, 02074 // we call the post routine to make sure that in some wierd case we 02075 // do not leave anyone hanging with no dirty bytes for the Lazy Writer. 02076 // 02077 02078 CcPostDeferredWrites(); 02079 02080 // 02081 // Schedule the lazy writer in case the reason we're blocking 02082 // is that we're waiting for Mm (or some other external flag) 02083 // to lower and let this write happen. He will be the one to 02084 // keep coming back and checking if this can proceed, even if 02085 // there are no cache manager pages to write. 02086 // 02087 02088 CcAcquireMasterLock( &OldIrql); 02089 02090 if (!LazyWriter.ScanActive) { 02091 CcScheduleLazyWriteScan(); 02092 } 02093 02094 CcReleaseMasterLock( OldIrql); 02095 }

VOID CcFastCopyRead IN PFILE_OBJECT  FileObject,
IN ULONG  FileOffset,
IN ULONG  Length,
IN ULONG  PageCount,
OUT PVOID  Buffer,
OUT PIO_STATUS_BLOCK  IoStatus
 

Definition at line 588 of file copysup.c.

References ASSERT, _VACB::BaseAddress, _PRIVATE_CACHE_MAP::BeyondLastByte1, _PRIVATE_CACHE_MAP::BeyondLastByte2, Buffer, CcCopyReadExceptionFilter(), CcCopyReadWait, CcCopyReadWaitMiss, CcFreeActiveVacb(), CcFreeVirtualAddress(), CcGetVirtualAddress(), CcMissCounter, CcScheduleReadAhead(), CcThrowAway, COMPUTE_PAGES_SPANNED, DebugTrace, ExRaiseStatus(), FALSE, _PRIVATE_CACHE_MAP::FileOffset1, _PRIVATE_CACHE_MAP::FileOffset2, _SHARED_CACHE_MAP::FileSize, FlagOn, FO_RANDOM_ACCESS, FsRtlNormalizeNtstatus(), GetActiveVacb, HOT_STATISTIC, me, MmCheckCachedPageState(), MmResetPageFaultReadAhead, MmSavePageFaultReadAhead, MmSetPageFaultReadAhead, _SHARED_CACHE_MAP::NeedToZero, NTSTATUS(), NULL, PAGE_SHIFT, PsGetCurrentThread, _PRIVATE_CACHE_MAP::ReadAheadEnabled, _PRIVATE_CACHE_MAP::ReadAheadLength, ROUND_TO_PAGES, SetActiveVacb, Status, TRUE, VACB_MAPPING_GRANULARITY, and VACB_OFFSET_SHIFT.

Referenced by FsRtlCopyRead().

00599 : 00600 00601 This routine attempts to copy the specified file data from the cache 00602 into the output buffer, and deliver the correct I/O status. 00603 00604 This is a faster version of CcCopyRead which only supports 32-bit file 00605 offsets and synchronicity (Wait = TRUE). 00606 00607 Arguments: 00608 00609 FileObject - Pointer to the file object for a file which was 00610 opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for 00611 which CcInitializeCacheMap was called by the file system. 00612 00613 FileOffset - Byte offset in file for desired data. 00614 00615 Length - Length of desired data in bytes. 00616 00617 PageCount - Number of pages spanned by the read. 00618 00619 Buffer - Pointer to output buffer to which data should be copied. 00620 00621 IoStatus - Pointer to standard I/O status block to receive the status 00622 for the transfer. (STATUS_SUCCESS guaranteed for cache 00623 hits, otherwise the actual I/O status is returned.) 00624 00625 Note that even if FALSE is returned, the IoStatus.Information 00626 field will return the count of any bytes successfully 00627 transferred before a blocking condition occured. The caller 00628 may either choose to ignore this information, or resume 00629 the copy later accounting for bytes transferred. 00630 00631 Return Value: 00632 00633 None 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 // Get pointer to shared and private cache maps 00663 // 00664 00665 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 00666 PrivateCacheMap = FileObject->PrivateCacheMap; 00667 00668 // 00669 // Check for read past file size, the caller must filter this case out. 00670 // 00671 00672 ASSERT( (FileOffset + Length) <= SharedCacheMap->FileSize.LowPart ); 00673 00674 // 00675 // If read ahead is enabled, then do the read ahead here so it 00676 // overlaps with the copy (otherwise we will do it below). 00677 // Note that we are assuming that we will not get ahead of our 00678 // current transfer - if read ahead is working it should either 00679 // already be in memory or else underway. 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 // This is not an exact solution, but when IoPageRead gets a miss, 00691 // it cannot tell whether it was CcCopyRead or CcMdlRead, but since 00692 // the miss should occur very soon, by loading the pointer here 00693 // probably the right counter will get incremented, and in any case, 00694 // we hope the errrors average out! 00695 // 00696 00697 CcMissCounter = &CcCopyReadWaitMiss; 00698 00699 // 00700 // Increment performance counters 00701 // 00702 00703 HOT_STATISTIC(CcCopyReadWait) += 1; 00704 00705 // 00706 // See if we have an active Vacb, that we can just copy to. 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 // Get the starting point in the view. 00723 // 00724 00725 CacheBuffer = (PVOID)((PCHAR)ActiveVacb->BaseAddress + 00726 (FileOffset & (VACB_MAPPING_GRANULARITY - 1))); 00727 00728 // 00729 // Reduce LengthToCopy if it is greater than our caller's length. 00730 // 00731 00732 if (LengthToCopy > Length) { 00733 LengthToCopy = Length; 00734 } 00735 00736 // 00737 // Like the logic for the normal case below, we want to spin around 00738 // making sure Mm only reads the pages we will need. 00739 // 00740 00741 PagesToGo = COMPUTE_PAGES_SPANNED( CacheBuffer, 00742 LengthToCopy ) - 1; 00743 00744 // 00745 // Copy the data to the user buffer. 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 // Here's hoping that it is cheaper to call Mm to see if 00765 // the page is valid. If not let Mm know how many pages 00766 // we are after before doing the move. 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 // Handle the read here that stays on a single page. 00783 // 00784 00785 } else { 00786 00787 // 00788 // Here's hoping that it is cheaper to call Mm to see if 00789 // the page is valid. If not let Mm know how many pages 00790 // we are after before doing the move. 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 // If we got an access violation, then the user buffer went 00811 // away. Otherwise we must have gotten an I/O error trying 00812 // to bring the data in. 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 // Now adjust FileOffset and Length by what we copied. 00826 // 00827 00828 FileOffset += LengthToCopy; 00829 Length -= LengthToCopy; 00830 } 00831 00832 // 00833 // If that was all the data, then remember the Vacb 00834 // 00835 00836 if (Length == 0) { 00837 00838 SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty ); 00839 00840 // 00841 // Otherwise we must free it because we will map other vacbs below. 00842 // 00843 00844 } else { 00845 00846 CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty ); 00847 } 00848 } 00849 00850 // 00851 // Not all of the transfer will come back at once, so we have to loop 00852 // until the entire transfer is complete. 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 // Call local routine to Map or Access the file data, then move the data, 00865 // then call another local routine to free the data. If we cannot map 00866 // the data because of a Wait condition, return FALSE. 00867 // 00868 // Note that this call may result in an exception, however, if it 00869 // does no Bcb is returned and this routine has absolutely no 00870 // cleanup to perform. Therefore, we do not have a try-finally 00871 // and we allow the possibility that we will simply be unwound 00872 // without notice. 00873 // 00874 00875 CacheBuffer = CcGetVirtualAddress( SharedCacheMap, 00876 FOffset, 00877 &Vacb, 00878 &ReceivedLength ); 00879 00880 BeyondLastByte = FOffset.LowPart + ReceivedLength; 00881 00882 // 00883 // If we got more than we need, make sure to only transfer 00884 // the right amount. 00885 // 00886 00887 if (ReceivedLength > Length) { 00888 ReceivedLength = Length; 00889 } 00890 00891 // 00892 // It is possible for the user buffer to become no longer accessible 00893 // since it was last checked by the I/O system. If we fail to access 00894 // the buffer we must raise a status that the caller's exception 00895 // filter considers as "expected". Also we unmap the Bcb here, since 00896 // we otherwise would have no other reason to put a try-finally around 00897 // this loop. 00898 // 00899 00900 try { 00901 00902 PagesToGo = COMPUTE_PAGES_SPANNED( CacheBuffer, 00903 ReceivedLength ) - 1; 00904 00905 // 00906 // We know exactly how much we want to read here, and we do not 00907 // want to read any more in case the caller is doing random access. 00908 // Our read ahead logic takes care of detecting sequential reads, 00909 // and tends to do large asynchronous read aheads. So far we have 00910 // only mapped the data and we have not forced any in. What we 00911 // do now is get into a loop where we copy a page at a time and 00912 // just prior to each move, we tell MM how many additional pages 00913 // we would like to have read in, in the event that we take a 00914 // fault. With this strategy, for cache hits we never make a single 00915 // expensive call to MM to guarantee that the data is in, yet if we 00916 // do take a fault, we are guaranteed to only take one fault because 00917 // we will read all of the data in for the rest of the transfer. 00918 // 00919 // We test first for the multiple page case, to keep the small 00920 // reads faster. 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 // Here's hoping that it is cheaper to call Mm to see if 00938 // the page is valid. If not let Mm know how many pages 00939 // we are after before doing the move. 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 // Handle the read here that stays on a single page. 00956 // 00957 00958 } else { 00959 00960 // 00961 // Here's hoping that it is cheaper to call Mm to see if 00962 // the page is valid. If not let Mm know how many pages 00963 // we are after before doing the move. 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 // If we get an exception, then we have to renable page fault 00981 // clustering and unmap on the way out. 00982 // 00983 00984 MmResetPageFaultReadAhead( Thread, SavedState ); 00985 00986 00987 CcFreeVirtualAddress( Vacb ); 00988 00989 // 00990 // If we got an access violation, then the user buffer went 00991 // away. Otherwise we must have gotten an I/O error trying 00992 // to bring the data in. 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 // Update number of bytes transferred. 01006 // 01007 01008 Length -= ReceivedLength; 01009 01010 // 01011 // Unmap the data now, and calculate length left to transfer. 01012 // 01013 01014 if (Length != 0) { 01015 01016 // 01017 // If there is more to go, just free this vacb. 01018 // 01019 01020 CcFreeVirtualAddress( Vacb ); 01021 01022 } else { 01023 01024 // 01025 // Otherwise save it for the next time through. 01026 // 01027 01028 SetActiveVacb( SharedCacheMap, OldIrql, Vacb, (FOffset.LowPart >> PAGE_SHIFT), 0 ); 01029 break; 01030 } 01031 01032 // 01033 // Assume we did not get all the data we wanted, and set FOffset 01034 // to the end of the returned data. 01035 // 01036 01037 FOffset.LowPart = BeyondLastByte; 01038 } 01039 01040 MmResetPageFaultReadAhead( Thread, SavedState ); 01041 01042 CcMissCounter = &CcThrowAway; 01043 01044 // 01045 // Now enable read ahead if it looks like we got any misses, and do 01046 // the first one. 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 // Now that we have described our desired read ahead, let's 01059 // shift the read history down. 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 }

VOID CcFastCopyWrite IN PFILE_OBJECT  FileObject,
IN ULONG  FileOffset,
IN ULONG  Length,
IN PVOID  Buffer
 

Definition at line 1482 of file copysup.c.

References ACTIVE_PAGE_IS_DIRTY, _SHARED_CACHE_MAP::ActiveVacbSpinLock, ASSERT, _VACB::BaseAddress, BooleanFlagOn, Buffer, CcCopyReadExceptionFilter(), CcFreeActiveVacb(), CcMapAndCopy(), DebugTrace, ExRaiseStatus(), FALSE, FlagOn, FO_WRITE_THROUGH, FsRtlNormalizeNtstatus(), GetActiveVacb, me, _SHARED_CACHE_MAP::NeedToZero, _SHARED_CACHE_MAP::NeedToZeroVacb, NTSTATUS(), NULL, PAGE_SHIFT, PAGE_SIZE, SetActiveVacb, Status, VACB_MAPPING_GRANULARITY, ZERO_FIRST_PAGE, ZERO_LAST_PAGE, and ZERO_MIDDLE_PAGES.

Referenced by FsRtlCopyWrite().

01491 : 01492 01493 This routine attempts to copy the specified file data from the specified 01494 buffer into the Cache, and deliver the correct I/O status. 01495 01496 This is a faster version of CcCopyWrite which only supports 32-bit file 01497 offsets and synchronicity (Wait = TRUE) and no Write Through. 01498 01499 Arguments: 01500 01501 FileObject - Pointer to the file object for a file which was 01502 opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for 01503 which CcInitializeCacheMap was called by the file system. 01504 01505 FileOffset - Byte offset in file to receive the data. 01506 01507 Length - Length of data in bytes. 01508 01509 Buffer - Pointer to input buffer from which data should be copied. 01510 01511 Return Value: 01512 01513 None 01514 01515 Raises: 01516 01517 STATUS_INSUFFICIENT_RESOURCES - If a pool allocation failure occurs. 01518 This can only occur if Wait was specified as TRUE. (If Wait is 01519 specified as FALSE, and an allocation failure occurs, this 01520 routine simply returns FALSE.) 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 // Get pointer to shared cache map and a copy of valid data length 01541 // 01542 01543 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 01544 01545 // 01546 // See if we have an active Vacb, that we can just copy to. 01547 // 01548 01549 GetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, PageIsDirty ); 01550 01551 if (ActiveVacb != NULL) { 01552 01553 // 01554 // See if the request starts in the ActivePage. WriteThrough requests must 01555 // go the longer route through CcMapAndCopy, where WriteThrough flushes are 01556 // implemented. 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 // Reduce LengthToCopy if it is greater than our caller's length. 01566 // 01567 01568 if (LengthToCopy > Length) { 01569 LengthToCopy = Length; 01570 } 01571 01572 // 01573 // Copy the data to the user buffer. 01574 // 01575 01576 try { 01577 01578 // 01579 // If we are copying to a page that is locked down, then 01580 // we have to do it under our spinlock, and update the 01581 // NeedToZero field. 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 // The FastLock may not write our "flag". 01593 // 01594 01595 OldIrql = 0; 01596 01597 ExAcquireFastLock( &SharedCacheMap->ActiveVacbSpinLock, &OldIrql ); 01598 01599 // 01600 // Note that the NeedToZero could be cleared, since we 01601 // tested it without the spinlock. 01602 // 01603 01604 ActiveAddress = SharedCacheMap->NeedToZero; 01605 if ((ActiveAddress != NULL) && 01606 (ActiveVacb == SharedCacheMap->NeedToZeroVacb) && 01607 (((PCHAR)CacheBuffer + LengthToCopy) > (PCHAR)ActiveAddress)) { 01608 01609 // 01610 // If we are skipping some bytes in the page, then we need 01611 // to zero them. 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 // If we failed to overwrite the uninitialized data, 01631 // zero it now (we cannot safely restore NeedToZero). 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 // If we got an access violation, then the user buffer went 01642 // away. Otherwise we must have gotten an I/O error trying 01643 // to bring the data in. 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 // Now adjust FileOffset and Length by what we copied. 01657 // 01658 01659 Buffer = (PVOID)((PCHAR)Buffer + LengthToCopy); 01660 FileOffset += LengthToCopy; 01661 Length -= LengthToCopy; 01662 01663 // 01664 // If that was all the data, then get outski... 01665 // 01666 01667 if (Length == 0) { 01668 01669 SetActiveVacb( SharedCacheMap, OldIrql, ActiveVacb, ActivePage, ACTIVE_PAGE_IS_DIRTY ); 01670 return; 01671 } 01672 01673 // 01674 // Remember that the page is dirty now. 01675 // 01676 01677 PageIsDirty |= ACTIVE_PAGE_IS_DIRTY; 01678 } 01679 01680 CcFreeActiveVacb( SharedCacheMap, ActiveVacb, ActivePage, PageIsDirty ); 01681 01682 // 01683 // Else someone else could have the active page, and may want to zero 01684 // the range we plan to write! 01685 // 01686 01687 } else if (SharedCacheMap->NeedToZero != NULL) { 01688 01689 CcFreeActiveVacb( SharedCacheMap, NULL, 0, FALSE ); 01690 } 01691 01692 // 01693 // Set up for call to CcMapAndCopy 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 // At this point we can calculate the ReadOnly flag for 01706 // the purposes of whether to use the Bcb resource, and 01707 // we can calculate the ZeroFlags. 01708 // 01709 01710 // 01711 // We can always zero middle pages, if any. 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 // Call a routine to map and copy the data in Mm and get out. 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 }

VOID CcPostDeferredWrites  ) 
 

Definition at line 2099 of file copysup.c.

References _DEFERRED_WRITE::BytesToWrite, CcCanIWrite(), CcDeferredWrites, CcDeferredWriteSpinLock, _DEFERRED_WRITE::Context1, _DEFERRED_WRITE::Context2, _DEFERRED_WRITE::DeferredWriteLinks, _DEFERRED_WRITE::Event, ExFreePool(), FALSE, _DEFERRED_WRITE::FileObject, KeSetEvent(), _DEFERRED_WRITE::LimitModifiedPages, NULL, and _DEFERRED_WRITE::PostRoutine.

Referenced by CcCanIWrite(), CcDeferWrite(), CcFlushCache(), CcLazyWriteScan(), CcUnpinRepinnedBcb(), and CcWriteBehind().

02104 : 02105 02106 This routine may be called to see if any deferred writes should be posted 02107 now, and to post them. It should be called any time the status of the 02108 queue may have changed, such as when a new entry has been added, or the 02109 Lazy Writer has finished writing out buffers and set them clean. 02110 02111 Arguments: 02112 02113 None 02114 02115 Return Value: 02116 02117 None 02118 02119 --*/ 02120 02121 { 02122 PDEFERRED_WRITE DeferredWrite; 02123 ULONG TotalBytesLetLoose = 0; 02124 KIRQL OldIrql; 02125 02126 do { 02127 02128 // 02129 // Initially clear the deferred write structure pointer 02130 // and syncrhronize. 02131 // 02132 02133 DeferredWrite = NULL; 02134 02135 ExAcquireSpinLock( &CcDeferredWriteSpinLock, &OldIrql ); 02136 02137 // 02138 // If the list is empty we are done. 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 // Check for a paranoid case here that TotalBytesLetLoose 02155 // wraps. We stop processing the list at this time. 02156 // 02157 02158 TotalBytesLetLoose += DeferredWrite->BytesToWrite; 02159 02160 if (TotalBytesLetLoose < DeferredWrite->BytesToWrite) { 02161 02162 DeferredWrite = NULL; 02163 break; 02164 } 02165 02166 // 02167 // If it is now ok to post this write, remove him from 02168 // the list. 02169 // 02170 02171 if (CcCanIWrite( DeferredWrite->FileObject, 02172 TotalBytesLetLoose, 02173 FALSE, 02174 MAXUCHAR - 1 )) { 02175 02176 RemoveEntryList( &DeferredWrite->DeferredWriteLinks ); 02177 break; 02178 02179 // 02180 // Otherwise, it is time to stop processing the list, so 02181 // we clear the pointer again unless we throttled this item 02182 // because of a private dirty page limit. 02183 // 02184 02185 } else { 02186 02187 // 02188 // If this was a private throttle, skip over it and 02189 // remove its byte count from the running total. 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 // If we got something, set the event or call the post routine 02213 // and deallocate the structure. 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 // Loop until we find no more work to do. 02232 // 02233 02234 } while (DeferredWrite != NULL); 02235 } }


Generated on Sat May 15 19:43:17 2004 for test by doxygen 1.3.7