3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File Read routine for Read called by the
12 Fsd/Fsp dispatch drivers.
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_READ)
29 // _In_ ULONG ByteCount
34 // This macro just puts a nice little try-except around RtlZeroMemory
38 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
40 RtlZeroMemory( (AT), (BYTE_COUNT) ); \
41 __pragma(warning(suppress: 6320)) \
42 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
43 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
47 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
49 RtlZeroMemory( (AT), (BYTE_COUNT) ); \
50 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
51 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
57 // Read ahead amount used for normal data files
60 #define READ_AHEAD_GRANULARITY (0x10000)
63 #pragma alloc_text(PAGE, CdCommonRead)
68 _Requires_lock_held_(_Global_critical_region_
)
71 _Inout_ PIRP_CONTEXT IrpContext
,
79 This is the common entry point for NtReadFile calls. For synchronous requests,
80 CommonRead will complete the request in the current thread. If not
81 synchronous the request will be passed to the Fsp if there is a need to
86 Irp - Supplies the Irp to process
90 NTSTATUS - The result of this operation.
95 NTSTATUS Status
= STATUS_SUCCESS
;
96 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
98 TYPE_OF_OPEN TypeOfOpen
;
108 LONGLONG StartingOffset
;
112 ULONG OriginalByteCount
;
116 BOOLEAN ReleaseFile
= TRUE
;
118 CD_IO_CONTEXT LocalIoContext
;
123 // If this is a zero length read then return SUCCESS immediately.
126 if (IrpSp
->Parameters
.Read
.Length
== 0) {
128 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
129 return STATUS_SUCCESS
;
133 // Decode the file object and verify we support read on this. It
134 // must be a user file, stream file or volume file (for a data disk).
137 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
139 // Internal lock object is acquired if return status is STATUS_PENDING
140 _Analysis_suppress_lock_checking_(Fcb
->Resource
);
142 if ((TypeOfOpen
== UnopenedFileObject
) ||
143 (TypeOfOpen
== UserDirectoryOpen
)) {
145 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
146 return STATUS_INVALID_DEVICE_REQUEST
;
150 // Examine our input parameters to determine if this is noncached and/or
151 // a paging io operation.
154 Wait
= BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
155 PagingIo
= FlagOn( Irp
->Flags
, IRP_PAGING_IO
);
156 NonCachedIo
= FlagOn( Irp
->Flags
, IRP_NOCACHE
);
157 SynchronousIo
= FlagOn( IrpSp
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
161 // Extract the range of the Io.
164 StartingOffset
= IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
;
165 OriginalByteCount
= ByteCount
= IrpSp
->Parameters
.Read
.Length
;
167 ByteRange
= StartingOffset
+ ByteCount
;
170 // Make sure that Dasd access is always non-cached.
173 if (TypeOfOpen
== UserVolumeOpen
) {
179 // Acquire the file shared to perform the read. If we are doing paging IO,
180 // it may be the case that we would have a deadlock imminent because we may
181 // block on shared access, so starve out any exclusive waiters. This requires
182 // a degree of caution - we believe that any paging IO bursts will recede and
183 // allow the exclusive waiter in.
188 CdAcquireFileSharedStarveExclusive( IrpContext
, Fcb
);
192 CdAcquireFileShared( IrpContext
, Fcb
);
196 // Use a try-finally to facilitate cleanup.
202 // Verify the Fcb. Allow reads if this is a DASD handle that is
203 // dismounting the volume.
206 if ((TypeOfOpen
!= UserVolumeOpen
) || (NULL
== Ccb
) ||
207 !FlagOn( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
)) {
209 CdVerifyFcbOperation( IrpContext
, Fcb
);
213 // If this is a non-cached then check whether we need to post this
214 // request if this thread can't block.
217 if (!Wait
&& NonCachedIo
) {
220 // XA requests must always be waitable.
223 if (FlagOn( Fcb
->FcbState
, FCB_STATE_RAWSECTOR_MASK
)) {
225 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
226 try_return( Status
= STATUS_CANT_WAIT
);
231 // If this is a user request then verify the oplock and filelock state.
234 if (TypeOfOpen
== UserFileOpen
) {
237 // We check whether we can proceed
238 // based on the state of the file oplocks.
241 Status
= FsRtlCheckOplock( CdGetFcbOplock(Fcb
),
244 (PVOID
)CdOplockComplete
,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
245 (PVOID
)CdPrePostIrp
);/* ReactOS Change: GCC "assignment from incompatible pointer type" */
248 // If the result is not STATUS_SUCCESS then the Irp was completed
252 if (Status
!= STATUS_SUCCESS
) {
257 try_return( NOTHING
);
261 (Fcb
->FileLock
!= NULL
) &&
262 !FsRtlCheckLockForReadAccess( Fcb
->FileLock
, Irp
)) {
264 try_return( Status
= STATUS_FILE_LOCK_CONFLICT
);
269 // Check request beyond end of file if this is not a read on a volume
270 // handle marked for extended DASD IO.
273 if ((TypeOfOpen
!= UserVolumeOpen
) ||
274 (!FlagOn( Ccb
->Flags
, CCB_FLAG_ALLOW_EXTENDED_DASD_IO
))) {
277 // Complete the request if it begins beyond the end of file.
280 if (StartingOffset
>= Fcb
->FileSize
.QuadPart
) {
282 try_return( Status
= STATUS_END_OF_FILE
);
286 // Truncate the read if it extends beyond the end of the file.
289 if (ByteRange
> Fcb
->FileSize
.QuadPart
) {
291 ByteCount
= (ULONG
) (Fcb
->FileSize
.QuadPart
- StartingOffset
);
292 ByteRange
= Fcb
->FileSize
.QuadPart
;
297 // Handle the non-cached read first.
303 // If we have an unaligned transfer then post this request if
304 // we can't wait. Unaligned means that the starting offset
305 // is not on a sector boundary or the read is not integral
309 ReadByteCount
= BlockAlign( Fcb
->Vcb
, ByteCount
);
311 if (SectorOffset( StartingOffset
) ||
312 SectorOffset( ReadByteCount
) ||
313 (ReadByteCount
> OriginalByteCount
)) {
317 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
321 // Make sure we don't overwrite the buffer.
324 ReadByteCount
= ByteCount
;
328 // Initialize the IoContext for the read.
329 // If there is a context pointer, we need to make sure it was
330 // allocated and not a stale stack pointer.
333 if (IrpContext
->IoContext
== NULL
||
334 !FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
)) {
337 // If we can wait, use the context on the stack. Otherwise
338 // we need to allocate one.
343 IrpContext
->IoContext
= &LocalIoContext
;
344 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
348 IrpContext
->IoContext
= CdAllocateIoContext();
349 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
353 RtlZeroMemory( IrpContext
->IoContext
, sizeof( CD_IO_CONTEXT
));
356 // Store whether we allocated this context structure in the structure
360 IrpContext
->IoContext
->AllocatedContext
=
361 BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
365 KeInitializeEvent( &IrpContext
->IoContext
->SyncEvent
,
371 IrpContext
->IoContext
->ResourceThreadId
= ExGetCurrentResourceThread();
372 IrpContext
->IoContext
->Resource
= Fcb
->Resource
;
373 IrpContext
->IoContext
->RequestedByteCount
= ByteCount
;
376 Irp
->IoStatus
.Information
= ReadByteCount
;
379 // Call one of the NonCacheIo routines to perform the actual
383 if (FlagOn( Fcb
->FcbState
, FCB_STATE_RAWSECTOR_MASK
)) {
385 Status
= CdNonCachedXARead( IrpContext
, Fcb
, StartingOffset
, ReadByteCount
);
389 Status
= CdNonCachedRead( IrpContext
, Fcb
, StartingOffset
, ReadByteCount
);
393 // Don't complete this request now if STATUS_PENDING was returned.
396 if (Status
== STATUS_PENDING
) {
402 // Test is we should zero part of the buffer or update the
403 // synchronous file position.
409 // Convert any unknown error code to IO_ERROR.
412 if (!NT_SUCCESS( Status
)) {
415 // Set the information field to zero.
418 Irp
->IoStatus
.Information
= 0;
421 // Raise if this is a user induced error.
424 if (IoIsErrorUserInduced( Status
)) {
426 CdRaiseStatus( IrpContext
, Status
);
429 Status
= FsRtlNormalizeNtstatus( Status
, STATUS_UNEXPECTED_IO_ERROR
);
432 // Check if there is any portion of the user's buffer to zero.
435 } else if (ReadByteCount
!= ByteCount
) {
437 CdMapUserBuffer( IrpContext
, &UserBuffer
);
439 SafeZeroMemory( IrpContext
,
443 ReadByteCount
- ByteCount
);
445 Irp
->IoStatus
.Information
= ByteCount
;
449 // Update the file position if this is a synchronous request.
452 if (SynchronousIo
&& !PagingIo
&& NT_SUCCESS( Status
)) {
454 IrpSp
->FileObject
->CurrentByteOffset
.QuadPart
= ByteRange
;
458 try_return( NOTHING
);
462 // Handle the cached case. Start by initializing the private
466 if (IrpSp
->FileObject
->PrivateCacheMap
== NULL
) {
469 // Now initialize the cache map.
472 CcInitializeCacheMap( IrpSp
->FileObject
,
473 (PCC_FILE_SIZES
) &Fcb
->AllocationSize
,
475 &CdData
.CacheManagerCallbacks
,
478 CcSetReadAheadGranularity( IrpSp
->FileObject
, READ_AHEAD_GRANULARITY
);
482 // Read from the cache if this is not an Mdl read.
485 if (!FlagOn( IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
488 // If we are in the Fsp now because we had to wait earlier,
489 // we must map the user buffer, otherwise we can use the
490 // user's buffer directly.
493 CdMapUserBuffer( IrpContext
, &SystemBuffer
);
496 // Now try to do the copy.
499 if (!CcCopyRead( IrpSp
->FileObject
,
500 (PLARGE_INTEGER
) &StartingOffset
,
506 try_return( Status
= STATUS_CANT_WAIT
);
510 // If the call didn't succeed, raise the error status
513 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
515 CdNormalizeAndRaiseStatus( IrpContext
, Irp
->IoStatus
.Status
);
519 // Otherwise perform the MdlRead operation.
524 CcMdlRead( IrpSp
->FileObject
,
525 (PLARGE_INTEGER
) &StartingOffset
,
530 Status
= Irp
->IoStatus
.Status
;
534 // Update the current file position in the user file object.
537 if (SynchronousIo
&& !PagingIo
&& NT_SUCCESS( Status
)) {
539 IrpSp
->FileObject
->CurrentByteOffset
.QuadPart
= ByteRange
;
551 CdReleaseFile( IrpContext
, Fcb
);
556 // Post the request if we got CANT_WAIT.
559 if (Status
== STATUS_CANT_WAIT
) {
561 Status
= CdFsdPostRequest( IrpContext
, Irp
);
564 // Otherwise complete the request.
569 CdCompleteRequest( IrpContext
, Irp
, Status
);