Source code of Windows XP (NT5)
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.

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