Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1373 lines
42 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Read.c
  5. Abstract:
  6. This module implements the File Read routine for Read called by the
  7. dispatch driver.
  8. Author:
  9. Joe Linn [JoeLinn] 11-Oct-1994
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // The local debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_READ)
  18. //
  19. // The following procedures are the handle the procedureal interface with lowio.
  20. //
  21. NTSTATUS
  22. RxLowIoReadShell (
  23. IN PRX_CONTEXT RxContext,
  24. IN PIRP Irp,
  25. IN PFCB Fcb
  26. );
  27. NTSTATUS
  28. RxLowIoReadShellCompletion (
  29. IN PRX_CONTEXT RxContext
  30. );
  31. #if DBG
  32. VOID CheckForLoudOperations (
  33. IN PRX_CONTEXT RxContext,
  34. IN PFCB Fcb
  35. );
  36. #else
  37. #define CheckForLoudOperations(___r)
  38. #endif
  39. //
  40. // This macro just puts a nice little try-except around RtlZeroMemory
  41. //
  42. #define SafeZeroMemory(AT,BYTE_COUNT) { \
  43. try { \
  44. RtlZeroMemory((AT), (BYTE_COUNT)); \
  45. } except(EXCEPTION_EXECUTE_HANDLER) { \
  46. RxRaiseStatus( RxContext, STATUS_INVALID_USER_BUFFER ); \
  47. } \
  48. }
  49. #ifdef ALLOC_PRAGMA
  50. #pragma alloc_text(PAGE, RxStackOverflowRead)
  51. #pragma alloc_text(PAGE, RxPostStackOverflowRead)
  52. #pragma alloc_text(PAGE, RxCommonRead)
  53. #pragma alloc_text(PAGE, RxLowIoReadShellCompletion)
  54. #pragma alloc_text(PAGE, RxLowIoReadShell)
  55. #if DBG
  56. #pragma alloc_text(PAGE, CheckForLoudOperations)
  57. #endif //DBG
  58. #endif
  59. //
  60. // Internal support routine
  61. //
  62. NTSTATUS
  63. RxPostStackOverflowRead (
  64. IN PRX_CONTEXT RxContext,
  65. IN PFCB Fcb
  66. )
  67. /*++
  68. Routine Description:
  69. This routine posts a read request that could not be processed by
  70. the fsp thread because of stack overflow potential.
  71. Arguments:
  72. RxContext - the usual
  73. Return Value:
  74. RxStatus(PENDING).
  75. --*/
  76. {
  77. PIRP Irp = RxContext->CurrentIrp;
  78. KEVENT Event;
  79. PERESOURCE Resource;
  80. PAGED_CODE();
  81. RxDbgTrace( 0, Dbg, ("Getting too close to stack limit pass request to Fsp\n", 0 ) );
  82. //
  83. // Initialize the event
  84. //
  85. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  86. if (FlagOn( Irp->Flags, IRP_PAGING_IO ) && (Fcb->Header.PagingIoResource != NULL)) {
  87. Resource = Fcb->Header.PagingIoResource;
  88. } else {
  89. Resource = Fcb->Header.Resource;
  90. }
  91. ExAcquireResourceSharedLite( Resource, TRUE );
  92. try {
  93. //
  94. // Make the Irp just like a regular post request and
  95. // then send the Irp to the special overflow thread.
  96. // After the post we will wait for the stack overflow
  97. // read routine to set the event so that we can
  98. // then release the fcb resource and return.
  99. //
  100. RxPrePostIrp( RxContext, Irp );
  101. FsRtlPostStackOverflow( RxContext, &Event, RxStackOverflowRead );
  102. //
  103. // And wait for the worker thread to complete the item
  104. //
  105. (VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
  106. } finally {
  107. ExReleaseResourceLite( Resource );
  108. }
  109. return STATUS_PENDING;
  110. }
  111. //
  112. // Internal support routine
  113. //
  114. VOID
  115. RxStackOverflowRead (
  116. IN PVOID Context,
  117. IN PKEVENT Event
  118. )
  119. /*++
  120. Routine Description:
  121. This routine processes a read request that could not be processed by
  122. the fsp thread because of stack overflow potential.
  123. Arguments:
  124. Context - the RxContext being processed
  125. Event - the event to be signaled when we've finished this request.
  126. Return Value:
  127. None.
  128. --*/
  129. {
  130. PRX_CONTEXT RxContext = Context;
  131. PIRP Irp = RxContext->CurrentIrp;
  132. PAGED_CODE();
  133. //
  134. // Make it now look like we can wait for I/O to complete
  135. //
  136. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  137. //
  138. // Do the read operation protected by a try-except clause
  139. //
  140. try {
  141. (VOID) RxCommonRead( RxContext, Irp );
  142. } except(RxExceptionFilter( RxContext, GetExceptionInformation() )) {
  143. NTSTATUS ExceptionCode;
  144. //
  145. // We had some trouble trying to perform the requested
  146. // operation, so we'll abort the I/O request with the
  147. // error status that we get back from the execption code
  148. ExceptionCode = GetExceptionCode();
  149. if (ExceptionCode == STATUS_FILE_DELETED) {
  150. RxContext->StoredStatus = ExceptionCode = STATUS_END_OF_FILE;
  151. Irp->IoStatus.Information = 0;
  152. }
  153. (VOID) RxProcessException( RxContext, ExceptionCode );
  154. }
  155. //
  156. // Signal the original thread that we're done.
  157. KeSetEvent( Event, 0, FALSE );
  158. }
  159. NTSTATUS
  160. RxCommonRead (
  161. IN PRX_CONTEXT RxContext,
  162. IN PIRP Irp
  163. )
  164. /*++
  165. Routine Description:
  166. This is the common read routine for NtReadFile, called from both
  167. the Fsd, or from the Fsp if a request could not be completed without
  168. blocking in the Fsd. This routine has no code where it determines
  169. whether it is running in the Fsd or Fsp. Instead, its actions are
  170. conditionalized by the Wait input parameter, which determines whether
  171. it is allowed to block or not. If a blocking condition is encountered
  172. with Wait == FALSE, however, the request is posted to the Fsp, who
  173. always calls with WAIT == TRUE.
  174. Arguments:
  175. Irp - Supplies the Irp to process
  176. Return Value:
  177. RXSTATUS - The return status for the operation
  178. --*/
  179. {
  180. NTSTATUS Status;
  181. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  182. PFILE_OBJECT FileObject = IrpSp->FileObject;
  183. PFCB Fcb;
  184. PFOBX Fobx;
  185. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  186. NODE_TYPE_CODE TypeOfOpen;
  187. LARGE_INTEGER StartingByte;
  188. RXVBO StartingVbo;
  189. ULONG ByteCount;
  190. ULONG CapturedRxContextSerialNumber = RxContext->SerialNumber;
  191. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  192. BOOLEAN PostIrp = FALSE;
  193. BOOLEAN FcbAcquired = FALSE;
  194. BOOLEAN RefdContextForTracker = FALSE;
  195. BOOLEAN Wait;
  196. BOOLEAN PagingIo;
  197. BOOLEAN NonCachedIo;
  198. BOOLEAN SynchronousIo;
  199. PNET_ROOT NetRoot;
  200. BOOLEAN PipeRead;
  201. BOOLEAN BlockingResume = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME );
  202. BOOLEAN fSetResourceOwner = FALSE;
  203. BOOLEAN InFsp = FALSE;
  204. PAGED_CODE();
  205. TypeOfOpen = RxDecodeFileObject( FileObject, &Fcb, &Fobx );
  206. NetRoot = (PNET_ROOT)Fcb->NetRoot;
  207. //
  208. // Initialize the local decision variables.
  209. //
  210. PipeRead = (BOOLEAN)(NetRoot->Type == NET_ROOT_PIPE);
  211. Wait = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  212. PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
  213. NonCachedIo = BooleanFlagOn( Irp->Flags,IRP_NOCACHE );
  214. SynchronousIo = !BooleanFlagOn( RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION );
  215. InFsp = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP );
  216. RxDbgTrace( +1, Dbg, ("RxCommonRead...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
  217. RxContext, Fobx, Fcb ));
  218. RxDbgTrace( 0, Dbg, (" ->ByteCount = %08lx, ByteOffset = %08lx %lx\n",
  219. IrpSp->Parameters.Read.Length,
  220. IrpSp->Parameters.Read.ByteOffset.LowPart,
  221. IrpSp->Parameters.Read.ByteOffset.HighPart) );
  222. RxDbgTrace( 0, Dbg,(" ->%s%s%s%s\n",
  223. Wait ?"Wait ":"",
  224. PagingIo ?"PagingIo ":"",
  225. NonCachedIo ?"NonCachedIo ":"",
  226. SynchronousIo ?"SynchronousIo ":"") );
  227. RxLog(( "CommonRead %lx %lx %lx\n", RxContext, Fobx, Fcb ));
  228. RxWmiLog( LOG,
  229. RxCommonRead_1,
  230. LOGPTR( RxContext )
  231. LOGPTR( Fobx )
  232. LOGPTR( Fcb ) );
  233. RxLog(( " read %lx@%lx %lx %s%s%s%s\n",
  234. IrpSp->Parameters.Read.Length,
  235. IrpSp->Parameters.Read.ByteOffset.LowPart,
  236. IrpSp->Parameters.Read.ByteOffset.HighPart,
  237. Wait?"Wt":"",
  238. PagingIo?"Pg":"",
  239. NonCachedIo?"Nc":"",
  240. SynchronousIo?"Sync":"" ));
  241. RxWmiLog( LOG,
  242. RxCommonRead_2,
  243. LOGULONG( IrpSp->Parameters.Read.Length )
  244. LOGULONG( IrpSp->Parameters.Read.ByteOffset.LowPart )
  245. LOGULONG( IrpSp->Parameters.Read.ByteOffset.HighPart )
  246. LOGUCHAR( Wait )
  247. LOGUCHAR( PagingIo )
  248. LOGUCHAR( NonCachedIo )
  249. LOGUCHAR( SynchronousIo ) );
  250. RxItsTheSameContext();
  251. Irp->IoStatus.Information = 0;
  252. //
  253. // Extract starting Vbo and offset.
  254. //
  255. StartingByte = IrpSp->Parameters.Read.ByteOffset;
  256. StartingVbo = StartingByte.QuadPart;
  257. ByteCount = IrpSp->Parameters.Read.Length;
  258. #if DBG
  259. CheckForLoudOperations( RxContext, Fcb );
  260. if (FlagOn( LowIoContext->Flags,LOWIO_CONTEXT_FLAG_LOUDOPS )){
  261. DbgPrint( "LoudRead %lx/%lx on %lx vdl/size/alloc %lx/%lx/%lx\n",
  262. StartingByte.LowPart,ByteCount,Fcb,
  263. Fcb->Header.ValidDataLength.LowPart,
  264. Fcb->Header.FileSize.LowPart,
  265. Fcb->Header.AllocationSize.LowPart );
  266. }
  267. #endif
  268. //
  269. // Statistics............
  270. //
  271. if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP ) &&
  272. (Fcb->CachedNetRootType == NET_ROOT_DISK)) {
  273. InterlockedIncrement( &RxDeviceObject->ReadOperations );
  274. if (StartingVbo != Fobx->Specific.DiskFile.PredictedReadOffset) {
  275. InterlockedIncrement( &RxDeviceObject->RandomReadOperations );
  276. }
  277. Fobx->Specific.DiskFile.PredictedReadOffset = StartingVbo + ByteCount;
  278. if (PagingIo) {
  279. ExInterlockedAddLargeStatistic( &RxDeviceObject->PagingReadBytesRequested, ByteCount );
  280. } else if (NonCachedIo) {
  281. ExInterlockedAddLargeStatistic( &RxDeviceObject->NonPagingReadBytesRequested, ByteCount );
  282. } else {
  283. ExInterlockedAddLargeStatistic( &RxDeviceObject->CacheReadBytesRequested, ByteCount );
  284. }
  285. }
  286. //
  287. // Check for a null, invalid request, and return immediately
  288. //
  289. if (PipeRead && PagingIo) {
  290. return STATUS_INVALID_DEVICE_REQUEST;
  291. }
  292. if (ByteCount == 0) {
  293. return STATUS_SUCCESS;
  294. }
  295. //
  296. // Get rid of invalid read requests right now.
  297. //
  298. if ((TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) &&
  299. (TypeOfOpen != RDBSS_NTC_VOLUME_FCB)) {
  300. RxDbgTrace( 0, Dbg, ("Invalid file object for read, type=%08lx\n", TypeOfOpen ));
  301. RxDbgTrace( -1, Dbg, ("RxCommonRead: Exit -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST ));
  302. return STATUS_INVALID_DEVICE_REQUEST;
  303. }
  304. //
  305. // Initialize LowIO_CONTEXT block in the RxContext
  306. //
  307. RxInitializeLowIoContext( RxContext, LOWIO_OP_READ, LowIoContext );
  308. //
  309. // Use a try-finally to release Fcb and free buffers on the way out.
  310. //
  311. try {
  312. //
  313. // This case corresponds to a normal user read file.
  314. //
  315. LONGLONG FileSize;
  316. LONGLONG ValidDataLength;
  317. RxDbgTrace( 0, Dbg, ("Type of read is user file open, fcbstate is %08lx\n", Fcb->FcbState ));
  318. //
  319. // for stackoverflowreads, we will already have the pagingio resource shared as it's
  320. // paging io. this doesn't cause a problem here....the resource is just acquired twice.
  321. //
  322. if ((NonCachedIo || !FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED )) &&
  323. !PagingIo &&
  324. (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
  325. //
  326. // We hold the main resource exclusive here because the flush
  327. // may generate a recursive write in this thread
  328. //
  329. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  330. if (Status == STATUS_LOCK_NOT_GRANTED) {
  331. RxDbgTrace( 0,Dbg,("Cannot acquire Fcb for flush = %08lx excl without waiting - lock not granted\n",Fcb) );
  332. try_return( PostIrp = TRUE );
  333. } else if (Status != STATUS_SUCCESS) {
  334. RxDbgTrace( 0,Dbg,("Cannot acquire Fcb = %08lx shared without waiting - other\n",Fcb) );
  335. try_return( PostIrp = FALSE );
  336. }
  337. ExAcquireResourceSharedLite( Fcb->Header.PagingIoResource, TRUE );
  338. CcFlushCache( FileObject->SectionObjectPointer,
  339. &StartingByte,
  340. ByteCount,
  341. &Irp->IoStatus );
  342. RxReleasePagingIoResource( RxContext, Fcb );
  343. RxReleaseFcb( RxContext, Fcb );
  344. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  345. Status = Irp->IoStatus.Status;
  346. try_return( Irp->IoStatus.Status );
  347. }
  348. RxAcquirePagingIoResource( RxContext, Fcb );
  349. RxReleasePagingIoResource( RxContext, Fcb );
  350. }
  351. //
  352. // We need shared access to the Fcb before proceeding.
  353. //
  354. if (PagingIo) {
  355. ASSERT( !PipeRead );
  356. if (!ExAcquireResourceSharedLite( Fcb->Header.PagingIoResource, Wait )) {
  357. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb) );
  358. try_return( PostIrp = TRUE );
  359. }
  360. if (!Wait) {
  361. LowIoContext->Resource = Fcb->Header.PagingIoResource;
  362. }
  363. } else if (!BlockingResume) {
  364. //
  365. // If this is unbuffered async I/O we need to check that
  366. // we don't exhaust the number of times a single thread can
  367. // acquire the resource. Also, we will wait if there is an
  368. // exclusive waiter.
  369. //
  370. if (!Wait && NonCachedIo) {
  371. Status = RxAcquireSharedFcbWaitForEx( RxContext, Fcb );
  372. if (Status == STATUS_LOCK_NOT_GRANTED) {
  373. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - lock not granted\n", Fcb) );
  374. RxLog(( "RdAsyLNG %x\n", RxContext ));
  375. RxWmiLog( LOG,
  376. RxCommonRead_3,
  377. LOGPTR( RxContext ) );
  378. try_return( PostIrp = TRUE );
  379. } else if (Status != STATUS_SUCCESS) {
  380. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - other\n", Fcb) );
  381. RxLog(( "RdAsyOthr %x\n", RxContext ));
  382. RxWmiLog( LOG,
  383. RxCommonRead_4,
  384. LOGPTR( RxContext ) );
  385. try_return( PostIrp = FALSE );
  386. }
  387. if (ExIsResourceAcquiredSharedLite( Fcb->Header.Resource ) > MAX_FCB_ASYNC_ACQUIRE) {
  388. FcbAcquired = TRUE;
  389. try_return( PostIrp = TRUE );
  390. }
  391. LowIoContext->Resource = Fcb->Header.Resource;
  392. } else {
  393. Status = RxAcquireSharedFcb( RxContext, Fcb );
  394. if (Status == STATUS_LOCK_NOT_GRANTED) {
  395. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - lock not granted\n", Fcb) );
  396. try_return( PostIrp = TRUE );
  397. } else if (Status != STATUS_SUCCESS) {
  398. RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - other\n", Fcb) );
  399. try_return( PostIrp = FALSE );
  400. }
  401. }
  402. }
  403. RxItsTheSameContext();
  404. FcbAcquired = !BlockingResume;
  405. //
  406. // for pipe reads, bail out now. we avoid a goto by duplicating the calldown
  407. //
  408. if (PipeRead) {
  409. //
  410. // In order to prevent corruption on multi-threaded multi-block
  411. // message mode pipe reads, we do this little dance with the fcb resource
  412. //
  413. if (!BlockingResume) {
  414. if ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_MESSAGE_TYPE) ||
  415. ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_BYTE_STREAM_TYPE) &&
  416. !FlagOn( Fobx->Specific.NamedPipe.CompletionMode, FILE_PIPE_COMPLETE_OPERATION))) {
  417. //
  418. // Synchronization is effected here that will prevent other
  419. // threads from coming in and reading from this file while the
  420. // message pipe read is continuing.
  421. //
  422. // This is necessary because we will release the FCB lock while
  423. // actually performing the I/O to allow open (and other) requests
  424. // to continue on this file while the I/O is in progress.
  425. //
  426. RxDbgTrace( 0, Dbg, ("Message pipe read: Fobx: %lx, Fcb: %lx, Enqueuing...\n", Fobx, Fcb) );
  427. Status = RxSynchronizeBlockingOperationsAndDropFcbLock( RxContext,
  428. Fcb,
  429. &Fobx->Specific.NamedPipe.ReadSerializationQueue );
  430. RxItsTheSameContext();
  431. FcbAcquired = FALSE;
  432. if (!NT_SUCCESS( Status ) ||
  433. (Status == STATUS_PENDING)) {
  434. try_return( Status );
  435. }
  436. RxDbgTrace( 0, Dbg, ("Succeeded: Fobx: %lx\n", Fobx) );
  437. }
  438. }
  439. LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
  440. LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
  441. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION );
  442. //
  443. // Set the resource owner pointers (there is no PagingIoResource here !)
  444. // if we are in FSP so that even if the FSP thread goes away, we dont run
  445. // into issues with the resource package trying to boost the thread priority.
  446. //
  447. if( InFsp && FcbAcquired ) {
  448. LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
  449. ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId);
  450. fSetResourceOwner = TRUE;
  451. }
  452. Status = RxLowIoReadShell( RxContext, Irp, Fcb );
  453. try_return( Status );
  454. }
  455. RxGetFileSizeWithLock( Fcb, &FileSize );
  456. ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
  457. //
  458. // We set the fastio state state to questionable
  459. // at initialization time and answer the question in realtime
  460. // this should be a policy so that local minis can do it this way
  461. //
  462. //
  463. // We have to check for read access according to the current
  464. // state of the file locks, and set FileSize from the Fcb.
  465. //
  466. if (!PagingIo &&
  467. !FsRtlCheckLockForReadAccess( &Fcb->FileLock, Irp )) {
  468. try_return( Status = STATUS_FILE_LOCK_CONFLICT );
  469. }
  470. //
  471. // adjust the length if we know the eof...also, don't issue reads past the EOF
  472. // if we know the eof
  473. //
  474. if (FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED )) {
  475. //
  476. // If the read starts beyond End of File, return EOF.
  477. //
  478. if (StartingVbo >= FileSize) {
  479. RxDbgTrace( 0, Dbg, ("End of File\n", 0 ) );
  480. try_return ( Status = STATUS_END_OF_FILE );
  481. }
  482. //
  483. // If the read extends beyond EOF, truncate the read
  484. //
  485. if (ByteCount > FileSize - StartingVbo) {
  486. ByteCount = (ULONG)(FileSize - StartingVbo);
  487. }
  488. }
  489. if (!PagingIo &&
  490. !NonCachedIo && // this part is not discretionary
  491. FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED ) &&
  492. !FlagOn( Fobx->SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING )) {
  493. //
  494. // HANDLE CACHED CASE
  495. //
  496. // We delay setting up the file cache until now, in case the
  497. // caller never does any I/O to the file, and thus
  498. // FileObject->PrivateCacheMap == NULL.
  499. //
  500. if (FileObject->PrivateCacheMap == NULL) {
  501. RxDbgTrace( 0, Dbg, ("Initialize cache mapping.\n", 0) );
  502. //
  503. // If this FileObject has gone through CleanUp, we cannot
  504. // CcInitializeCacheMap it.
  505. //
  506. if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
  507. Status = STATUS_FILE_CLOSED;
  508. try_return( Status );
  509. }
  510. RxAdjustAllocationSizeforCC( Fcb );
  511. //
  512. // Now initialize the cache map.
  513. //
  514. try {
  515. Status = STATUS_SUCCESS;
  516. CcInitializeCacheMap( FileObject,
  517. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
  518. FALSE,
  519. &RxData.CacheManagerCallbacks,
  520. Fcb );
  521. } except( EXCEPTION_EXECUTE_HANDLER ) {
  522. Status = GetExceptionCode();
  523. }
  524. if (Status != STATUS_SUCCESS) {
  525. try_return( Status );
  526. }
  527. if (!FlagOn( Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD )) {
  528. //
  529. // Start out with read ahead disabled
  530. //
  531. CcSetAdditionalCacheAttributes( FileObject, TRUE, FALSE );
  532. SetFlag( Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED );
  533. } else {
  534. //
  535. // this mini doesn't want deferred readahead
  536. //
  537. CcSetAdditionalCacheAttributes( FileObject, FALSE, FALSE );
  538. }
  539. CcSetReadAheadGranularity( FileObject, NetRoot->DiskParameters.ReadAheadGranularity );
  540. } else {
  541. //
  542. // if we have wandered off the first page and haven't started reading ahead
  543. // then start now
  544. //
  545. if (FlagOn( Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED ) &&
  546. (StartingVbo >= PAGE_SIZE)) {
  547. CcSetAdditionalCacheAttributes( FileObject, FALSE, FALSE );
  548. ClearFlag( Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED );
  549. }
  550. }
  551. //
  552. // DO A NORMAL CACHED READ, if the MDL bit is not set,
  553. //
  554. RxDbgTrace( 0, Dbg, ("Cached read.\n", 0) );
  555. if (!FlagOn( RxContext->MinorFunction, IRP_MN_MDL )) {
  556. PVOID SystemBuffer;
  557. #if DBG
  558. ULONG SaveExceptionFlag;
  559. #endif
  560. //
  561. // Get hold of the user's buffer.
  562. //
  563. SystemBuffer = RxMapUserBuffer( RxContext, Irp );
  564. if (SystemBuffer == NULL) {
  565. Status = STATUS_INSUFFICIENT_RESOURCES;
  566. try_return( Status );
  567. }
  568. //
  569. // Make sure that a returned exception clears the breakpoint in the filter
  570. //
  571. RxSaveAndSetExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
  572. RxItsTheSameContext();
  573. //
  574. // Now try to do the copy.
  575. //
  576. if (!CcCopyRead( FileObject,
  577. &StartingByte,
  578. ByteCount,
  579. Wait,
  580. SystemBuffer,
  581. &Irp->IoStatus )) {
  582. RxDbgTrace( 0, Dbg, ("Cached Read could not wait\n", 0 ) );
  583. RxRestoreExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
  584. RxItsTheSameContext();
  585. try_return( PostIrp = TRUE );
  586. }
  587. Status = Irp->IoStatus.Status;
  588. RxRestoreExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
  589. RxItsTheSameContext();
  590. ASSERT( NT_SUCCESS( Status ));
  591. try_return( Status );
  592. } else {
  593. //
  594. // HANDLE A MDL READ
  595. //
  596. RxDbgTrace(0, Dbg, ("MDL read.\n", 0));
  597. ASSERT( FALSE ); // not yet ready for MDL reads
  598. ASSERT( Wait );
  599. CcMdlRead( FileObject,
  600. &StartingByte,
  601. ByteCount,
  602. &Irp->MdlAddress,
  603. &Irp->IoStatus );
  604. Status = Irp->IoStatus.Status;
  605. ASSERT( NT_SUCCESS( Status ));
  606. try_return( Status );
  607. }
  608. }
  609. //
  610. // HANDLE THE NON-CACHED CASE
  611. //
  612. // Bt first, a ValidDataLength check.
  613. //
  614. // If the file in question is a disk file, and it is currently cached,
  615. // and the read offset is greater than valid data length, then
  616. // return 0s to the application.
  617. //
  618. if ((Fcb->CachedNetRootType == NET_ROOT_DISK) &&
  619. FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED ) &&
  620. (StartingVbo >= ValidDataLength)) {
  621. //
  622. // check if zeroing is really needed.
  623. //
  624. if (StartingVbo >= FileSize) {
  625. ByteCount = 0;
  626. } else {
  627. PBYTE SystemBuffer;
  628. //
  629. // There is at least one byte available. Truncate
  630. // the transfer length if it goes beyond EOF.
  631. //
  632. if (StartingVbo + ByteCount > FileSize) {
  633. ByteCount = (ULONG)(FileSize - StartingVbo);
  634. }
  635. SystemBuffer = RxMapUserBuffer( RxContext, Irp );
  636. SafeZeroMemory( SystemBuffer, ByteCount ); // this could raise!!
  637. }
  638. Irp->IoStatus.Information = ByteCount;
  639. try_return( Status = STATUS_SUCCESS );
  640. }
  641. LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
  642. LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
  643. RxItsTheSameContext();
  644. //
  645. // Set the resource owner pointers.
  646. // if we are in FSP so that even if the FSP thread goes away, we dont run
  647. // into issues with the resource package trying to boost the thread priority.
  648. //
  649. if ( InFsp && FcbAcquired ) {
  650. LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
  651. if ( PagingIo ) {
  652. ExSetResourceOwnerPointer( Fcb->Header.PagingIoResource, (PVOID)LowIoContext->ResourceThreadId );
  653. } else {
  654. ExSetResourceOwnerPointer( Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId );
  655. }
  656. fSetResourceOwner = TRUE;
  657. }
  658. Status = RxLowIoReadShell( RxContext, Irp, Fcb );
  659. RxItsTheSameContext();
  660. try_return( Status );
  661. try_exit: NOTHING;
  662. //
  663. // If the request was not posted, deal with it.
  664. //
  665. RxItsTheSameContext();
  666. if (!PostIrp) {
  667. if (!PipeRead) {
  668. RxDbgTrace( 0, Dbg, ("CommonRead InnerFinally-> %08lx %08lx\n",
  669. Status, Irp->IoStatus.Information) );
  670. //
  671. // If the file was opened for Synchronous IO, update the current
  672. // file position. this works becuase info==0 for errors
  673. //
  674. if (!PagingIo &&
  675. FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO )) {
  676. FileObject->CurrentByteOffset.QuadPart =
  677. StartingVbo + Irp->IoStatus.Information;
  678. }
  679. }
  680. } else {
  681. RxDbgTrace( 0, Dbg, ("Passing request to Fsp\n", 0 ));
  682. InterlockedIncrement( &RxContext->ReferenceCount );
  683. RefdContextForTracker = TRUE;
  684. Status = RxFsdPostRequest( RxContext );
  685. }
  686. } finally {
  687. DebugUnwind( RxCommonRead );
  688. //
  689. // If this was not PagingIo, mark that the last access
  690. // time on the dirent needs to be updated on close.
  691. //
  692. if (NT_SUCCESS( Status ) && (Status != STATUS_PENDING) && !PagingIo && !PipeRead) {
  693. SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
  694. }
  695. //
  696. // If resources have been acquired, release them under the right conditions.
  697. // the right conditions are these:
  698. // 1) if we have abnormal termination. here we obviously release the since no one else will.
  699. // 2) if the underlying call did not succeed: Status==Pending.
  700. // 3) if we posted the request
  701. //
  702. // Completion for this case is not handled in the common dispatch routine
  703. //
  704. if (AbnormalTermination() || (Status != STATUS_PENDING) || PostIrp) {
  705. if (FcbAcquired) {
  706. if ( PagingIo ) {
  707. if( fSetResourceOwner ) {
  708. RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
  709. } else {
  710. RxReleasePagingIoResource( RxContext, Fcb );
  711. }
  712. } else {
  713. if( fSetResourceOwner ) {
  714. RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
  715. } else {
  716. RxReleaseFcb( RxContext, Fcb );
  717. }
  718. }
  719. }
  720. if (RefdContextForTracker) {
  721. RxDereferenceAndDeleteRxContext( RxContext );
  722. }
  723. if (!PostIrp) {
  724. if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION )) {
  725. RxResumeBlockedOperations_Serially( RxContext,
  726. &Fobx->Specific.NamedPipe.ReadSerializationQueue );
  727. }
  728. }
  729. if (Status == STATUS_SUCCESS) {
  730. ASSERT( Irp->IoStatus.Information <= IrpSp->Parameters.Read.Length );
  731. }
  732. } else {
  733. //
  734. // here the guy below is going to handle the completion....but, we don't know the finish
  735. // order....in all likelihood the deletecontext call below just reduces the refcount
  736. // but the guy may already have finished in which case this will really delete the context.
  737. //
  738. ASSERT( !SynchronousIo );
  739. RxDereferenceAndDeleteRxContext( RxContext );
  740. }
  741. RxDbgTrace( -1, Dbg, ("CommonRead -> %08lx\n", Status) );
  742. } // finally
  743. IF_DEBUG {
  744. if ((Status == STATUS_END_OF_FILE) &&
  745. FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS )){
  746. DbgPrint( "Returning end of file on %wZ\n", &(Fcb->PrivateAlreadyPrefixedName) );
  747. }
  748. }
  749. return Status;
  750. }
  751. NTSTATUS
  752. RxLowIoReadShellCompletion (
  753. IN PRX_CONTEXT RxContext
  754. )
  755. /*++
  756. Routine Description:
  757. This routine postprocesses a read request after it comes back from the
  758. minirdr. It does callouts to handle compression, buffering and
  759. shadowing. It is the opposite number of LowIoReadShell.
  760. This will be called from LowIo; for async, originally in the
  761. completion routine. If RxStatus(MORE_PROCESSING_REQUIRED) is returned,
  762. LowIo will call again in a thread. If this was syncIo, you'll be back
  763. in the user's thread; if async, lowIo will requeue to a thread.
  764. Currrently, we always get to a thread before anything; this is a bit slower
  765. than completing at DPC time,
  766. but it's aheckuva lot safer and we may often have stuff to do
  767. (like decompressing, shadowing, etc) that we don't want to do at DPC
  768. time.
  769. Arguments:
  770. RxContext - the usual
  771. Return Value:
  772. whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
  773. --*/
  774. {
  775. NTSTATUS Status;
  776. PIRP Irp = RxContext->CurrentIrp;
  777. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  778. PFILE_OBJECT FileObject = IrpSp->FileObject;
  779. PFCB Fcb;
  780. PFOBX Fobx;
  781. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  782. BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  783. BOOLEAN PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
  784. BOOLEAN PipeOperation = BooleanFlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION );
  785. BOOLEAN SynchronousPipe = BooleanFlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
  786. //
  787. // we will want to revisit this....not taking this at dpc time would cause
  788. // two extra context swaps IF MINIRDRS MADE THE CALL FROM THE INDICATION
  789. // CRRRENTLY, THEY DO NOT.
  790. //
  791. PAGED_CODE();
  792. RxDecodeFileObject( FileObject, &Fcb, &Fobx );
  793. Status = RxContext->StoredStatus;
  794. Irp->IoStatus.Information = RxContext->InformationToReturn;
  795. RxDbgTrace( +1, Dbg, ("RxLowIoReadShellCompletion entry Status = %08lx\n", Status) );
  796. RxLog(( "RdShlComp %lx %lx %lx\n", RxContext, Status, Irp->IoStatus.Information ));
  797. RxWmiLog( LOG,
  798. RxLowIoReadShellCompletion_1,
  799. LOGPTR( RxContext )
  800. LOGULONG( Status )
  801. LOGPTR( Irp->IoStatus.Information ) );
  802. if (PagingIo) {
  803. //
  804. // for paging io, it's nonsense to have 0bytes and success...map it!
  805. //
  806. if (NT_SUCCESS(Status) &&
  807. (Irp->IoStatus.Information == 0)) {
  808. Status = STATUS_END_OF_FILE;
  809. }
  810. }
  811. ASSERT( RxLowIoIsBufferLocked( LowIoContext ) );
  812. switch (Status) {
  813. case STATUS_SUCCESS:
  814. if(FlagOn( RxContext->Flags, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED )){
  815. if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED )){
  816. ASSERT( FALSE ); // NOT YET IMPLEMENTED should decompress and put away
  817. } else if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED )){
  818. ASSERT( FALSE ); // NOT YET IMPLEMENTED should decompress and put away
  819. }
  820. }
  821. break;
  822. case STATUS_FILE_LOCK_CONFLICT:
  823. if(FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED )){
  824. ASSERT( FALSE ); // disenlarge the read
  825. return STATUS_RETRY;
  826. }
  827. break;
  828. case STATUS_CONNECTION_INVALID:
  829. //
  830. // NOT YET IMPLEMENTED here is where the failover will happen
  831. // first we give the local guy current minirdr another chance...then we go
  832. // to fullscale retry
  833. // return(RxStatus(DISCONNECTED)); //special....let LowIo get us back
  834. //
  835. break;
  836. }
  837. if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD )) {
  838. ASSERT( FALSE ); // RxUnwaitReadAheadWaiters(RxContext);
  839. }
  840. if (FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL )){
  841. //
  842. // if we're being called from lowioubmit then just get out
  843. //
  844. RxDbgTrace(-1, Dbg, ("RxLowIoReadShellCompletion syncexit Status = %08lx\n", Status));
  845. return Status;
  846. }
  847. //
  848. // otherwise we have to do the end of the read from here
  849. //
  850. //
  851. // mark that the file has been read accessed
  852. //
  853. if (NT_SUCCESS( Status ) && !PagingIo && !PipeOperation) {
  854. SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
  855. }
  856. if ( PagingIo ) {
  857. RxReleasePagingIoResourceForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  858. } else if (!SynchronousPipe) {
  859. RxReleaseFcbForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  860. } else {
  861. RxResumeBlockedOperations_Serially( RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue );
  862. }
  863. if (PipeOperation) {
  864. if (Irp->IoStatus.Information == 0) {
  865. //
  866. // if this is a nowait pipe, initiate throttling to keep from flooding the net
  867. //
  868. if (Fobx->Specific.NamedPipe.CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
  869. RxInitiateOrContinueThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
  870. RxLog(( "RThrottlYes %lx %lx %lx %ld\n",
  871. RxContext,Fobx,&Fobx->Specific.NamedPipe.ThrottlingState,
  872. Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
  873. RxWmiLog( LOG,
  874. RxLowIoReadShellCompletion_2,
  875. LOGPTR( RxContext )
  876. LOGPTR( Fobx )
  877. LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
  878. }
  879. //
  880. // translate the status if this is a msgmode pipe
  881. //
  882. if ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_MESSAGE_TYPE) &&
  883. (Status == STATUS_SUCCESS)) {
  884. Status = STATUS_PIPE_EMPTY;
  885. }
  886. } else {
  887. //
  888. // if we have been throttling on this pipe, stop because we got some data.....
  889. //
  890. RxTerminateThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
  891. RxLog(( "RThrottlNo %lx %lx %lx %ld\n",
  892. RxContext, Fobx, &Fobx->Specific.NamedPipe.ThrottlingState,
  893. Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
  894. RxWmiLog( LOG,
  895. RxLowIoReadShellCompletion_3,
  896. LOGPTR( RxContext )
  897. LOGPTR( Fobx )
  898. LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
  899. }
  900. }
  901. ASSERT( Status != STATUS_RETRY );
  902. if (Status != STATUS_RETRY) {
  903. ASSERT( Irp->IoStatus.Information <= IrpSp->Parameters.Read.Length );
  904. ASSERT( RxContext->MajorFunction == IRP_MJ_READ );
  905. }
  906. RxDbgTrace( -1, Dbg, ("RxLowIoReadShellCompletion asyncexit Status = %08lx\n", Status) );
  907. return Status;
  908. }
  909. NTSTATUS
  910. RxLowIoReadShell (
  911. IN PRX_CONTEXT RxContext,
  912. IN PIRP Irp,
  913. IN PFCB Fcb
  914. )
  915. /*++
  916. Routine Description:
  917. This routine preprocesses a read request before it goes down to the minirdr. It does callouts
  918. to handle compression, buffering and shadowing. It is the opposite number of LowIoReadShellCompletion.
  919. By the time we get here, either the shadowing system will handle the read OR we are going to the wire.
  920. Read buffering was already tried in the UncachedRead strategy
  921. Arguments:
  922. RxContext - the usual
  923. Return Value:
  924. whatever value is returned by a callout....or by LowIo.
  925. --*/
  926. {
  927. NTSTATUS Status;
  928. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  929. PAGED_CODE();
  930. RxDbgTrace( +1, Dbg, ("RxLowIoReadShell entry %08lx\n") );
  931. RxLog(( "RdShl in %lx\n", RxContext ));
  932. RxWmiLog( LOG,
  933. RxLowIoReadShell_1,
  934. LOGPTR( RxContext ) );
  935. if (Fcb->CachedNetRootType == NET_ROOT_DISK) {
  936. ExInterlockedAddLargeStatistic( &RxContext->RxDeviceObject->NetworkReadBytesRequested,
  937. LowIoContext->ParamsFor.ReadWrite.ByteCount );
  938. }
  939. Status = RxLowIoSubmit( RxContext, Irp, Fcb, RxLowIoReadShellCompletion );
  940. RxDbgTrace( -1, Dbg, ("RxLowIoReadShell exit Status = %08lx\n", Status) );
  941. RxLog(( "RdShl out %x %x\n", RxContext, Status ));
  942. RxWmiLog( LOG,
  943. RxLowIoReadShell_2,
  944. LOGPTR( RxContext )
  945. LOGULONG( Status ) );
  946. return Status;
  947. }
  948. #if DBG
  949. ULONG RxLoudLowIoOpsEnabled = 0;
  950. VOID CheckForLoudOperations (
  951. IN PRX_CONTEXT RxContext,
  952. IN PFCB Fcb
  953. )
  954. {
  955. PAGED_CODE();
  956. if (RxLoudLowIoOpsEnabled) {
  957. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  958. PCHAR Buffer;
  959. PWCHAR FileOfConcern = L"all.scr";
  960. ULONG Length = 7*sizeof( WCHAR ); //7 is the length of all.scr;
  961. Buffer = Add2Ptr( Fcb->PrivateAlreadyPrefixedName.Buffer, Fcb->PrivateAlreadyPrefixedName.Length - Length );
  962. if (RtlCompareMemory( Buffer, FileOfConcern, Length ) == Length) {
  963. SetFlag( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS );
  964. }
  965. }
  966. return;
  967. }
  968. #endif //if DBG