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

fastio.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 FastIo.c 00008 00009 Abstract: 00010 00011 The Fast I/O path is used to avoid calling the file systems directly to 00012 do a cached read. This module is only used if the file object indicates 00013 that caching is enabled (i.e., the private cache map is not null). 00014 00015 Author: 00016 00017 Gary Kimura [GaryKi] 25-Feb-1991 00018 00019 Revision History: 00020 00021 Tom Miller [TomM] 14-Apr-1991 Added Fast Write routines 00022 00023 --*/ 00024 00025 #include "FsRtlP.h" 00026 00027 // 00028 // Trace level for the module 00029 // 00030 00031 #define Dbg (0x04000000) 00032 00033 #ifdef ALLOC_PRAGMA 00034 #pragma alloc_text(PAGE, FsRtlCopyRead) 00035 #pragma alloc_text(PAGE, FsRtlCopyWrite) 00036 #pragma alloc_text(PAGE, FsRtlMdlRead) 00037 #pragma alloc_text(PAGE, FsRtlMdlReadDev) 00038 #pragma alloc_text(PAGE, FsRtlPrepareMdlWrite) 00039 #pragma alloc_text(PAGE, FsRtlPrepareMdlWriteDev) 00040 #pragma alloc_text(PAGE, FsRtlMdlWriteComplete) 00041 #pragma alloc_text(PAGE, FsRtlMdlWriteCompleteDev) 00042 #pragma alloc_text(PAGE, FsRtlAcquireFileForModWrite) 00043 #pragma alloc_text(PAGE, FsRtlReleaseFileForModWrite) 00044 #pragma alloc_text(PAGE, FsRtlAcquireFileForCcFlush) 00045 #pragma alloc_text(PAGE, FsRtlReleaseFileForCcFlush) 00046 #pragma alloc_text(PAGE, FsRtlAcquireFileExclusive) 00047 #pragma alloc_text(PAGE, FsRtlReleaseFile) 00048 #pragma alloc_text(PAGE, FsRtlGetFileSize) 00049 #pragma alloc_text(PAGE, FsRtlSetFileSize) 00050 #endif 00051 00052 00053 BOOLEAN 00054 FsRtlCopyRead ( 00055 IN PFILE_OBJECT FileObject, 00056 IN PLARGE_INTEGER FileOffset, 00057 IN ULONG Length, 00058 IN BOOLEAN Wait, 00059 IN ULONG LockKey, 00060 OUT PVOID Buffer, 00061 OUT PIO_STATUS_BLOCK IoStatus, 00062 IN PDEVICE_OBJECT DeviceObject 00063 ) 00064 00065 /*++ 00066 00067 Routine Description: 00068 00069 This routine does a fast cached read bypassing the usual file system 00070 entry routine (i.e., without the Irp). It is used to do a copy read 00071 of a cached file object. For a complete description of the arguments 00072 see CcCopyRead. 00073 00074 Arguments: 00075 00076 FileObject - Pointer to the file object being read. 00077 00078 FileOffset - Byte offset in file for desired data. 00079 00080 Length - Length of desired data in bytes. 00081 00082 Wait - FALSE if caller may not block, TRUE otherwise 00083 00084 Buffer - Pointer to output buffer to which data should be copied. 00085 00086 IoStatus - Pointer to standard I/O status block to receive the status 00087 for the transfer. 00088 00089 Return Value: 00090 00091 FALSE - if Wait was supplied as FALSE and the data was not delivered, or 00092 if there is an I/O error. 00093 00094 TRUE - if the data is being delivered 00095 00096 --*/ 00097 00098 { 00099 PFSRTL_COMMON_FCB_HEADER Header; 00100 BOOLEAN Status = TRUE; 00101 ULONG PageCount = COMPUTE_PAGES_SPANNED( FileOffset->QuadPart, Length ); 00102 LARGE_INTEGER BeyondLastByte; 00103 PDEVICE_OBJECT targetVdo; 00104 00105 PAGED_CODE(); 00106 00107 // 00108 // Special case a read of zero length 00109 // 00110 00111 if (Length != 0) { 00112 00113 // 00114 // Check for overflow. Returning false here will re-route this request through the 00115 // IRP based path, but this isn't performance critical. 00116 // 00117 00118 if (MAXLONGLONG - FileOffset->QuadPart < (LONGLONG)Length) { 00119 00120 IoStatus->Status = STATUS_INVALID_PARAMETER; 00121 IoStatus->Information = 0; 00122 00123 return FALSE; 00124 } 00125 00126 BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length; 00127 Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 00128 00129 // 00130 // Enter the file system 00131 // 00132 00133 FsRtlEnterFileSystem(); 00134 00135 // 00136 // Increment performance counters and get the resource 00137 // 00138 00139 if (Wait) { 00140 00141 HOT_STATISTIC(CcFastReadWait) += 1; 00142 00143 // 00144 // Acquired shared on the common fcb header 00145 // 00146 00147 (VOID)ExAcquireResourceShared( Header->Resource, TRUE ); 00148 00149 } else { 00150 00151 HOT_STATISTIC(CcFastReadNoWait) += 1; 00152 00153 // 00154 // Acquired shared on the common fcb header, and return if we 00155 // don't get it 00156 // 00157 00158 if (!ExAcquireResourceShared( Header->Resource, FALSE )) { 00159 00160 FsRtlExitFileSystem(); 00161 00162 CcFastReadResourceMiss += 1; 00163 00164 return FALSE; 00165 } 00166 } 00167 00168 // 00169 // Now that the File is acquired shared, we can safely test if it 00170 // is really cached and if we can do fast i/o and if not, then 00171 // release the fcb and return. 00172 // 00173 00174 if ((FileObject->PrivateCacheMap == NULL) || 00175 (Header->IsFastIoPossible == FastIoIsNotPossible)) { 00176 00177 ExReleaseResource( Header->Resource ); 00178 FsRtlExitFileSystem(); 00179 00180 HOT_STATISTIC(CcFastReadNotPossible) += 1; 00181 00182 return FALSE; 00183 } 00184 00185 // 00186 // Check if fast I/O is questionable and if so then go ask the 00187 // file system the answer 00188 // 00189 00190 if (Header->IsFastIoPossible == FastIoIsQuestionable) { 00191 00192 PFAST_IO_DISPATCH FastIoDispatch; 00193 00194 ASSERT(!KeIsExecutingDpc()); 00195 00196 targetVdo = IoGetRelatedDeviceObject( FileObject ); 00197 FastIoDispatch = targetVdo->DriverObject->FastIoDispatch; 00198 00199 00200 // 00201 // All file systems that set "Is Questionable" had better support 00202 // fast I/O 00203 // 00204 00205 ASSERT(FastIoDispatch != NULL); 00206 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 00207 00208 // 00209 // Call the file system to check for fast I/O. If the answer is 00210 // anything other than GoForIt then we cannot take the fast I/O 00211 // path. 00212 // 00213 00214 if (!FastIoDispatch->FastIoCheckIfPossible( FileObject, 00215 FileOffset, 00216 Length, 00217 Wait, 00218 LockKey, 00219 TRUE, // read operation 00220 IoStatus, 00221 targetVdo )) { 00222 00223 // 00224 // Fast I/O is not possible so release the Fcb and return. 00225 // 00226 00227 ExReleaseResource( Header->Resource ); 00228 FsRtlExitFileSystem(); 00229 00230 HOT_STATISTIC(CcFastReadNotPossible) += 1; 00231 00232 return FALSE; 00233 } 00234 } 00235 00236 // 00237 // Check for read past file size. 00238 // 00239 00240 if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) { 00241 00242 if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) { 00243 IoStatus->Status = STATUS_END_OF_FILE; 00244 IoStatus->Information = 0; 00245 00246 ExReleaseResource( Header->Resource ); 00247 FsRtlExitFileSystem(); 00248 00249 return TRUE; 00250 } 00251 00252 Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart ); 00253 } 00254 00255 // 00256 // We can do fast i/o so call the cc routine to do the work and then 00257 // release the fcb when we've done. If for whatever reason the 00258 // copy read fails, then return FALSE to our caller. 00259 // 00260 // Also mark this as the top level "Irp" so that lower file system 00261 // levels will not attempt a pop-up 00262 // 00263 00264 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 00265 00266 try { 00267 00268 if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) { 00269 00270 CcFastCopyRead( FileObject, 00271 FileOffset->LowPart, 00272 Length, 00273 PageCount, 00274 Buffer, 00275 IoStatus ); 00276 00277 FileObject->Flags |= FO_FILE_FAST_IO_READ; 00278 00279 ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) || 00280 ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart)); 00281 00282 } else { 00283 00284 Status = CcCopyRead( FileObject, 00285 FileOffset, 00286 Length, 00287 Wait, 00288 Buffer, 00289 IoStatus ); 00290 00291 FileObject->Flags |= FO_FILE_FAST_IO_READ; 00292 00293 ASSERT( !Status || (IoStatus->Status == STATUS_END_OF_FILE) || 00294 ((LONGLONG)(FileOffset->QuadPart + IoStatus->Information) <= Header->FileSize.QuadPart)); 00295 } 00296 00297 if (Status) { 00298 00299 FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information; 00300 } 00301 00302 } except( FsRtlIsNtstatusExpected(GetExceptionCode()) 00303 ? EXCEPTION_EXECUTE_HANDLER 00304 : EXCEPTION_CONTINUE_SEARCH ) { 00305 00306 Status = FALSE; 00307 } 00308 00309 PsGetCurrentThread()->TopLevelIrp = 0; 00310 00311 ExReleaseResource( Header->Resource ); 00312 FsRtlExitFileSystem(); 00313 return Status; 00314 00315 } else { 00316 00317 // 00318 // A zero length transfer was requested. 00319 // 00320 00321 IoStatus->Status = STATUS_SUCCESS; 00322 IoStatus->Information = 0; 00323 00324 return TRUE; 00325 } 00326 } 00327 00328 00329 BOOLEAN 00330 FsRtlCopyWrite ( 00331 IN PFILE_OBJECT FileObject, 00332 IN PLARGE_INTEGER FileOffset, 00333 IN ULONG Length, 00334 IN BOOLEAN Wait, 00335 IN ULONG LockKey, 00336 IN PVOID Buffer, 00337 OUT PIO_STATUS_BLOCK IoStatus, 00338 IN PDEVICE_OBJECT DeviceObject 00339 ) 00340 00341 /*++ 00342 00343 Routine Description: 00344 00345 This routine does a fast cached write bypassing the usual file system 00346 entry routine (i.e., without the Irp). It is used to do a copy write 00347 of a cached file object. For a complete description of the arguments 00348 see CcCopyWrite. 00349 00350 Arguments: 00351 00352 FileObject - Pointer to the file object being write. 00353 00354 FileOffset - Byte offset in file for desired data. 00355 00356 Length - Length of desired data in bytes. 00357 00358 Wait - FALSE if caller may not block, TRUE otherwise 00359 00360 Buffer - Pointer to output buffer to which data should be copied. 00361 00362 IoStatus - Pointer to standard I/O status block to receive the status 00363 for the transfer. 00364 00365 Return Value: 00366 00367 FALSE - if Wait was supplied as FALSE and the data was not delivered, or 00368 if there is an I/O error. 00369 00370 TRUE - if the data is being delivered 00371 00372 --*/ 00373 00374 { 00375 PFSRTL_COMMON_FCB_HEADER Header; 00376 BOOLEAN AcquiredShared = FALSE; 00377 BOOLEAN Status = TRUE; 00378 BOOLEAN FileSizeChanged = FALSE; 00379 BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) && 00380 (FileOffset->HighPart == -1)); 00381 00382 PAGED_CODE(); 00383 00384 // 00385 // Get a real pointer to the common fcb header 00386 // 00387 00388 Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 00389 00390 // 00391 // Do we need to verify the volume? If so, we must go to the file 00392 // system. Also return FALSE if FileObject is write through, the 00393 // File System must do that. 00394 // 00395 00396 if (CcCanIWrite( FileObject, Length, Wait, FALSE ) && 00397 !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) && 00398 CcCopyWriteWontFlush(FileObject, FileOffset, Length)) { 00399 00400 // 00401 // Assume our transfer will work 00402 // 00403 00404 IoStatus->Status = STATUS_SUCCESS; 00405 IoStatus->Information = Length; 00406 00407 // 00408 // Special case the zero byte length 00409 // 00410 00411 if (Length != 0) { 00412 00413 // 00414 // Enter the file system 00415 // 00416 00417 FsRtlEnterFileSystem(); 00418 00419 // 00420 // Split into separate paths for increased performance. First 00421 // we have the faster path which only supports Wait == TRUE and 00422 // 32 bits. We will make an unsafe test on whether the fast path 00423 // is ok, then just return FALSE later if we were wrong. This 00424 // should virtually never happen. 00425 // 00426 // IMPORTANT NOTE: It is very important that any changes made to 00427 // this path also be applied to the 64-bit path 00428 // which is the else of this test! 00429 // 00430 00431 if (Wait && (Header->AllocationSize.HighPart == 0)) { 00432 00433 ULONG Offset, NewFileSize; 00434 ULONG OldFileSize; 00435 ULONG OldValidDataLength; 00436 BOOLEAN Wrapped; 00437 00438 // 00439 // Make our best guess on whether we need the file exclusive 00440 // or shared. Note that we do not check FileOffset->HighPart 00441 // until below. 00442 // 00443 00444 NewFileSize = FileOffset->LowPart + Length; 00445 00446 if (WriteToEndOfFile || (NewFileSize > Header->ValidDataLength.LowPart)) { 00447 00448 // 00449 // Acquired shared on the common fcb header 00450 // 00451 00452 ExAcquireResourceExclusive( Header->Resource, TRUE ); 00453 00454 } else { 00455 00456 // 00457 // Acquired shared on the common fcb header 00458 // 00459 00460 ExAcquireResourceShared( Header->Resource, TRUE ); 00461 00462 AcquiredShared = TRUE; 00463 } 00464 00465 // 00466 // We have the fcb shared now check if we can do fast i/o 00467 // and if the file space is allocated, and if not then 00468 // release the fcb and return. 00469 // 00470 00471 if (WriteToEndOfFile) { 00472 00473 Offset = Header->FileSize.LowPart; 00474 NewFileSize = Header->FileSize.LowPart + Length; 00475 Wrapped = NewFileSize < Header->FileSize.LowPart; 00476 00477 } else { 00478 00479 Offset = FileOffset->LowPart; 00480 NewFileSize = FileOffset->LowPart + Length; 00481 Wrapped = (NewFileSize < FileOffset->LowPart) || (FileOffset->HighPart != 0); 00482 } 00483 00484 // 00485 // Now that the File is acquired shared, we can safely test 00486 // if it is really cached and if we can do fast i/o and we 00487 // do not have to extend. If not then release the fcb and 00488 // return. 00489 // 00490 // Get out if we have too much to zero. This case is not important 00491 // for performance, and a file system supporting sparseness may have 00492 // a way to do this more efficiently. 00493 // 00494 00495 if ((FileObject->PrivateCacheMap == NULL) || 00496 (Header->IsFastIoPossible == FastIoIsNotPossible) || 00497 (NewFileSize > Header->AllocationSize.LowPart) || 00498 (Offset >= (Header->ValidDataLength.LowPart + 0x2000)) || 00499 (Header->AllocationSize.HighPart != 0) || Wrapped) { 00500 00501 ExReleaseResource( Header->Resource ); 00502 FsRtlExitFileSystem(); 00503 00504 return FALSE; 00505 } 00506 00507 // 00508 // If we will be extending ValidDataLength, we will have to 00509 // get the Fcb exclusive, and make sure that FastIo is still 00510 // possible. We should only execute this block of code very 00511 // rarely, when the unsafe test for ValidDataLength failed 00512 // above. 00513 // 00514 00515 if (AcquiredShared && (NewFileSize > Header->ValidDataLength.LowPart)) { 00516 00517 ExReleaseResource( Header->Resource ); 00518 00519 ExAcquireResourceExclusive( Header->Resource, TRUE ); 00520 00521 // 00522 // If writing to end of file, we must recalculate new size. 00523 // 00524 00525 if (WriteToEndOfFile) { 00526 00527 Offset = Header->FileSize.LowPart; 00528 NewFileSize = Header->FileSize.LowPart + Length; 00529 Wrapped = NewFileSize < Header->FileSize.LowPart; 00530 } 00531 00532 if ((FileObject->PrivateCacheMap == NULL) || 00533 (Header->IsFastIoPossible == FastIoIsNotPossible) || 00534 (NewFileSize > Header->AllocationSize.LowPart) || 00535 (Header->AllocationSize.HighPart != 0) || Wrapped) { 00536 00537 ExReleaseResource( Header->Resource ); 00538 FsRtlExitFileSystem(); 00539 00540 return FALSE; 00541 } 00542 } 00543 00544 // 00545 // Check if fast I/O is questionable and if so then go ask 00546 // the file system the answer 00547 // 00548 00549 if (Header->IsFastIoPossible == FastIoIsQuestionable) { 00550 00551 PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject ); 00552 PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch; 00553 IO_STATUS_BLOCK IoStatus; 00554 00555 // 00556 // All file system then set "Is Questionable" had better 00557 // support fast I/O 00558 // 00559 00560 ASSERT(FastIoDispatch != NULL); 00561 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 00562 00563 // 00564 // Call the file system to check for fast I/O. If the 00565 // answer is anything other than GoForIt then we cannot 00566 // take the fast I/O path. 00567 // 00568 00569 ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff); 00570 00571 if (!FastIoDispatch->FastIoCheckIfPossible( FileObject, 00572 FileOffset->QuadPart != (LONGLONG)-1 ? 00573 FileOffset : &Header->FileSize, 00574 Length, 00575 TRUE, 00576 LockKey, 00577 FALSE, // write operation 00578 &IoStatus, 00579 targetVdo )) { 00580 00581 // 00582 // Fast I/O is not possible so release the Fcb and 00583 // return. 00584 // 00585 00586 ExReleaseResource( Header->Resource ); 00587 FsRtlExitFileSystem(); 00588 00589 return FALSE; 00590 } 00591 } 00592 00593 // 00594 // Now see if we will change FileSize. We have to do it now 00595 // so that our reads are not nooped. 00596 // 00597 00598 if (NewFileSize > Header->FileSize.LowPart) { 00599 00600 FileSizeChanged = TRUE; 00601 OldFileSize = Header->FileSize.LowPart; 00602 OldValidDataLength = Header->ValidDataLength.LowPart; 00603 Header->FileSize.LowPart = NewFileSize; 00604 } 00605 00606 // 00607 // We can do fast i/o so call the cc routine to do the work 00608 // and then release the fcb when we've done. If for whatever 00609 // reason the copy write fails, then return FALSE to our 00610 // caller. 00611 // 00612 // Also mark this as the top level "Irp" so that lower file 00613 // system levels will not attempt a pop-up 00614 // 00615 00616 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 00617 00618 try { 00619 00620 // 00621 // See if we have to do some zeroing 00622 // 00623 00624 if (Offset > Header->ValidDataLength.LowPart) { 00625 00626 LARGE_INTEGER ZeroEnd; 00627 00628 ZeroEnd.LowPart = Offset; 00629 ZeroEnd.HighPart = 0; 00630 00631 CcZeroData( FileObject, 00632 &Header->ValidDataLength, 00633 &ZeroEnd, 00634 TRUE ); 00635 } 00636 00637 CcFastCopyWrite( FileObject, 00638 Offset, 00639 Length, 00640 Buffer ); 00641 00642 } except( FsRtlIsNtstatusExpected(GetExceptionCode()) 00643 ? EXCEPTION_EXECUTE_HANDLER 00644 : EXCEPTION_CONTINUE_SEARCH ) { 00645 00646 Status = FALSE; 00647 } 00648 00649 PsGetCurrentThread()->TopLevelIrp = 0; 00650 00651 // 00652 // If we succeeded, see if we have to update FileSize or 00653 // ValidDataLength. 00654 // 00655 00656 if (Status) { 00657 00658 // 00659 // In the case of ValidDataLength, we really have to 00660 // check again since we did not do this when we acquired 00661 // the resource exclusive. 00662 // 00663 00664 if (NewFileSize > Header->ValidDataLength.LowPart) { 00665 00666 Header->ValidDataLength.LowPart = NewFileSize; 00667 } 00668 00669 // 00670 // Set this handle as having modified the file 00671 // 00672 00673 FileObject->Flags |= FO_FILE_MODIFIED; 00674 00675 if (FileSizeChanged) { 00676 00677 CcGetFileSizePointer(FileObject)->LowPart = NewFileSize; 00678 00679 FileObject->Flags |= FO_FILE_SIZE_CHANGED; 00680 } 00681 00682 // 00683 // Also update the file position pointer 00684 // 00685 00686 FileObject->CurrentByteOffset.LowPart = Offset + Length; 00687 FileObject->CurrentByteOffset.HighPart = 0; 00688 00689 // 00690 // If we did not succeed, then we must restore the original 00691 // FileSize while holding the PagingIoResource exclusive if 00692 // it exists. 00693 // 00694 00695 } else if (FileSizeChanged) { 00696 00697 if ( Header->PagingIoResource != NULL ) { 00698 00699 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 00700 Header->FileSize.LowPart = OldFileSize; 00701 Header->ValidDataLength.LowPart = OldValidDataLength; 00702 ExReleaseResource( Header->PagingIoResource ); 00703 00704 } else { 00705 00706 Header->FileSize.LowPart = OldFileSize; 00707 Header->ValidDataLength.LowPart = OldValidDataLength; 00708 } 00709 } 00710 00711 // 00712 // Here is the 64-bit or no-wait path. 00713 // 00714 00715 } else { 00716 00717 LARGE_INTEGER Offset, NewFileSize; 00718 LARGE_INTEGER OldFileSize; 00719 LARGE_INTEGER OldValidDataLength; 00720 00721 ASSERT(!KeIsExecutingDpc()); 00722 00723 // 00724 // Make our best guess on whether we need the file exclusive 00725 // or shared. 00726 // 00727 00728 NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length; 00729 00730 if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) { 00731 00732 // 00733 // Acquired shared on the common fcb header, and return 00734 // if we don't get it. 00735 // 00736 00737 if (!ExAcquireResourceExclusive( Header->Resource, Wait )) { 00738 00739 FsRtlExitFileSystem(); 00740 00741 return FALSE; 00742 } 00743 00744 } else { 00745 00746 // 00747 // Acquired shared on the common fcb header, and return 00748 // if we don't get it. 00749 // 00750 00751 if (!ExAcquireResourceShared( Header->Resource, Wait )) { 00752 00753 FsRtlExitFileSystem(); 00754 00755 return FALSE; 00756 } 00757 00758 AcquiredShared = TRUE; 00759 } 00760 00761 00762 // 00763 // We have the fcb shared now check if we can do fast i/o 00764 // and if the file space is allocated, and if not then 00765 // release the fcb and return. 00766 // 00767 00768 if (WriteToEndOfFile) { 00769 00770 Offset = Header->FileSize; 00771 NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length; 00772 00773 } else { 00774 00775 Offset = *FileOffset; 00776 NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length; 00777 } 00778 00779 // 00780 // Now that the File is acquired shared, we can safely test 00781 // if it is really cached and if we can do fast i/o and we 00782 // do not have to extend. If not then release the fcb and 00783 // return. 00784 // 00785 // Get out if we are about to zero too much as well, as commented above. 00786 // Likewise, for NewFileSizes that exceed MAXLONGLONG. 00787 // 00788 00789 if ((FileObject->PrivateCacheMap == NULL) || 00790 (Header->IsFastIoPossible == FastIoIsNotPossible) || 00791 (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000)) || 00792 (MAXLONGLONG - Offset.QuadPart < (LONGLONG)Length) || 00793 (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ) { 00794 00795 ExReleaseResource( Header->Resource ); 00796 FsRtlExitFileSystem(); 00797 00798 return FALSE; 00799 } 00800 00801 // 00802 // If we will be extending ValidDataLength, we will have to 00803 // get the Fcb exclusive, and make sure that FastIo is still 00804 // possible. We should only execute this block of code very 00805 // rarely, when the unsafe test for ValidDataLength failed 00806 // above. 00807 // 00808 00809 if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) { 00810 00811 ExReleaseResource( Header->Resource ); 00812 00813 if (!ExAcquireResourceExclusive( Header->Resource, Wait )) { 00814 00815 FsRtlExitFileSystem(); 00816 00817 return FALSE; 00818 } 00819 00820 // 00821 // If writing to end of file, we must recalculate new size. 00822 // 00823 00824 if (WriteToEndOfFile) { 00825 00826 Offset = Header->FileSize; 00827 NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length; 00828 } 00829 00830 if ((FileObject->PrivateCacheMap == NULL) || 00831 (Header->IsFastIoPossible == FastIoIsNotPossible) || 00832 ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) { 00833 00834 ExReleaseResource( Header->Resource ); 00835 FsRtlExitFileSystem(); 00836 00837 return FALSE; 00838 } 00839 } 00840 00841 // 00842 // Check if fast I/O is questionable and if so then go ask 00843 // the file system the answer 00844 // 00845 00846 if (Header->IsFastIoPossible == FastIoIsQuestionable) { 00847 00848 PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch; 00849 IO_STATUS_BLOCK IoStatus; 00850 00851 // 00852 // All file system then set "Is Questionable" had better 00853 // support fast I/O 00854 // 00855 00856 ASSERT(FastIoDispatch != NULL); 00857 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 00858 00859 // 00860 // Call the file system to check for fast I/O. If the 00861 // answer is anything other than GoForIt then we cannot 00862 // take the fast I/O path. 00863 // 00864 00865 ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff); 00866 00867 if (!FastIoDispatch->FastIoCheckIfPossible( FileObject, 00868 FileOffset->QuadPart != (LONGLONG)-1 ? 00869 FileOffset : &Header->FileSize, 00870 Length, 00871 Wait, 00872 LockKey, 00873 FALSE, // write operation 00874 &IoStatus, 00875 DeviceObject )) { 00876 00877 // 00878 // Fast I/O is not possible so release the Fcb and 00879 // return. 00880 // 00881 00882 ExReleaseResource( Header->Resource ); 00883 FsRtlExitFileSystem(); 00884 00885 return FALSE; 00886 } 00887 } 00888 00889 // 00890 // Now see if we will change FileSize. We have to do it now 00891 // so that our reads are not nooped. 00892 // 00893 00894 if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) { 00895 00896 FileSizeChanged = TRUE; 00897 OldFileSize = Header->FileSize; 00898 OldValidDataLength = Header->ValidDataLength; 00899 00900 // 00901 // Deal with an extremely rare pathalogical case here the 00902 // file size wraps. 00903 // 00904 00905 if ( (Header->FileSize.HighPart != NewFileSize.HighPart) && 00906 (Header->PagingIoResource != NULL) ) { 00907 00908 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 00909 Header->FileSize = NewFileSize; 00910 ExReleaseResource( Header->PagingIoResource ); 00911 00912 } else { 00913 00914 Header->FileSize = NewFileSize; 00915 } 00916 } 00917 00918 // 00919 // We can do fast i/o so call the cc routine to do the work 00920 // and then release the fcb when we've done. If for whatever 00921 // reason the copy write fails, then return FALSE to our 00922 // caller. 00923 // 00924 // Also mark this as the top level "Irp" so that lower file 00925 // system levels will not attempt a pop-up 00926 // 00927 00928 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 00929 00930 try { 00931 00932 // 00933 // See if we have to do some zeroing 00934 // 00935 00936 if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) { 00937 00938 Status = CcZeroData( FileObject, 00939 &Header->ValidDataLength, 00940 &Offset, 00941 Wait ); 00942 } 00943 00944 if (Status) { 00945 00946 Status = CcCopyWrite( FileObject, 00947 &Offset, 00948 Length, 00949 Wait, 00950 Buffer ); 00951 } 00952 00953 } except( FsRtlIsNtstatusExpected(GetExceptionCode()) 00954 ? EXCEPTION_EXECUTE_HANDLER 00955 : EXCEPTION_CONTINUE_SEARCH ) { 00956 00957 Status = FALSE; 00958 } 00959 00960 PsGetCurrentThread()->TopLevelIrp = 0; 00961 00962 // 00963 // If we succeeded, see if we have to update FileSize or 00964 // ValidDataLength. 00965 // 00966 00967 if (Status) { 00968 00969 // 00970 // In the case of ValidDataLength, we really have to 00971 // check again since we did not do this when we acquired 00972 // the resource exclusive. 00973 // 00974 00975 if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) { 00976 00977 // 00978 // Deal with an extremely rare pathalogical case here 00979 // the ValidDataLength wraps. 00980 // 00981 00982 if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) && 00983 (Header->PagingIoResource != NULL) ) { 00984 00985 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 00986 Header->ValidDataLength = NewFileSize; 00987 ExReleaseResource( Header->PagingIoResource ); 00988 00989 } else { 00990 00991 Header->ValidDataLength = NewFileSize; 00992 } 00993 } 00994 00995 // 00996 // Set this handle as having modified the file 00997 // 00998 00999 FileObject->Flags |= FO_FILE_MODIFIED; 01000 01001 if (FileSizeChanged) { 01002 01003 *CcGetFileSizePointer(FileObject) = NewFileSize; 01004 01005 FileObject->Flags |= FO_FILE_SIZE_CHANGED; 01006 } 01007 01008 // 01009 // Also update the current file position pointer 01010 // 01011 01012 FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length; 01013 01014 // 01015 // If we did not succeed, then we must restore the original 01016 // FileSize while holding the PagingIoResource exclusive if 01017 // it exists. 01018 // 01019 01020 } else if (FileSizeChanged) { 01021 01022 if ( Header->PagingIoResource != NULL ) { 01023 01024 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 01025 Header->FileSize = OldFileSize; 01026 Header->ValidDataLength = OldValidDataLength; 01027 ExReleaseResource( Header->PagingIoResource ); 01028 01029 } else { 01030 01031 Header->FileSize = OldFileSize; 01032 Header->ValidDataLength = OldValidDataLength; 01033 } 01034 } 01035 01036 } 01037 01038 ExReleaseResource( Header->Resource ); 01039 FsRtlExitFileSystem(); 01040 01041 return Status; 01042 01043 } else { 01044 01045 // 01046 // A zero length transfer was requested. 01047 // 01048 01049 return TRUE; 01050 } 01051 01052 } else { 01053 01054 // 01055 // The volume must be verified or the file is write through. 01056 // 01057 01058 return FALSE; 01059 } 01060 } 01061 01062 01063 BOOLEAN 01064 FsRtlMdlReadDev ( 01065 IN PFILE_OBJECT FileObject, 01066 IN PLARGE_INTEGER FileOffset, 01067 IN ULONG Length, 01068 IN ULONG LockKey, 01069 OUT PMDL *MdlChain, 01070 OUT PIO_STATUS_BLOCK IoStatus, 01071 IN PDEVICE_OBJECT DeviceObject 01072 ) 01073 01074 /*++ 01075 01076 Routine Description: 01077 01078 This routine does a fast cached mdl read bypassing the usual file system 01079 entry routine (i.e., without the Irp). It is used to do a copy read 01080 of a cached file object. For a complete description of the arguments 01081 see CcMdlRead. 01082 01083 Arguments: 01084 01085 FileObject - Pointer to the file object being read. 01086 01087 FileOffset - Byte offset in file for desired data. 01088 01089 Length - Length of desired data in bytes. 01090 01091 MdlChain - On output it returns a pointer to an MDL chain describing 01092 the desired data. 01093 01094 IoStatus - Pointer to standard I/O status block to receive the status 01095 for the transfer. 01096 01097 DeviceObject - Supplies DeviceObject for callee. 01098 01099 Return Value: 01100 01101 FALSE - if the data was not delivered, or if there is an I/O error. 01102 01103 TRUE - if the data is being delivered 01104 01105 --*/ 01106 01107 { 01108 PFSRTL_COMMON_FCB_HEADER Header; 01109 BOOLEAN Status = TRUE; 01110 LARGE_INTEGER BeyondLastByte; 01111 01112 PAGED_CODE(); 01113 01114 // 01115 // Special case a read of zero length 01116 // 01117 01118 if (Length == 0) { 01119 01120 IoStatus->Status = STATUS_SUCCESS; 01121 IoStatus->Information = 0; 01122 01123 return TRUE; 01124 } 01125 01126 // 01127 // Overflows should've been handled by caller. 01128 // 01129 01130 ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length); 01131 01132 01133 // 01134 // Get a real pointer to the common fcb header 01135 // 01136 01137 BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length; 01138 Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 01139 01140 // 01141 // Enter the file system 01142 // 01143 01144 FsRtlEnterFileSystem(); 01145 01146 CcFastMdlReadWait += 1; 01147 01148 // 01149 // Acquired shared on the common fcb header 01150 // 01151 01152 (VOID)ExAcquireResourceShared( Header->Resource, TRUE ); 01153 01154 // 01155 // Now that the File is acquired shared, we can safely test if it is 01156 // really cached and if we can do fast i/o and if not 01157 // then release the fcb and return. 01158 // 01159 01160 if ((FileObject->PrivateCacheMap == NULL) || 01161 (Header->IsFastIoPossible == FastIoIsNotPossible)) { 01162 01163 ExReleaseResource( Header->Resource ); 01164 FsRtlExitFileSystem(); 01165 01166 CcFastMdlReadNotPossible += 1; 01167 01168 return FALSE; 01169 } 01170 01171 // 01172 // Check if fast I/O is questionable and if so then go ask the file system 01173 // the answer 01174 // 01175 01176 if (Header->IsFastIoPossible == FastIoIsQuestionable) { 01177 01178 PFAST_IO_DISPATCH FastIoDispatch; 01179 01180 ASSERT(!KeIsExecutingDpc()); 01181 01182 FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch; 01183 01184 01185 // 01186 // All file system then set "Is Questionable" had better support fast I/O 01187 // 01188 01189 ASSERT(FastIoDispatch != NULL); 01190 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 01191 01192 // 01193 // Call the file system to check for fast I/O. If the answer is anything 01194 // other than GoForIt then we cannot take the fast I/O path. 01195 // 01196 01197 if (!FastIoDispatch->FastIoCheckIfPossible( FileObject, 01198 FileOffset, 01199 Length, 01200 TRUE, 01201 LockKey, 01202 TRUE, // read operation 01203 IoStatus, 01204 IoGetRelatedDeviceObject( FileObject ) )) { 01205 01206 // 01207 // Fast I/O is not possible so release the Fcb and return. 01208 // 01209 01210 ExReleaseResource( Header->Resource ); 01211 FsRtlExitFileSystem(); 01212 01213 CcFastMdlReadNotPossible += 1; 01214 01215 return FALSE; 01216 } 01217 } 01218 01219 // 01220 // Check for read past file size. 01221 // 01222 01223 if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) { 01224 01225 if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) { 01226 IoStatus->Status = STATUS_END_OF_FILE; 01227 IoStatus->Information = 0; 01228 01229 ExReleaseResource( Header->Resource ); 01230 FsRtlExitFileSystem(); 01231 01232 return TRUE; 01233 } 01234 01235 Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart ); 01236 } 01237 01238 // 01239 // We can do fast i/o so call the cc routine to do the work and then 01240 // release the fcb when we've done. If for whatever reason the 01241 // mdl read fails, then return FALSE to our caller. 01242 // 01243 // 01244 // Also mark this as the top level "Irp" so that lower file system levels 01245 // will not attempt a pop-up 01246 // 01247 01248 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 01249 01250 try { 01251 01252 CcMdlRead( FileObject, FileOffset, Length, MdlChain, IoStatus ); 01253 01254 FileObject->Flags |= FO_FILE_FAST_IO_READ; 01255 01256 } except( FsRtlIsNtstatusExpected(GetExceptionCode()) 01257 ? EXCEPTION_EXECUTE_HANDLER 01258 : EXCEPTION_CONTINUE_SEARCH ) { 01259 01260 Status = FALSE; 01261 } 01262 01263 PsGetCurrentThread()->TopLevelIrp = 0; 01264 01265 ExReleaseResource( Header->Resource ); 01266 FsRtlExitFileSystem(); 01267 01268 return Status; 01269 } 01270 01271 01272 // 01273 // The old routine will either dispatch or call FsRtlMdlReadDev 01274 // 01275 01276 BOOLEAN 01277 FsRtlMdlRead ( 01278 IN PFILE_OBJECT FileObject, 01279 IN PLARGE_INTEGER FileOffset, 01280 IN ULONG Length, 01281 IN ULONG LockKey, 01282 OUT PMDL *MdlChain, 01283 OUT PIO_STATUS_BLOCK IoStatus 01284 ) 01285 01286 /*++ 01287 01288 Routine Description: 01289 01290 This routine does a fast cached mdl read bypassing the usual file system 01291 entry routine (i.e., without the Irp). It is used to do a copy read 01292 of a cached file object. For a complete description of the arguments 01293 see CcMdlRead. 01294 01295 Arguments: 01296 01297 FileObject - Pointer to the file object being read. 01298 01299 FileOffset - Byte offset in file for desired data. 01300 01301 Length - Length of desired data in bytes. 01302 01303 MdlChain - On output it returns a pointer to an MDL chain describing 01304 the desired data. 01305 01306 IoStatus - Pointer to standard I/O status block to receive the status 01307 for the transfer. 01308 01309 Return Value: 01310 01311 FALSE - if the data was not delivered, or if there is an I/O error. 01312 01313 TRUE - if the data is being delivered 01314 01315 --*/ 01316 01317 { 01318 PDEVICE_OBJECT DeviceObject, VolumeDeviceObject; 01319 PFAST_IO_DISPATCH FastIoDispatch; 01320 01321 DeviceObject = IoGetRelatedDeviceObject( FileObject ); 01322 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 01323 01324 // 01325 // See if the (top-level) FileSystem has a FastIo routine, and if so, call it. 01326 // 01327 01328 if ((FastIoDispatch != NULL) && 01329 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead)) && 01330 (FastIoDispatch->MdlRead != NULL)) { 01331 01332 return FastIoDispatch->MdlRead( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject ); 01333 01334 } else { 01335 01336 // 01337 // Get the DeviceObject for the volume. If that DeviceObject is different, and 01338 // it specifies the FastIo routine, then we have to return FALSE here and cause 01339 // an Irp to get generated. 01340 // 01341 01342 VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 01343 if ((VolumeDeviceObject != DeviceObject) && 01344 (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) && 01345 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead)) && 01346 (FastIoDispatch->MdlRead != NULL)) { 01347 01348 return FALSE; 01349 01350 // 01351 // Otherwise, call the default routine. 01352 // 01353 01354 } else { 01355 01356 return FsRtlMdlReadDev( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject ); 01357 } 01358 } 01359 } 01360 01361 01362 // 01363 // The old routine will either dispatch or call FsRtlMdlReadCompleteDev 01364 // 01365 01366 BOOLEAN 01367 FsRtlMdlReadComplete ( 01368 IN PFILE_OBJECT FileObject, 01369 IN PMDL MdlChain 01370 ) 01371 01372 /*++ 01373 01374 Routine Description: 01375 01376 This routine does a fast cached mdl read bypassing the usual file system 01377 entry routine (i.e., without the Irp). It is used to do a copy read 01378 of a cached file object. 01379 01380 Arguments: 01381 01382 FileObject - Pointer to the file object being read. 01383 01384 MdlChain - Supplies a pointer to an MDL chain returned from CcMdlRead. 01385 01386 Return Value: 01387 01388 None 01389 01390 --*/ 01391 01392 { 01393 PDEVICE_OBJECT DeviceObject, VolumeDeviceObject; 01394 PFAST_IO_DISPATCH FastIoDispatch; 01395 01396 DeviceObject = IoGetRelatedDeviceObject( FileObject ); 01397 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 01398 01399 // 01400 // See if the (top-level) FileSystem has a FastIo routine, and if so, call it. 01401 // 01402 01403 if ((FastIoDispatch != NULL) && 01404 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete)) && 01405 (FastIoDispatch->MdlReadComplete != NULL)) { 01406 01407 return FastIoDispatch->MdlReadComplete( FileObject, MdlChain, DeviceObject ); 01408 01409 } else { 01410 01411 // 01412 // Get the DeviceObject for the volume. If that DeviceObject is different, and 01413 // it specifies the FastIo routine, then we have to return FALSE here and cause 01414 // an Irp to get generated. 01415 // 01416 01417 VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 01418 if ((VolumeDeviceObject != DeviceObject) && 01419 (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) && 01420 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete)) && 01421 (FastIoDispatch->MdlReadComplete != NULL)) { 01422 01423 return FALSE; 01424 01425 // 01426 // Otherwise, call the default routine. 01427 // 01428 01429 } else { 01430 01431 return FsRtlMdlReadCompleteDev( FileObject, MdlChain, DeviceObject ); 01432 } 01433 } 01434 } 01435 01436 01437 BOOLEAN 01438 FsRtlMdlReadCompleteDev ( 01439 IN PFILE_OBJECT FileObject, 01440 IN PMDL MdlChain, 01441 IN PDEVICE_OBJECT DeviceObject 01442 ) 01443 01444 /*++ 01445 01446 Routine Description: 01447 01448 This routine does a fast cached mdl read bypassing the usual file system 01449 entry routine (i.e., without the Irp). It is used to do a copy read 01450 of a cached file object. 01451 01452 Arguments: 01453 01454 FileObject - Pointer to the file object being read. 01455 01456 MdlChain - Supplies a pointer to an MDL chain returned from CcMdlRead. 01457 01458 DeviceObject - Supplies the DeviceObject for the callee. 01459 01460 Return Value: 01461 01462 None 01463 01464 --*/ 01465 01466 01467 { 01468 CcMdlReadComplete2( FileObject, MdlChain ); 01469 return TRUE; 01470 } 01471 01472 01473 BOOLEAN 01474 FsRtlPrepareMdlWriteDev ( 01475 IN PFILE_OBJECT FileObject, 01476 IN PLARGE_INTEGER FileOffset, 01477 IN ULONG Length, 01478 IN ULONG LockKey, 01479 OUT PMDL *MdlChain, 01480 OUT PIO_STATUS_BLOCK IoStatus, 01481 IN PDEVICE_OBJECT DeviceObject 01482 ) 01483 01484 /*++ 01485 01486 Routine Description: 01487 01488 This routine does a fast cached mdl read bypassing the usual file system 01489 entry routine (i.e., without the Irp). It is used to do a copy read 01490 of a cached file object. For a complete description of the arguments 01491 see CcMdlRead. 01492 01493 Arguments: 01494 01495 FileObject - Pointer to the file object being read. 01496 01497 FileOffset - Byte offset in file for desired data. 01498 01499 Length - Length of desired data in bytes. 01500 01501 MdlChain - On output it returns a pointer to an MDL chain describing 01502 the desired data. 01503 01504 IoStatus - Pointer to standard I/O status block to receive the status 01505 for the transfer. 01506 01507 DeviceObject - Supplies the DeviceObject for the callee. 01508 01509 Return Value: 01510 01511 FALSE - if the data was not written, or if there is an I/O error. 01512 01513 TRUE - if the data is being written 01514 01515 --*/ 01516 01517 { 01518 PFSRTL_COMMON_FCB_HEADER Header; 01519 LARGE_INTEGER Offset, NewFileSize; 01520 LARGE_INTEGER OldFileSize; 01521 LARGE_INTEGER OldValidDataLength; 01522 BOOLEAN Status = TRUE; 01523 BOOLEAN AcquiredShared = FALSE; 01524 BOOLEAN FileSizeChanged = FALSE; 01525 BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) && 01526 (FileOffset->HighPart == -1)); 01527 01528 PAGED_CODE(); 01529 01530 // 01531 // Call CcCanIWrite. Also return FALSE if FileObject is write through, 01532 // the File System must do that. 01533 // 01534 01535 if ( !CcCanIWrite( FileObject, Length, TRUE, FALSE ) || 01536 FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) { 01537 01538 return FALSE; 01539 } 01540 01541 // 01542 // Assume our transfer will work 01543 // 01544 01545 IoStatus->Status = STATUS_SUCCESS; 01546 01547 // 01548 // Special case the zero byte length 01549 // 01550 01551 if (Length == 0) { 01552 01553 return TRUE; 01554 } 01555 01556 // 01557 // Get a real pointer to the common fcb header 01558 // 01559 01560 Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 01561 01562 // 01563 // Enter the file system 01564 // 01565 01566 FsRtlEnterFileSystem(); 01567 01568 // 01569 // Make our best guess on whether we need the file exclusive or 01570 // shared. 01571 // 01572 01573 NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length; 01574 01575 if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) { 01576 01577 // 01578 // Acquired exclusive on the common fcb header, and return if we don't 01579 // get it. 01580 // 01581 01582 ExAcquireResourceExclusive( Header->Resource, TRUE ); 01583 01584 } else { 01585 01586 // 01587 // Acquired shared on the common fcb header, and return if we don't 01588 // get it. 01589 // 01590 01591 ExAcquireResourceShared( Header->Resource, TRUE ); 01592 01593 AcquiredShared = TRUE; 01594 } 01595 01596 01597 // 01598 // We have the fcb shared now check if we can do fast i/o and if the file 01599 // space is allocated, and if not then release the fcb and return. 01600 // 01601 01602 if (WriteToEndOfFile) { 01603 01604 Offset = Header->FileSize; 01605 NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length; 01606 01607 } else { 01608 01609 Offset = *FileOffset; 01610 NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length; 01611 } 01612 01613 // 01614 // Now that the File is acquired shared, we can safely test if it is 01615 // really cached and if we can do fast i/o and we do not have to extend. 01616 // If not then release the fcb and return. 01617 // 01618 01619 if ((FileObject->PrivateCacheMap == NULL) || 01620 (Header->IsFastIoPossible == FastIoIsNotPossible) || 01621 (MAXLONGLONG - Offset.QuadPart < (LONGLONG)Length) || 01622 ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) { 01623 01624 ExReleaseResource( Header->Resource ); 01625 FsRtlExitFileSystem(); 01626 01627 return FALSE; 01628 } 01629 01630 // 01631 // If we will be extending ValidDataLength, we will have to get the 01632 // Fcb exclusive, and make sure that FastIo is still possible. 01633 // 01634 01635 if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) { 01636 01637 ExReleaseResource( Header->Resource ); 01638 01639 ExAcquireResourceExclusive( Header->Resource, TRUE ); 01640 01641 AcquiredShared = FALSE; 01642 01643 // 01644 // If writing to end of file, we must recalculate new size. 01645 // 01646 01647 if (WriteToEndOfFile) { 01648 01649 Offset = Header->FileSize; 01650 NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length; 01651 } 01652 01653 if ((FileObject->PrivateCacheMap == NULL) || 01654 (Header->IsFastIoPossible == FastIoIsNotPossible) || 01655 ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart )) { 01656 01657 ExReleaseResource( Header->Resource ); 01658 FsRtlExitFileSystem(); 01659 01660 return FALSE; 01661 } 01662 } 01663 01664 // 01665 // Check if fast I/O is questionable and if so then go ask the file system 01666 // the answer 01667 // 01668 01669 if (Header->IsFastIoPossible == FastIoIsQuestionable) { 01670 01671 PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch; 01672 01673 // 01674 // All file system then set "Is Questionable" had better support fast I/O 01675 // 01676 01677 ASSERT(FastIoDispatch != NULL); 01678 ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); 01679 01680 // 01681 // Call the file system to check for fast I/O. If the answer is anything 01682 // other than GoForIt then we cannot take the fast I/O path. 01683 // 01684 01685 if (!FastIoDispatch->FastIoCheckIfPossible( FileObject, 01686 FileOffset, 01687 Length, 01688 TRUE, 01689 LockKey, 01690 FALSE, // write operation 01691 IoStatus, 01692 IoGetRelatedDeviceObject( FileObject ) )) { 01693 01694 // 01695 // Fast I/O is not possible so release the Fcb and return. 01696 // 01697 01698 ExReleaseResource( Header->Resource ); 01699 FsRtlExitFileSystem(); 01700 01701 return FALSE; 01702 } 01703 } 01704 01705 // 01706 // Now see if we will change FileSize. We have to do it now so that our 01707 // reads are not nooped. 01708 // 01709 01710 if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) { 01711 01712 FileSizeChanged = TRUE; 01713 OldFileSize = Header->FileSize; 01714 OldValidDataLength = Header->ValidDataLength; 01715 01716 // 01717 // Deal with an extremely rare pathalogical case here the file 01718 // size wraps. 01719 // 01720 01721 if ( (Header->FileSize.HighPart != NewFileSize.HighPart) && 01722 (Header->PagingIoResource != NULL) ) { 01723 01724 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 01725 Header->FileSize = NewFileSize; 01726 ExReleaseResource( Header->PagingIoResource ); 01727 01728 } else { 01729 01730 Header->FileSize = NewFileSize; 01731 } 01732 } 01733 01734 // 01735 // We can do fast i/o so call the cc routine to do the work and then 01736 // release the fcb when we've done. If for whatever reason the 01737 // copy write fails, then return FALSE to our caller. 01738 // 01739 // 01740 // Also mark this as the top level "Irp" so that lower file system levels 01741 // will not attempt a pop-up 01742 // 01743 01744 PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; 01745 01746 try { 01747 01748 // 01749 // See if we have to do some zeroing 01750 // 01751 01752 if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) { 01753 01754 Status = CcZeroData( FileObject, 01755 &Header->ValidDataLength, 01756 &Offset, 01757 TRUE ); 01758 } 01759 01760 if (Status) { 01761 01762 CcPrepareMdlWrite( FileObject, &Offset, Length, MdlChain, IoStatus ); 01763 } 01764 01765 } except( FsRtlIsNtstatusExpected(GetExceptionCode()) 01766 ? EXCEPTION_EXECUTE_HANDLER 01767 : EXCEPTION_CONTINUE_SEARCH ) { 01768 01769 Status = FALSE; 01770 } 01771 01772 PsGetCurrentThread()->TopLevelIrp = 0; 01773 01774 // 01775 // If we succeeded, see if we have to update FileSize or ValidDataLength. 01776 // 01777 01778 if (Status) { 01779 01780 // 01781 // In the case of ValidDataLength, we really have to check again 01782 // since we did not do this when we acquired the resource exclusive. 01783 // 01784 01785 if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) { 01786 01787 // 01788 // Deal with an extremely rare pathalogical case here the 01789 // ValidDataLength wraps. 01790 // 01791 01792 if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) && 01793 (Header->PagingIoResource != NULL) ) { 01794 01795 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 01796 Header->ValidDataLength = NewFileSize; 01797 ExReleaseResource( Header->PagingIoResource ); 01798 01799 } else { 01800 01801 Header->ValidDataLength = NewFileSize; 01802 } 01803 } 01804 01805 // 01806 // Set this handle as having modified the file 01807 // 01808 01809 FileObject->Flags |= FO_FILE_MODIFIED; 01810 01811 if (FileSizeChanged) { 01812 01813 *CcGetFileSizePointer(FileObject) = NewFileSize; 01814 01815 FileObject->Flags |= FO_FILE_SIZE_CHANGED; 01816 } 01817 01818 // 01819 // If we did not succeed, then we must restore the original FileSize 01820 // and release the resource. In the success path, the cache manager 01821 // will release the resource. 01822 // 01823 01824 } else { 01825 01826 if (FileSizeChanged) { 01827 01828 if ( Header->PagingIoResource != NULL ) { 01829 01830 (VOID)ExAcquireResourceExclusive( Header->PagingIoResource, TRUE ); 01831 Header->FileSize = OldFileSize; 01832 Header->ValidDataLength = OldValidDataLength; 01833 ExReleaseResource( Header->PagingIoResource ); 01834 01835 } else { 01836 01837 Header->FileSize = OldFileSize; 01838 Header->ValidDataLength = OldValidDataLength; 01839 } 01840 } 01841 } 01842 01843 // 01844 // Now we can release the resource. 01845 // 01846 01847 ExReleaseResource( Header->Resource ); 01848 01849 FsRtlExitFileSystem(); 01850 01851 return Status; 01852 } 01853 01854 01855 // 01856 // The old routine will either dispatch or call FsRtlPrepareMdlWriteDev 01857 // 01858 01859 BOOLEAN 01860 FsRtlPrepareMdlWrite ( 01861 IN PFILE_OBJECT FileObject, 01862 IN PLARGE_INTEGER FileOffset, 01863 IN ULONG Length, 01864 IN ULONG LockKey, 01865 OUT PMDL *MdlChain, 01866 OUT PIO_STATUS_BLOCK IoStatus 01867 ) 01868 01869 /*++ 01870 01871 Routine Description: 01872 01873 This routine does a fast cached mdl read bypassing the usual file system 01874 entry routine (i.e., without the Irp). It is used to do a copy read 01875 of a cached file object. For a complete description of the arguments 01876 see CcMdlRead. 01877 01878 Arguments: 01879 01880 FileObject - Pointer to the file object being read. 01881 01882 FileOffset - Byte offset in file for desired data. 01883 01884 Length - Length of desired data in bytes. 01885 01886 MdlChain - On output it returns a pointer to an MDL chain describing 01887 the desired data. 01888 01889 IoStatus - Pointer to standard I/O status block to receive the status 01890 for the transfer. 01891 01892 Return Value: 01893 01894 FALSE - if the data was not written, or if there is an I/O error. 01895 01896 TRUE - if the data is being written 01897 01898 --*/ 01899 01900 { 01901 PDEVICE_OBJECT DeviceObject, VolumeDeviceObject; 01902 PFAST_IO_DISPATCH FastIoDispatch; 01903 01904 DeviceObject = IoGetRelatedDeviceObject( FileObject ); 01905 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 01906 01907 // 01908 // See if the (top-level) FileSystem has a FastIo routine, and if so, call it. 01909 // 01910 01911 if ((FastIoDispatch != NULL) && 01912 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, PrepareMdlWrite)) && 01913 (FastIoDispatch->PrepareMdlWrite != NULL)) { 01914 01915 return FastIoDispatch->PrepareMdlWrite( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject ); 01916 01917 } else { 01918 01919 // 01920 // Get the DeviceObject for the volume. If that DeviceObject is different, and 01921 // it specifies the FastIo routine, then we have to return FALSE here and cause 01922 // an Irp to get generated. 01923 // 01924 01925 VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 01926 if ((VolumeDeviceObject != DeviceObject) && 01927 (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) && 01928 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, PrepareMdlWrite)) && 01929 (FastIoDispatch->PrepareMdlWrite != NULL)) { 01930 01931 return FALSE; 01932 01933 // 01934 // Otherwise, call the default routine. 01935 // 01936 01937 } else { 01938 01939 return FsRtlPrepareMdlWriteDev( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject ); 01940 } 01941 } 01942 } 01943 01944 01945 // 01946 // The old routine will either dispatch or call FsRtlMdlWriteCompleteDev 01947 // 01948 01949 BOOLEAN 01950 FsRtlMdlWriteComplete ( 01951 IN PFILE_OBJECT FileObject, 01952 IN PLARGE_INTEGER FileOffset, 01953 IN PMDL MdlChain 01954 ) 01955 01956 /*++ 01957 01958 Routine Description: 01959 01960 This routine completes an Mdl write. 01961 01962 Arguments: 01963 01964 FileObject - Pointer to the file object being read. 01965 01966 MdlChain - Supplies a pointer to an MDL chain returned from CcMdlPrepareMdlWrite. 01967 01968 Return Value: 01969 01970 01971 01972 --*/ 01973 01974 { 01975 PDEVICE_OBJECT DeviceObject, VolumeDeviceObject; 01976 PFAST_IO_DISPATCH FastIoDispatch; 01977 01978 DeviceObject = IoGetRelatedDeviceObject( FileObject ); 01979 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 01980 01981 // 01982 // See if the (top-level) FileSystem has a FastIo routine, and if so, call it. 01983 // 01984 01985 if ((FastIoDispatch != NULL) && 01986 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) && 01987 (FastIoDispatch->MdlWriteComplete != NULL)) { 01988 01989 return FastIoDispatch->MdlWriteComplete( FileObject, FileOffset, MdlChain, DeviceObject ); 01990 01991 } else { 01992 01993 // 01994 // Get the DeviceObject for the volume. If that DeviceObject is different, and 01995 // it specifies the FastIo routine, then we have to return FALSE here and cause 01996 // an Irp to get generated. 01997 // 01998 01999 VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02000 if ((VolumeDeviceObject != DeviceObject) && 02001 (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) && 02002 (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) && 02003 (FastIoDispatch->MdlWriteComplete != NULL)) { 02004 02005 return FALSE; 02006 02007 // 02008 // Otherwise, call the default routine. 02009 // 02010 02011 } else { 02012 02013 return FsRtlMdlWriteCompleteDev( FileObject, FileOffset, MdlChain, DeviceObject ); 02014 } 02015 } 02016 } 02017 02018 02019 BOOLEAN 02020 FsRtlMdlWriteCompleteDev ( 02021 IN PFILE_OBJECT FileObject, 02022 IN PLARGE_INTEGER FileOffset, 02023 IN PMDL MdlChain, 02024 IN PDEVICE_OBJECT DeviceObject 02025 ) 02026 02027 /*++ 02028 02029 Routine Description: 02030 02031 This routine completes an Mdl write. 02032 02033 Arguments: 02034 02035 FileObject - Pointer to the file object being read. 02036 02037 MdlChain - Supplies a pointer to an MDL chain returned from CcMdlPrepareMdlWrite. 02038 02039 DeviceObject - Supplies the DeviceObject for the callee. 02040 02041 Return Value: 02042 02043 02044 02045 --*/ 02046 02047 02048 { 02049 // 02050 // Do not support WRITE_THROUGH in the fast path call. 02051 // 02052 02053 if (FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) { 02054 return FALSE; 02055 } 02056 02057 CcMdlWriteComplete2( FileObject, FileOffset, MdlChain ); 02058 return TRUE; 02059 } 02060 02061 02062 NTKERNELAPI 02063 BOOLEAN 02064 FsRtlAcquireFileForModWrite ( 02065 IN PFILE_OBJECT FileObject, 02066 IN PLARGE_INTEGER EndingOffset, 02067 OUT PERESOURCE *ResourceToRelease 02068 ) 02069 02070 /*++ 02071 02072 Routine Description: 02073 02074 This routine decides which file system resource the modified page 02075 writer should acquire and acquires it if possible. Wait is always 02076 specified as FALSE. We pass back the resource Mm has to release 02077 when the write completes. 02078 02079 Arguments: 02080 02081 FileObject - Pointer to the file object being written. 02082 02083 EndingOffset - The offset of the last byte being written + 1. 02084 02085 ByteCount - Length of data in bytes. 02086 02087 ResourceToRelease - Returns the resource to release. Not defined if 02088 FALSE is returned. 02089 02090 Return Value: 02091 02092 FALSE - The resource could not be acquired without waiting. 02093 02094 TRUE - The returned resource has been acquired. 02095 02096 --*/ 02097 02098 { 02099 PFSRTL_COMMON_FCB_HEADER Header; 02100 PERESOURCE ResourceAcquired; 02101 PDEVICE_OBJECT DeviceObject; 02102 PFAST_IO_DISPATCH FastIoDispatch; 02103 02104 BOOLEAN AcquireExclusive; 02105 02106 PAGED_CODE(); 02107 02108 Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; 02109 02110 // 02111 // First see if we have to call the file system. 02112 // 02113 02114 DeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02115 02116 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 02117 if ((FastIoDispatch->SizeOfFastIoDispatch > 02118 FIELD_OFFSET( FAST_IO_DISPATCH, AcquireForModWrite )) && 02119 (FastIoDispatch->AcquireForModWrite != NULL)) { 02120 02121 NTSTATUS Status; 02122 02123 Status = FastIoDispatch->AcquireForModWrite(FileObject, 02124 EndingOffset, 02125 ResourceToRelease, 02126 DeviceObject); 02127 02128 if (Status == STATUS_SUCCESS) { 02129 return( TRUE ); 02130 } else if (Status == STATUS_CANT_WAIT) { 02131 return( FALSE ); 02132 } else { 02133 02134 // 02135 // Fall through. When dealing with layered file systems, it might 02136 // be the case that the layered file system has the above dispatch 02137 // routine, but the FS it is layered on top of does not. In that 02138 // case, the layered file system will return an error code other 02139 // than STATUS_SUCCESS or STATUS_CANT_WAIT, and we simply handle 02140 // it as if the file system did not have the dispatch routine to 02141 // begin with. 02142 // 02143 02144 NOTHING; 02145 } 02146 } 02147 02148 // 02149 // We follow the following rules to determine which resource 02150 // to acquire. We use the flags in the common header. These 02151 // flags can't change once we have acquired any resource. 02152 // This means we can do an unsafe test and optimisticly 02153 // acquire a resource. At that point we can test the bits 02154 // to see if we have what we want. 02155 // 02156 // 0 - If there is no main resource, acquire nothing. 02157 // 02158 // 1 - Acquire the main resource exclusively if the 02159 // ACQUIRE_MAIN_RSRC_EX flag is set or we are extending 02160 // valid data. 02161 // 02162 // 2 - Acquire the main resource shared if there is 02163 // no paging io resource or the 02164 // ACQUIRE_MAIN_RSRC_SH flag is set. 02165 // 02166 // 3 - Otherwise acquire the paging io resource shared. 02167 // 02168 02169 if (Header->Resource == NULL) { 02170 02171 *ResourceToRelease = NULL; 02172 02173 return TRUE; 02174 } 02175 02176 if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX ) || 02177 (EndingOffset->QuadPart > Header->ValidDataLength.QuadPart && 02178 Header->ValidDataLength.QuadPart != Header->FileSize.QuadPart)) { 02179 02180 ResourceAcquired = Header->Resource; 02181 AcquireExclusive = TRUE; 02182 02183 } else if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH ) || 02184 Header->PagingIoResource == NULL) { 02185 02186 ResourceAcquired = Header->Resource; 02187 AcquireExclusive = FALSE; 02188 02189 } else { 02190 02191 ResourceAcquired = Header->PagingIoResource; 02192 AcquireExclusive = FALSE; 02193 } 02194 02195 // 02196 // Perform the following in a loop in case we need to back and 02197 // check the state of the resource acquisition. In most cases 02198 // the initial checks will succeed and we can proceed immediately. 02199 // We have to worry about the two FsRtl bits changing but 02200 // if there is no paging io resource before there won't ever be 02201 // one. 02202 // 02203 02204 while (TRUE) { 02205 02206 // 02207 // Now acquire the desired resource. 02208 // 02209 02210 if (AcquireExclusive) { 02211 02212 if (!ExAcquireResourceExclusive( ResourceAcquired, FALSE )) { 02213 02214 return FALSE; 02215 } 02216 02217 } else if (!ExAcquireSharedWaitForExclusive( ResourceAcquired, FALSE )) { 02218 02219 return FALSE; 02220 } 02221 02222 // 02223 // If the valid data length is changing or the exclusive bit is 02224 // set and we don't have the main resource exclusive then 02225 // release the current resource and acquire the main resource 02226 // exclusively and move to the top of the loop. 02227 // 02228 02229 if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX ) || 02230 (EndingOffset->QuadPart > Header->ValidDataLength.QuadPart && 02231 Header->ValidDataLength.QuadPart != Header->FileSize.QuadPart)) { 02232 02233 // 02234 // If we don't have the main resource exclusively then 02235 // release the current resource and attempt to acquire 02236 // the main resource exclusively. 02237 // 02238 02239 if (!AcquireExclusive) { 02240 02241 ExReleaseResource( ResourceAcquired ); 02242 AcquireExclusive = TRUE; 02243 ResourceAcquired = Header->Resource; 02244 continue; 02245 } 02246 02247 // 02248 // We have the correct resource. Exit the loop. 02249 // 02250 02251 // 02252 // If we should be acquiring the main resource shared then move 02253 // to acquire the correct resource and proceed to the top of the loop. 02254 // 02255 02256 } else if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH )) { 02257 02258 // 02259 // If we have the main resource exclusively then downgrade to 02260 // shared and exit the loop. 02261 // 02262 02263 if (AcquireExclusive) { 02264 02265 ExConvertExclusiveToShared( ResourceAcquired ); 02266 02267 // 02268 // If we have the paging io resource then give up this resource 02269 // and acquire the main resource exclusively. This is going 02270 // at it with a large hammer but is guaranteed to be resolved 02271 // in the next pass through the loop. 02272 // 02273 02274 } else if (ResourceAcquired != Header->Resource) { 02275 02276 ExReleaseResource( ResourceAcquired ); 02277 ResourceAcquired = Header->Resource; 02278 AcquireExclusive = TRUE; 02279 continue; 02280 } 02281 02282 // 02283 // We have the correct resource. Exit the loop. 02284 // 02285 02286 // 02287 // At this point we should have the paging Io resource shared 02288 // if it exists. If not then acquire it shared and release the 02289 // other resource and exit the loop. 02290 // 02291 02292 } else if (Header->PagingIoResource != NULL 02293 && ResourceAcquired != Header->PagingIoResource) { 02294 02295 ResourceAcquired = NULL; 02296 02297 if (ExAcquireSharedWaitForExclusive( Header->PagingIoResource, FALSE )) { 02298 02299 ResourceAcquired = Header->PagingIoResource; 02300 } 02301 02302 ExReleaseResource( Header->Resource ); 02303 02304 if (ResourceAcquired == NULL) { 02305 02306 return FALSE; 02307 } 02308 02309 // 02310 // We now have the correct resource. Exit the loop. 02311 // 02312 02313 // 02314 // We should have the main resource shared. If we don't then 02315 // degrade our lock to shared access. 02316 // 02317 02318 } else if (AcquireExclusive) { 02319 02320 ExConvertExclusiveToShared( ResourceAcquired ); 02321 02322 // 02323 // We now have the correct resource. Exit the loop. 02324 // 02325 } 02326 02327 // 02328 // We have the correct resource. Exit the loop. 02329 // 02330 02331 break; 02332 } 02333 02334 *ResourceToRelease = ResourceAcquired; 02335 02336 return TRUE; 02337 } 02338 02339 02340 NTKERNELAPI 02341 VOID 02342 FsRtlReleaseFileForModWrite ( 02343 IN PFILE_OBJECT FileObject, 02344 IN PERESOURCE ResourceToRelease 02345 ) 02346 02347 /*++ 02348 02349 Routine Description: 02350 02351 This routine releases a file system resource previously acquired for 02352 the modified page writer. 02353 02354 Arguments: 02355 02356 FileObject - Pointer to the file object being written. 02357 02358 ResourceToRelease - Supplies the resource to release. Not defined if 02359 FALSE is returned. 02360 02361 Return Value: 02362 02363 None. 02364 02365 --*/ 02366 02367 { 02368 PDEVICE_OBJECT DeviceObject; 02369 PFAST_IO_DISPATCH FastIoDispatch; 02370 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; 02371 02372 PAGED_CODE(); 02373 02374 // 02375 // First see if we have to call the file system. Note that in the case 02376 // of layered file systems, the layered file system might have the 02377 // dispatch routine, but the file system on which it is layered on may 02378 // not. In that case, the layered file system will return 02379 // STATUS_INVALID_DEVICE_REQUEST. 02380 // 02381 02382 DeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02383 02384 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 02385 if ((FastIoDispatch->SizeOfFastIoDispatch > 02386 FIELD_OFFSET( FAST_IO_DISPATCH, ReleaseForModWrite )) && 02387 (FastIoDispatch->ReleaseForModWrite != NULL)) { 02388 02389 Status = FastIoDispatch->ReleaseForModWrite( FileObject, ResourceToRelease, DeviceObject ); 02390 } 02391 02392 ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) ); 02393 02394 if (Status == STATUS_INVALID_DEVICE_REQUEST) { 02395 ExReleaseResource( ResourceToRelease ); 02396 } 02397 } 02398 02399 02400 NTKERNELAPI 02401 VOID 02402 FsRtlAcquireFileForCcFlush ( 02403 IN PFILE_OBJECT FileObject 02404 ) 02405 02406 /*++ 02407 02408 Routine Description: 02409 02410 This routine acquires a file system resource prior to a call to CcFlush. 02411 02412 Arguments: 02413 02414 FileObject - Pointer to the file object being written. 02415 02416 Return Value: 02417 02418 None. 02419 02420 --*/ 02421 02422 { 02423 PDEVICE_OBJECT DeviceObject; 02424 PFAST_IO_DISPATCH FastIoDispatch; 02425 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; 02426 02427 PAGED_CODE(); 02428 02429 // 02430 // First see if we have to call the file system. Note that in the case 02431 // of layered file systems, the layered file system might have the 02432 // dispatch routine, but the file system on which it is layered on may 02433 // not. In that case, the layered file system will return 02434 // STATUS_INVALID_DEVICE_REQUEST. 02435 // 02436 02437 DeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02438 02439 FsRtlEnterFileSystem(); 02440 02441 if ((FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch) && 02442 (FastIoDispatch->SizeOfFastIoDispatch > 02443 FIELD_OFFSET( FAST_IO_DISPATCH, AcquireForCcFlush )) && 02444 (FastIoDispatch->AcquireForCcFlush != NULL)) { 02445 02446 Status = FastIoDispatch->AcquireForCcFlush( FileObject, DeviceObject ); 02447 02448 } 02449 02450 02451 ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) ); 02452 02453 if (Status == STATUS_INVALID_DEVICE_REQUEST) { 02454 02455 PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext; 02456 02457 // 02458 // If not already owned get the main resource exclusive because me may 02459 // extend ValidDataLength. Otherwise acquire it one more time recursively. 02460 // 02461 02462 if (Header->Resource != NULL) { 02463 if (!ExIsResourceAcquiredShared(Header->Resource)) { 02464 ExAcquireResourceExclusive( Header->Resource, TRUE ); 02465 } else { 02466 ExAcquireResourceShared( Header->Resource, TRUE ); 02467 } 02468 } 02469 02470 // 02471 // Also get the paging I/O resource ahead of any MM resources. 02472 // 02473 02474 if (Header->PagingIoResource != NULL) { 02475 ExAcquireResourceShared( Header->PagingIoResource, TRUE ); 02476 } 02477 } 02478 } 02479 02480 02481 NTKERNELAPI 02482 VOID 02483 FsRtlReleaseFileForCcFlush ( 02484 IN PFILE_OBJECT FileObject 02485 ) 02486 02487 /*++ 02488 02489 Routine Description: 02490 02491 This routine releases a file system resource previously acquired for 02492 the CcFlush. 02493 02494 Arguments: 02495 02496 FileObject - Pointer to the file object being written. 02497 02498 Return Value: 02499 02500 None. 02501 02502 --*/ 02503 02504 { 02505 PDEVICE_OBJECT DeviceObject; 02506 PFAST_IO_DISPATCH FastIoDispatch; 02507 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; 02508 02509 PAGED_CODE(); 02510 02511 // 02512 // First see if we have to call the file system. Note that in the case 02513 // of layered file systems, the layered file system might have the 02514 // dispatch routine, but the file system on which it is layered on may 02515 // not. In that case, the layered file system will return 02516 // STATUS_INVALID_DEVICE_REQUEST. 02517 // 02518 02519 DeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02520 02521 if ((FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch) && 02522 (FastIoDispatch->SizeOfFastIoDispatch > 02523 FIELD_OFFSET( FAST_IO_DISPATCH, ReleaseForCcFlush )) && 02524 (FastIoDispatch->ReleaseForCcFlush != NULL)) { 02525 02526 Status = FastIoDispatch->ReleaseForCcFlush( FileObject, DeviceObject ); 02527 02528 } 02529 02530 ASSERT( (Status == STATUS_SUCCESS) || (Status == STATUS_INVALID_DEVICE_REQUEST) ); 02531 02532 if (Status == STATUS_INVALID_DEVICE_REQUEST) { 02533 02534 PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext; 02535 02536 // 02537 // Free whatever we acquired. 02538 // 02539 02540 if (Header->PagingIoResource != NULL) { 02541 ExReleaseResource( Header->PagingIoResource ); 02542 } 02543 02544 if (Header->Resource != NULL) { 02545 ExReleaseResource( Header->Resource ); 02546 } 02547 } 02548 02549 FsRtlExitFileSystem(); 02550 } 02551 02552 02553 NTKERNELAPI 02554 VOID 02555 FsRtlAcquireFileExclusive ( 02556 IN PFILE_OBJECT FileObject 02557 ) 02558 02559 /*++ 02560 02561 Routine Description: 02562 02563 This routine is used by NtCreateSection to pre-acquire file system 02564 resources in order to avoid deadlocks. If there is a FastIo entry 02565 for AcquireFileForNtCreateSection then that routine will be called. 02566 Otherwise, we will simply acquire the main file resource exclusive. 02567 If there is no main resource then we acquire nothing and return 02568 FALSE. In the cases that we acquire a resource, we also set the 02569 TopLevelIrp field in the thread local storage to indicate to file 02570 systems beneath us that we have acquired file system resources. 02571 02572 Arguments: 02573 02574 FileObject - Pointer to the file object being written. 02575 02576 Return Value: 02577 02578 NONE 02579 02580 --*/ 02581 02582 { 02583 PDEVICE_OBJECT DeviceObject; 02584 PFAST_IO_DISPATCH FastIoDispatch; 02585 PFSRTL_COMMON_FCB_HEADER Header; 02586 02587 PAGED_CODE(); 02588 02589 // 02590 // First see if we have to call the file system. 02591 // 02592 02593 DeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02594 02595 if ((FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch) && 02596 (FastIoDispatch->SizeOfFastIoDispatch > 02597 FIELD_OFFSET( FAST_IO_DISPATCH, AcquireFileForNtCreateSection )) && 02598 (FastIoDispatch->AcquireFileForNtCreateSection != NULL)) { 02599 02600 FsRtlEnterFileSystem(); 02601 FastIoDispatch->AcquireFileForNtCreateSection( FileObject ); 02602 02603 return; 02604 } 02605 02606 // 02607 // If there is a main file resource, acquire that. 02608 // 02609 02610 if ((Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext) && 02611 (Header->Resource != NULL)) { 02612 02613 FsRtlEnterFileSystem(); 02614 ExAcquireResourceExclusive( Header->Resource, TRUE ); 02615 02616 return; 02617 } 02618 02619 // 02620 // Nothing to acquire. 02621 // 02622 02623 return; 02624 } 02625 02626 NTKERNELAPI 02627 VOID 02628 FsRtlReleaseFile ( 02629 IN PFILE_OBJECT FileObject 02630 ) 02631 02632 /*++ 02633 02634 Routine Description: 02635 02636 This routine releases resources acquired by FsRtlAcquireFileExclusive. 02637 02638 Arguments: 02639 02640 FileObject - Pointer to the file object being written. 02641 02642 Return Value: 02643 02644 None. 02645 02646 --*/ 02647 02648 { 02649 PDEVICE_OBJECT DeviceObject; 02650 PFAST_IO_DISPATCH FastIoDispatch; 02651 PFSRTL_COMMON_FCB_HEADER Header; 02652 02653 PAGED_CODE(); 02654 02655 // 02656 // First see if we have to call the file system. 02657 // 02658 02659 DeviceObject = IoGetBaseFileSystemDeviceObject( FileObject ); 02660 02661 if ((FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch) && 02662 (FastIoDispatch->SizeOfFastIoDispatch > 02663 FIELD_OFFSET( FAST_IO_DISPATCH, ReleaseFileForNtCreateSection )) && 02664 (FastIoDispatch->ReleaseFileForNtCreateSection != NULL)) { 02665 02666 FastIoDispatch->ReleaseFileForNtCreateSection( FileObject ); 02667 FsRtlExitFileSystem(); 02668 return; 02669 } 02670 02671 // 02672 // If there is a main file resource, release that. 02673 // 02674 02675 if ((Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext) && 02676 (Header->Resource != NULL)) { 02677 02678 ExReleaseResource( Header->Resource ); 02679 FsRtlExitFileSystem(); 02680 return; 02681 } 02682 02683 // 02684 // Nothing to release. 02685 // 02686 02687 return; 02688 } 02689 02690 NTSTATUS 02691 FsRtlGetFileSize( 02692 IN PFILE_OBJECT FileObject, 02693 IN OUT PLARGE_INTEGER FileSize 02694 ) 02695 02696 /*++ 02697 02698 Routine Description: 02699 02700 This routine is used to call the File System to get the FileSize 02701 for a file. 02702 02703 It does this without acquiring the file object lock on synchronous file 02704 objects. This routine is therefore safe to call if you already own 02705 file system resources, while IoQueryFileInformation could (and does) 02706 lead to deadlocks. 02707 02708 Arguments: 02709 02710 FileObject - The file to query 02711 FileSize - Receives the file size. 02712 02713 Return Value: 02714 02715 NTSTATUS - The final I/O status of the operation. If the FileObject 02716 refers to a directory, STATUS_FILE_IS_A_DIRECTORY is returned. 02717 02718 --*/ 02719 { 02720 IO_STATUS_BLOCK IoStatus; 02721 PDEVICE_OBJECT DeviceObject; 02722 PFAST_IO_DISPATCH FastIoDispatch; 02723 FILE_STANDARD_INFORMATION FileInformation; 02724 02725 PAGED_CODE(); 02726 02727 // 02728 // Get the address of the target device object. 02729 // 02730 02731 DeviceObject = IoGetRelatedDeviceObject( FileObject ); 02732 02733 // 02734 // Try the fast query call if it exists. 02735 // 02736 02737 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 02738 02739 if (FastIoDispatch && 02740 FastIoDispatch->FastIoQueryStandardInfo && 02741 FastIoDispatch->FastIoQueryStandardInfo( FileObject, 02742 TRUE, 02743 &FileInformation, 02744 &IoStatus, 02745 DeviceObject )) { 02746 // 02747 // Cool, it worked. 02748 // 02749 02750 } else { 02751 02752 // 02753 // Life's tough, take the long path. 02754 // 02755 02756 PIRP Irp; 02757 KEVENT Event; 02758 NTSTATUS Status; 02759 PIO_STACK_LOCATION IrpSp; 02760 02761 // 02762 // Initialize the event. 02763 // 02764 02765 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 02766 02767 // 02768 // Allocate an I/O Request Packet (IRP) for this in-page operation. 02769 // 02770 02771 Irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); 02772 if (Irp == NULL) { 02773 02774 return STATUS_INSUFFICIENT_RESOURCES; 02775 } 02776 02777 // 02778 // Get a pointer to the first stack location in the packet. This location 02779 // will be used to pass the function codes and parameters to the first 02780 // driver. 02781 // 02782 02783 IrpSp = IoGetNextIrpStackLocation( Irp ); 02784 02785 // 02786 // Fill in the IRP according to this request, setting the flags to 02787 // just cause IO to set the event and deallocate the Irp. 02788 // 02789 02790 Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO; 02791 Irp->RequestorMode = KernelMode; 02792 Irp->UserIosb = &IoStatus; 02793 Irp->UserEvent = &Event; 02794 Irp->Tail.Overlay.OriginalFileObject = FileObject; 02795 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 02796 Irp->AssociatedIrp.SystemBuffer = &FileInformation; 02797 02798 // 02799 // Fill in the normal query parameters. 02800 // 02801 02802 IrpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION; 02803 IrpSp->FileObject = FileObject; 02804 IrpSp->DeviceObject = DeviceObject; 02805 IrpSp->Parameters.SetFile.Length = sizeof(FILE_STANDARD_INFORMATION); 02806 IrpSp->Parameters.SetFile.FileInformationClass = FileStandardInformation; 02807 02808 // 02809 // Queue the packet to the appropriate driver based. This routine 02810 // should not raise. 02811 // 02812 02813 Status = IoCallDriver( DeviceObject, Irp ); 02814 02815 // 02816 // If pending is returned (which is a successful status), 02817 // we must wait for the request to complete. 02818 // 02819 02820 if (Status == STATUS_PENDING) { 02821 KeWaitForSingleObject( &Event, 02822 Executive, 02823 KernelMode, 02824 FALSE, 02825 (PLARGE_INTEGER)NULL); 02826 } 02827 02828 // 02829 // If we got an error back in Status, then the Iosb 02830 // was not written, so we will just copy the status 02831 // there, then test the final status after that. 02832 // 02833 02834 if (!NT_SUCCESS(Status)) { 02835 IoStatus.Status = Status; 02836 } 02837 } 02838 02839 // 02840 // If the call worked, check to make sure it wasn't a directory and 02841 // if not, fill in the FileSize parameter. 02842 // 02843 02844 if (NT_SUCCESS(IoStatus.Status)) { 02845 02846 if (FileInformation.Directory) { 02847 02848 // 02849 // Can't get file size for a directory. Return error. 02850 // 02851 02852 IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY; 02853 02854 } else { 02855 02856 *FileSize = FileInformation.EndOfFile; 02857 } 02858 } 02859 02860 return IoStatus.Status; 02861 } 02862 02863 NTSTATUS 02864 FsRtlSetFileSize( 02865 IN PFILE_OBJECT FileObject, 02866 IN OUT PLARGE_INTEGER FileSize 02867 ) 02868 02869 /*++ 02870 02871 Routine Description: 02872 02873 This routine is used to call the File System to update FileSize 02874 for a file. 02875 02876 It does this without acquiring the file object lock on synchronous file 02877 objects. This routine is therefore safe to call if you already own 02878 file system resources, while IoSetInformation could (and does) lead 02879 to deadlocks. 02880 02881 Arguments: 02882 02883 FileObject - A pointer to a referenced file object. 02884 02885 ValidDataLength - Pointer to new FileSize. 02886 02887 Return Value: 02888 02889 Status of operation. 02890 02891 --*/ 02892 02893 { 02894 PIO_STACK_LOCATION IrpSp; 02895 PDEVICE_OBJECT DeviceObject; 02896 NTSTATUS Status; 02897 FILE_END_OF_FILE_INFORMATION Buffer; 02898 IO_STATUS_BLOCK IoStatus; 02899 KEVENT Event; 02900 PIRP Irp; 02901 02902 PAGED_CODE(); 02903 02904 // 02905 // Copy FileSize to our buffer. 02906 // 02907 02908 Buffer.EndOfFile = *FileSize; 02909 02910 // 02911 // Initialize the event. 02912 // 02913 02914 KeInitializeEvent( &Event, NotificationEvent, FALSE ); 02915 02916 // 02917 // Begin by getting a pointer to the device object that the file resides 02918 // on. 02919 // 02920 02921 DeviceObject = IoGetRelatedDeviceObject( FileObject ); 02922 02923 // 02924 // Allocate an I/O Request Packet (IRP) for this in-page operation. 02925 // 02926 02927 Irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); 02928 if (Irp == NULL) { 02929 02930 return STATUS_INSUFFICIENT_RESOURCES; 02931 } 02932 02933 // 02934 // Get a pointer to the first stack location in the packet. This location 02935 // will be used to pass the function codes and parameters to the first 02936 // driver. 02937 // 02938 02939 IrpSp = IoGetNextIrpStackLocation( Irp ); 02940 02941 // 02942 // Fill in the IRP according to this request, setting the flags to 02943 // just cause IO to set the event and deallocate the Irp. 02944 // 02945 02946 Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO; 02947 Irp->RequestorMode = KernelMode; 02948 Irp->UserIosb = &IoStatus; 02949 Irp->UserEvent = &Event; 02950 Irp->Tail.Overlay.OriginalFileObject = FileObject; 02951 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 02952 Irp->AssociatedIrp.SystemBuffer = &Buffer; 02953 02954 // 02955 // Fill in the normal set file parameters. 02956 // 02957 02958 IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION; 02959 IrpSp->FileObject = FileObject; 02960 IrpSp->DeviceObject = DeviceObject; 02961 IrpSp->Parameters.SetFile.Length = sizeof(FILE_END_OF_FILE_INFORMATION); 02962 IrpSp->Parameters.SetFile.FileInformationClass = FileEndOfFileInformation; 02963 02964 // 02965 // Queue the packet to the appropriate driver based on whether or not there 02966 // is a VPB associated with the device. This routine should not raise. 02967 // 02968 02969 Status = IoCallDriver( DeviceObject, Irp ); 02970 02971 // 02972 // If pending is returned (which is a successful status), 02973 // we must wait for the request to complete. 02974 // 02975 02976 if (Status == STATUS_PENDING) { 02977 KeWaitForSingleObject( &Event, 02978 Executive, 02979 KernelMode, 02980 FALSE, 02981 (PLARGE_INTEGER)NULL); 02982 } 02983 02984 // 02985 // If we got an error back in Status, then the Iosb 02986 // was not written, so we will just copy the status 02987 // there, then test the final status after that. 02988 // 02989 02990 if (!NT_SUCCESS(Status)) { 02991 IoStatus.Status = Status; 02992 } 02993 02994 return IoStatus.Status; 02995 }

Generated on Sat May 15 19:39:58 2004 for test by doxygen 1.3.7