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.

582 lines
16 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Read.c
  5. Abstract:
  6. This module implements the File Read routine for Read called by the
  7. Fsd/Fsp dispatch drivers.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Dan Lovinger [DanLo] 22-Sep-1996
  11. Tom Jolly [tomjolly] 21-Jan-2000
  12. Revision History:
  13. // @@END_DDKSPLIT
  14. --*/
  15. #include "UdfProcs.h"
  16. //
  17. // The Bug check file id for this module
  18. //
  19. #define BugCheckFileId (UDFS_BUG_CHECK_READ)
  20. //
  21. // The local debug trace level
  22. //
  23. #define Dbg (UDFS_DEBUG_LEVEL_READ)
  24. //
  25. // Read ahead amount used for normal data files
  26. //
  27. #define READ_AHEAD_GRANULARITY (0x10000)
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, UdfCommonRead)
  30. #endif
  31. NTSTATUS
  32. UdfCommonRead (
  33. IN PIRP_CONTEXT IrpContext,
  34. IN PIRP Irp
  35. )
  36. /*++
  37. Routine Description:
  38. This is the common entry point for NtReadFile calls. For synchronous requests,
  39. CommonRead will complete the request in the current thread. If not
  40. synchronous the request will be passed to the Fsp if there is a need to
  41. block.
  42. Arguments:
  43. Irp - Supplies the Irp to process
  44. Return Value:
  45. NTSTATUS - The result of this operation.
  46. --*/
  47. {
  48. NTSTATUS Status;
  49. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  50. TYPE_OF_OPEN TypeOfOpen;
  51. PFCB Fcb;
  52. PCCB Ccb;
  53. PVCB Vcb;
  54. BOOLEAN Wait;
  55. ULONG PagingIo;
  56. ULONG SynchronousIo;
  57. ULONG NonCachedIo;
  58. LONGLONG StartingOffset;
  59. LONGLONG ByteRange;
  60. ULONG ByteCount;
  61. ULONG ReadByteCount;
  62. ULONG OriginalByteCount;
  63. PVOID SystemBuffer, UserBuffer;
  64. BOOLEAN ReleaseFile = TRUE;
  65. BOOLEAN ReleaseVmcbMap = FALSE;
  66. PFILE_OBJECT MappingFileObject;
  67. UDF_IO_CONTEXT LocalIoContext;
  68. PAGED_CODE();
  69. //
  70. // If this is a zero length read then return SUCCESS immediately.
  71. //
  72. if (IrpSp->Parameters.Read.Length == 0) {
  73. UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  74. return STATUS_SUCCESS;
  75. }
  76. //
  77. // Decode the file object and verify we support read on this. It
  78. // must be a user file, stream file or volume file (for a data disk).
  79. //
  80. TypeOfOpen = UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb );
  81. if ((TypeOfOpen == UnopenedFileObject) || (TypeOfOpen == UserDirectoryOpen)) {
  82. UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  83. return STATUS_INVALID_DEVICE_REQUEST;
  84. }
  85. Vcb = Fcb->Vcb;
  86. //
  87. // Examine our input parameters to determine if this is noncached and/or
  88. // a paging io operation.
  89. //
  90. Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  91. PagingIo = FlagOn( Irp->Flags, IRP_PAGING_IO );
  92. NonCachedIo = FlagOn( Irp->Flags, IRP_NOCACHE );
  93. SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO );
  94. //
  95. // Extract the range of the Io.
  96. //
  97. StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart;
  98. OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length;
  99. ByteRange = StartingOffset + ByteCount;
  100. //
  101. // Make sure that Dasd access is always non-cached.
  102. //
  103. if (TypeOfOpen == UserVolumeOpen) {
  104. NonCachedIo = TRUE;
  105. }
  106. //
  107. // Acquire the file shared to perform the read. If we are doing paging IO,
  108. // it may be the case that we would have a deadlock imminent because we may
  109. // block on shared access, so starve out any exclusive waiters. This requires
  110. // a degree of caution - we believe that any paging IO bursts will recede and
  111. // allow the exclusive waiter in.
  112. //
  113. if (PagingIo) {
  114. UdfAcquireFileSharedStarveExclusive( IrpContext, Fcb );
  115. } else {
  116. UdfAcquireFileShared( IrpContext, Fcb );
  117. }
  118. //
  119. // Use a try-finally to facilitate cleanup.
  120. //
  121. try {
  122. //
  123. // Verify the Fcb. Allow reads if this is a DASD handle that is
  124. // dismounting the volume.
  125. //
  126. if ((TypeOfOpen != UserVolumeOpen) || (NULL == Ccb) ||
  127. !FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) {
  128. UdfVerifyFcbOperation( IrpContext, Fcb );
  129. }
  130. //
  131. // If this is a user request then verify the oplock and filelock state.
  132. //
  133. if (TypeOfOpen == UserFileOpen) {
  134. //
  135. // We check whether we can proceed
  136. // based on the state of the file oplocks.
  137. //
  138. Status = FsRtlCheckOplock( &Fcb->Oplock,
  139. Irp,
  140. IrpContext,
  141. UdfOplockComplete,
  142. UdfPrePostIrp );
  143. //
  144. // If the result is not STATUS_SUCCESS then the Irp was completed
  145. // elsewhere.
  146. //
  147. if (Status != STATUS_SUCCESS) {
  148. Irp = NULL;
  149. IrpContext = NULL;
  150. try_leave( Status );
  151. }
  152. if (!PagingIo &&
  153. (Fcb->FileLock != NULL) &&
  154. !FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) {
  155. try_leave( Status = STATUS_FILE_LOCK_CONFLICT );
  156. }
  157. }
  158. if ((TypeOfOpen != UserVolumeOpen) || !FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
  159. //
  160. // Complete the request if it begins beyond the end of file.
  161. //
  162. if (StartingOffset >= Fcb->FileSize.QuadPart) {
  163. try_leave( Status = STATUS_END_OF_FILE );
  164. }
  165. //
  166. // Truncate the read if it extends beyond the end of the file.
  167. //
  168. if (ByteRange > Fcb->FileSize.QuadPart) {
  169. ASSERT( Fcb != Vcb->MetadataFcb);
  170. ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
  171. ByteRange = Fcb->FileSize.QuadPart;
  172. }
  173. }
  174. //
  175. // Now if the data is embedded in the ICB, map through the metadata
  176. // stream to retrieve the bytes.
  177. //
  178. if (FlagOn( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA )) {
  179. //
  180. // The metadata stream better be here by now.
  181. //
  182. ASSERT( Vcb->MetadataFcb->FileObject != NULL );
  183. //
  184. // Bias our starting offset by the offset of the ICB in the metadata
  185. // stream plus the offset of the data bytes in that ICB. Obviously,
  186. // we aren't doing non-cached IO here.
  187. //
  188. StartingOffset += (LlBytesFromSectors( Vcb, Fcb->EmbeddedVsn ) + Fcb->EmbeddedOffset);
  189. MappingFileObject = Vcb->MetadataFcb->FileObject;
  190. NonCachedIo = FALSE;
  191. //
  192. // Ensure that we're mapping within the range of the metadata stream
  193. //
  194. ASSERT( (StartingOffset + ByteCount) <= Vcb->MetadataFcb->FileSize.QuadPart);
  195. } else {
  196. //
  197. // We are mapping through the caller's fileobject
  198. //
  199. MappingFileObject = IrpSp->FileObject;
  200. }
  201. //
  202. // Handle the non-cached read first.
  203. //
  204. if (NonCachedIo) {
  205. //
  206. // If we have an unaligned transfer then post this request if
  207. // we can't wait. Unaligned means that the starting offset
  208. // is not on a sector boundary or the read is not integral
  209. // sectors.
  210. //
  211. ReadByteCount = SectorAlign( Vcb, ByteCount );
  212. if (SectorOffset( Vcb, StartingOffset ) ||
  213. (ReadByteCount > OriginalByteCount)) {
  214. if (!Wait) {
  215. UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  216. }
  217. //
  218. // Make sure we don't overwrite the buffer.
  219. //
  220. ReadByteCount = ByteCount;
  221. }
  222. //
  223. // Initialize the IoContext for the read.
  224. // If there is a context pointer, we need to make sure it was
  225. // allocated and not a stale stack pointer.
  226. //
  227. if (IrpContext->IoContext == NULL ||
  228. !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
  229. //
  230. // If we can wait, use the context on the stack. Otherwise
  231. // we need to allocate one.
  232. //
  233. if (Wait) {
  234. IrpContext->IoContext = &LocalIoContext;
  235. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  236. } else {
  237. IrpContext->IoContext = UdfAllocateIoContext();
  238. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  239. }
  240. }
  241. RtlZeroMemory( IrpContext->IoContext, sizeof( UDF_IO_CONTEXT ));
  242. //
  243. // Store whether we allocated this context structure in the structure
  244. // itself.
  245. //
  246. IrpContext->IoContext->AllocatedContext =
  247. BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  248. if (Wait) {
  249. KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
  250. NotificationEvent,
  251. FALSE );
  252. } else {
  253. IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
  254. IrpContext->IoContext->Resource = Fcb->Resource;
  255. IrpContext->IoContext->RequestedByteCount = ByteCount;
  256. }
  257. Irp->IoStatus.Information = ReadByteCount;
  258. //
  259. // Call the NonCacheIo routine to perform the actual read.
  260. //
  261. Status = UdfNonCachedRead( IrpContext, Fcb, Ccb, StartingOffset, ReadByteCount );
  262. //
  263. // Don't complete this request now if STATUS_PENDING was returned.
  264. //
  265. if (Status == STATUS_PENDING) {
  266. Irp = NULL;
  267. ReleaseFile = FALSE;
  268. //
  269. // Test is we should zero part of the buffer or update the
  270. // synchronous file position.
  271. //
  272. } else {
  273. //
  274. // Convert any unknown error code to IO_ERROR.
  275. //
  276. if (!NT_SUCCESS( Status )) {
  277. //
  278. // Set the information field to zero.
  279. //
  280. Irp->IoStatus.Information = 0;
  281. //
  282. // Raise if this is a user induced error.
  283. //
  284. if (IoIsErrorUserInduced( Status )) {
  285. UdfRaiseStatus( IrpContext, Status );
  286. }
  287. Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR );
  288. //
  289. // Check if there is any portion of the user's buffer to zero.
  290. //
  291. } else if (ReadByteCount != ByteCount) {
  292. UdfMapUserBuffer( IrpContext, &UserBuffer );
  293. SafeZeroMemory( IrpContext,
  294. Add2Ptr( UserBuffer,
  295. ByteCount,
  296. PVOID ),
  297. ReadByteCount - ByteCount );
  298. Irp->IoStatus.Information = ByteCount;
  299. }
  300. //
  301. // Update the file position if this is a synchronous request.
  302. //
  303. if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
  304. IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
  305. }
  306. }
  307. try_leave( NOTHING );
  308. }
  309. //
  310. // Handle the cached case. Start by initializing the private
  311. // cache map.
  312. //
  313. if (MappingFileObject->PrivateCacheMap == NULL) {
  314. //
  315. // The metadata Fcb stream was fired up before any data read. We should never
  316. // see it here.
  317. //
  318. ASSERT( MappingFileObject != Vcb->MetadataFcb->FileObject );
  319. //
  320. // Now initialize the cache map.
  321. //
  322. CcInitializeCacheMap( IrpSp->FileObject,
  323. (PCC_FILE_SIZES) &Fcb->AllocationSize,
  324. FALSE,
  325. &UdfData.CacheManagerCallbacks,
  326. Fcb );
  327. CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY );
  328. }
  329. //
  330. // Read from the cache if this is not an Mdl read.
  331. //
  332. if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
  333. //
  334. // If we are in the Fsp now because we had to wait earlier,
  335. // we must map the user buffer, otherwise we can use the
  336. // user's buffer directly.
  337. //
  338. UdfMapUserBuffer( IrpContext, &SystemBuffer);
  339. //
  340. // Now try to do the copy.
  341. //
  342. if (MappingFileObject == Vcb->MetadataFcb->FileObject) {
  343. UdfAcquireVmcbForCcMap( IrpContext, Vcb);
  344. ReleaseVmcbMap = TRUE;
  345. }
  346. if (!CcCopyRead( MappingFileObject,
  347. (PLARGE_INTEGER) &StartingOffset,
  348. ByteCount,
  349. Wait,
  350. SystemBuffer,
  351. &Irp->IoStatus )) {
  352. try_leave( Status = STATUS_CANT_WAIT );
  353. }
  354. //
  355. // If the call didn't succeed, raise the error status
  356. //
  357. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  358. UdfNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status );
  359. }
  360. Status = Irp->IoStatus.Status;
  361. //
  362. // Otherwise perform the MdlRead operation.
  363. //
  364. } else {
  365. CcMdlRead( MappingFileObject,
  366. (PLARGE_INTEGER) &StartingOffset,
  367. ByteCount,
  368. &Irp->MdlAddress,
  369. &Irp->IoStatus );
  370. Status = Irp->IoStatus.Status;
  371. }
  372. //
  373. // Update the current file position in the user file object.
  374. //
  375. if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
  376. IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
  377. }
  378. } finally {
  379. DebugUnwind( "UdfCommonRead" );
  380. //
  381. // Release the Fcb / Vmcb mapping resource
  382. //
  383. if (ReleaseFile) { UdfReleaseFile( IrpContext, Fcb ); }
  384. if (ReleaseVmcbMap) { UdfReleaseVmcb( IrpContext, Vcb); }
  385. }
  386. //
  387. // Post the request if we got CANT_WAIT.
  388. //
  389. if (Status == STATUS_CANT_WAIT) {
  390. Status = UdfFsdPostRequest( IrpContext, Irp );
  391. //
  392. // Otherwise complete the request.
  393. //
  394. } else {
  395. UdfCompleteRequest( IrpContext, Irp, Status );
  396. }
  397. return Status;
  398. }