ReactOS  0.4.13-dev-479-gec9c8fd
read.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  Read.c
8 
9 Abstract:
10 
11  This module implements the File Read routine for Read called by the
12  Fsd/Fsp dispatch drivers.
13 
14 
15 --*/
16 
17 #include "cdprocs.h"
18 
19 //
20 // The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId (CDFS_BUG_CHECK_READ)
24 
25 //
26 // VOID
27 // SafeZeroMemory (
28 // _Out_ PUCHAR At,
29 // _In_ ULONG ByteCount
30 // );
31 //
32 
33 //
34 // This macro just puts a nice little try-except around RtlZeroMemory
35 //
36 
37 #ifndef __REACTOS__
38 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
39  _SEH2_TRY { \
40  RtlZeroMemory( (AT), (BYTE_COUNT) ); \
41 __pragma(warning(suppress: 6320)) \
42  } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
43  CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
44  } _SEH2_END; \
45 }
46 #else
47 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
48  _SEH2_TRY { \
49  RtlZeroMemory( (AT), (BYTE_COUNT) ); \
50  } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \
51  CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
52  } _SEH2_END; \
53 }
54 #endif
55 
56 //
57 // Read ahead amount used for normal data files
58 //
59 
60 #define READ_AHEAD_GRANULARITY (0x10000)
61 
62 #ifdef ALLOC_PRAGMA
63 #pragma alloc_text(PAGE, CdCommonRead)
64 #endif
65 
66 
67 
68 _Requires_lock_held_(_Global_critical_region_)
70 CdCommonRead (
71  _Inout_ PIRP_CONTEXT IrpContext,
73  )
74 
75 /*++
76 
77 Routine Description:
78 
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
82  block.
83 
84 Arguments:
85 
86  Irp - Supplies the Irp to process
87 
88 Return Value:
89 
90  NTSTATUS - The result of this operation.
91 
92 --*/
93 
94 {
97 
99  PFCB Fcb;
100  PCCB Ccb;
101 
102  BOOLEAN Wait;
103  ULONG PagingIo;
104  ULONG SynchronousIo;
105  ULONG NonCachedIo;
106  PVOID UserBuffer;
107 
109  LONGLONG ByteRange;
111  ULONG ReadByteCount;
112  ULONG OriginalByteCount;
113 
114  PVOID SystemBuffer;
115 
116  BOOLEAN ReleaseFile = TRUE;
117 
118  CD_IO_CONTEXT LocalIoContext;
119 
120  PAGED_CODE();
121 
122  //
123  // If this is a zero length read then return SUCCESS immediately.
124  //
125 
126  if (IrpSp->Parameters.Read.Length == 0) {
127 
128  CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
129  return STATUS_SUCCESS;
130  }
131 
132  //
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).
135  //
136 
137  TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
138 
139  // Internal lock object is acquired if return status is STATUS_PENDING
141 
142  if ((TypeOfOpen == UnopenedFileObject) ||
144 
147  }
148 
149  //
150  // Examine our input parameters to determine if this is noncached and/or
151  // a paging io operation.
152  //
153 
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 );
158 
159 
160  //
161  // Extract the range of the Io.
162  //
163 
164  StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart;
165  OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length;
166 
167  ByteRange = StartingOffset + ByteCount;
168 
169  //
170  // Make sure that Dasd access is always non-cached.
171  //
172 
173  if (TypeOfOpen == UserVolumeOpen) {
174 
175  NonCachedIo = TRUE;
176  }
177 
178  //
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.
184  //
185 
186  if (PagingIo) {
187 
189 
190  } else {
191 
192  CdAcquireFileShared( IrpContext, Fcb );
193  }
194 
195  //
196  // Use a try-finally to facilitate cleanup.
197  //
198 
199  _SEH2_TRY {
200 
201  //
202  // Verify the Fcb. Allow reads if this is a DASD handle that is
203  // dismounting the volume.
204  //
205 
206  if ((TypeOfOpen != UserVolumeOpen) || (NULL == Ccb) ||
208 
209  CdVerifyFcbOperation( IrpContext, Fcb );
210  }
211 
212  //
213  // If this is a non-cached then check whether we need to post this
214  // request if this thread can't block.
215  //
216 
217  if (!Wait && NonCachedIo) {
218 
219  //
220  // XA requests must always be waitable.
221  //
222 
224 
225  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
227  }
228  }
229 
230  //
231  // If this is a user request then verify the oplock and filelock state.
232  //
233 
234  if (TypeOfOpen == UserFileOpen) {
235 
236  //
237  // We check whether we can proceed
238  // based on the state of the file oplocks.
239  //
240 
242  Irp,
243  IrpContext,
244  (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
245  (PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */
246 
247  //
248  // If the result is not STATUS_SUCCESS then the Irp was completed
249  // elsewhere.
250  //
251 
252  if (Status != STATUS_SUCCESS) {
253 
254  Irp = NULL;
255  IrpContext = NULL;
256 
257  try_return( NOTHING );
258  }
259 
260  if (!PagingIo &&
261  (Fcb->FileLock != NULL) &&
263 
265  }
266  }
267 
268  //
269  // Check request beyond end of file if this is not a read on a volume
270  // handle marked for extended DASD IO.
271  //
272 
273  if ((TypeOfOpen != UserVolumeOpen) ||
275 
276  //
277  // Complete the request if it begins beyond the end of file.
278  //
279 
280  if (StartingOffset >= Fcb->FileSize.QuadPart) {
281 
283  }
284 
285  //
286  // Truncate the read if it extends beyond the end of the file.
287  //
288 
289  if (ByteRange > Fcb->FileSize.QuadPart) {
290 
291  ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
292  ByteRange = Fcb->FileSize.QuadPart;
293  }
294  }
295 
296  //
297  // Handle the non-cached read first.
298  //
299 
300  if (NonCachedIo) {
301 
302  //
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
306  // sectors.
307  //
308 
309  ReadByteCount = BlockAlign( Fcb->Vcb, ByteCount );
310 
311  if (SectorOffset( StartingOffset ) ||
312  SectorOffset( ReadByteCount ) ||
313  (ReadByteCount > OriginalByteCount)) {
314 
315  if (!Wait) {
316 
317  CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
318  }
319 
320  //
321  // Make sure we don't overwrite the buffer.
322  //
323 
324  ReadByteCount = ByteCount;
325  }
326 
327  //
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.
331  //
332 
333  if (IrpContext->IoContext == NULL ||
334  !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
335 
336  //
337  // If we can wait, use the context on the stack. Otherwise
338  // we need to allocate one.
339  //
340 
341  if (Wait) {
342 
343  IrpContext->IoContext = &LocalIoContext;
344  ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
345 
346  } else {
347 
348  IrpContext->IoContext = CdAllocateIoContext();
349  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
350  }
351  }
352 
353  RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT ));
354 
355  //
356  // Store whether we allocated this context structure in the structure
357  // itself.
358  //
359 
360  IrpContext->IoContext->AllocatedContext =
361  BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
362 
363  if (Wait) {
364 
365  KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
367  FALSE );
368 
369  } else {
370 
371  IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
372  IrpContext->IoContext->Resource = Fcb->Resource;
373  IrpContext->IoContext->RequestedByteCount = ByteCount;
374  }
375 
376  Irp->IoStatus.Information = ReadByteCount;
377 
378  //
379  // Call one of the NonCacheIo routines to perform the actual
380  // read.
381  //
382 
384 
385  Status = CdNonCachedXARead( IrpContext, Fcb, StartingOffset, ReadByteCount );
386 
387  } else {
388 
389  Status = CdNonCachedRead( IrpContext, Fcb, StartingOffset, ReadByteCount );
390  }
391 
392  //
393  // Don't complete this request now if STATUS_PENDING was returned.
394  //
395 
396  if (Status == STATUS_PENDING) {
397 
398  Irp = NULL;
399  ReleaseFile = FALSE;
400 
401  //
402  // Test is we should zero part of the buffer or update the
403  // synchronous file position.
404  //
405 
406  } else {
407 
408  //
409  // Convert any unknown error code to IO_ERROR.
410  //
411 
412  if (!NT_SUCCESS( Status )) {
413 
414  //
415  // Set the information field to zero.
416  //
417 
418  Irp->IoStatus.Information = 0;
419 
420  //
421  // Raise if this is a user induced error.
422  //
423 
424  if (IoIsErrorUserInduced( Status )) {
425 
426  CdRaiseStatus( IrpContext, Status );
427  }
428 
430 
431  //
432  // Check if there is any portion of the user's buffer to zero.
433  //
434 
435  } else if (ReadByteCount != ByteCount) {
436 
437  CdMapUserBuffer( IrpContext, &UserBuffer);
438 
439  SafeZeroMemory( IrpContext,
440  Add2Ptr( UserBuffer,
441  ByteCount,
442  PVOID ),
443  ReadByteCount - ByteCount );
444 
445  Irp->IoStatus.Information = ByteCount;
446  }
447 
448  //
449  // Update the file position if this is a synchronous request.
450  //
451 
452  if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
453 
454  IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
455  }
456  }
457 
458  try_return( NOTHING );
459  }
460 
461  //
462  // Handle the cached case. Start by initializing the private
463  // cache map.
464  //
465 
466  if (IrpSp->FileObject->PrivateCacheMap == NULL) {
467 
468  //
469  // Now initialize the cache map.
470  //
471 
473  (PCC_FILE_SIZES) &Fcb->AllocationSize,
474  FALSE,
476  Fcb );
477 
479  }
480 
481  //
482  // Read from the cache if this is not an Mdl read.
483  //
484 
485  if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
486 
487  //
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.
491  //
492 
493  CdMapUserBuffer( IrpContext, &SystemBuffer );
494 
495  //
496  // Now try to do the copy.
497  //
498 
499  if (!CcCopyRead( IrpSp->FileObject,
501  ByteCount,
502  Wait,
503  SystemBuffer,
504  &Irp->IoStatus )) {
505 
507  }
508 
509  //
510  // If the call didn't succeed, raise the error status
511  //
512 
513  if (!NT_SUCCESS( Irp->IoStatus.Status )) {
514 
515  CdNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status );
516  }
517 
518  //
519  // Otherwise perform the MdlRead operation.
520  //
521 
522  } else {
523 
526  ByteCount,
527  &Irp->MdlAddress,
528  &Irp->IoStatus );
529 
530  Status = Irp->IoStatus.Status;
531  }
532 
533  //
534  // Update the current file position in the user file object.
535  //
536 
537  if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
538 
539  IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
540  }
541 
542  try_exit: NOTHING;
543  } _SEH2_FINALLY {
544 
545  //
546  // Release the Fcb.
547  //
548 
549  if (ReleaseFile) {
550 
551  CdReleaseFile( IrpContext, Fcb );
552  }
553  } _SEH2_END;
554 
555  //
556  // Post the request if we got CANT_WAIT.
557  //
558 
559  if (Status == STATUS_CANT_WAIT) {
560 
561  Status = CdFsdPostRequest( IrpContext, Irp );
562 
563  //
564  // Otherwise complete the request.
565  //
566 
567  } else {
568 
569  CdCompleteRequest( IrpContext, Irp, Status );
570  }
571 
572  return Status;
573 }
574 
575 
576 
#define ExGetCurrentResourceThread()
Definition: env_spec_w32.h:633
FILE_LOCK FileLock
Definition: fatstruc.h:1067
VOID NTAPI CcMdlRead(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus)
Definition: mdlsup.c:64
#define _Analysis_suppress_lock_checking_(lock)
Definition: no_sal2.h:685
#define TRUE
Definition: types.h:120
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define Add2Ptr(PTR, INC)
#define CCB_FLAG_DISMOUNT_ON_CLOSE
Definition: cdstruc.h:1113
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:282
#define CdAcquireFileSharedStarveExclusive(IC, F)
Definition: cdprocs.h:1005
#define IRP_CONTEXT_FLAG_ALLOC_IO
Definition: cdstruc.h:1227
#define IRP_CONTEXT_FLAG_FORCE_POST
Definition: cdstruc.h:1222
#define CdReleaseFile(IC, F)
Definition: cdprocs.h:1008
#define SafeZeroMemory(IC, AT, BYTE_COUNT)
Definition: read.c:38
_In_ PIRP Irp
Definition: csq.h:116
Definition: cdstruc.h:908
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
#define CCB_FLAG_ALLOW_EXTENDED_DASD_IO
Definition: cdstruc.h:1114
Definition: cdstruc.h:1073
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks
Definition: cdstruc.h:415
#define CdMapUserBuffer(IC, UB)
Definition: cdprocs.h:376
#define IoIsErrorUserInduced(Status)
Definition: iofuncs.h:2769
LONG NTSTATUS
Definition: precomp.h:26
#define IRP_NOCACHE
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define READ_AHEAD_GRANULARITY
Definition: read.c:60
#define CdAcquireFileShared(IC, F)
Definition: cdprocs.h:1002
#define PAGED_CODE()
Definition: video.h:57
_SEH2_TRY
Definition: create.c:4250
#define STATUS_END_OF_FILE
Definition: shellext.h:62
#define FO_SYNCHRONOUS_IO
Definition: iotypes.h:1732
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:593
#define CdGetFcbOplock(F)
Definition: cdprocs.h:1086
VOID CdCompleteRequest(_Inout_opt_ PIRP_CONTEXT IrpContext, _Inout_opt_ PIRP Irp, _In_ NTSTATUS Status)
Definition: cddata.c:914
#define SectorOffset(L)
Definition: cdprocs.h:1632
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define BlockAlign(V, L)
Definition: cdprocs.h:1648
int64_t LONGLONG
Definition: typedefs.h:66
CD_DATA CdData
Definition: cddata.c:42
#define CdAllocateIoContext()
Definition: cdprocs.h:1349
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
VOID NTAPI CcInitializeCacheMap(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes, IN BOOLEAN PinAccess, IN PCACHE_MANAGER_CALLBACKS Callbacks, IN PVOID LazyWriteContext)
Definition: fssup.c:193
#define try_return(S)
Definition: cdprocs.h:2189
BOOLEAN NTAPI FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock, IN PIRP Irp)
Definition: filelock.c:676
#define _Inout_
Definition: no_sal2.h:244
ULONG Flags
Definition: ntfs.h:520
BOOLEAN NTAPI CcCopyRead(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus)
Definition: copysup.c:43
#define FCB_STATE_RAWSECTOR_MASK
Definition: cdstruc.h:1058
#define IRP_MN_MDL
Definition: iotypes.h:4062
enum _TYPE_OF_OPEN TYPE_OF_OPEN
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:593
#define NOTHING
Definition: env_spec_w32.h:461
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1060
Status
Definition: gdiplustypes.h:24
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
PFILE_OBJECT FileObject
Definition: iotypes.h:2812
_SEH2_END
Definition: create.c:4424
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define CdRaiseStatus(IC, S)
Definition: cdprocs.h:1869
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4157
_SEH2_FINALLY
Definition: create.c:4395
_Requires_lock_held_(_Global_critical_region_)
Definition: read.c:68
BOOLEAN CdVerifyFcbOperation(_In_opt_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb)
Definition: verfysup.c:615
#define IRP_PAGING_IO
#define STATUS_UNEXPECTED_IO_ERROR
Definition: ntstatus.h:455
#define STATUS_FILE_LOCK_CONFLICT
Definition: ntstatus.h:306
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
PVCB Vcb
Definition: cdstruc.h:939
#define CdNormalizeAndRaiseStatus(IC, S)
Definition: cdprocs.h:1870
NTSTATUS NTAPI FsRtlCheckOplock(IN POPLOCK Oplock, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:1172
NTSTATUS NTAPI FsRtlNormalizeNtstatus(IN NTSTATUS NtStatusToNormalize, IN NTSTATUS NormalizedNtStatus)
Definition: filter.c:90
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
_In_ PFCB Fcb
Definition: cdprocs.h:151
return STATUS_SUCCESS
Definition: btrfs.c:2777
ULONG FcbState
Definition: cdstruc.h:977
#define STATUS_CANT_WAIT
Definition: ntstatus.h:438
IN BOOLEAN Wait
Definition: fatprocs.h:1529
VOID NTAPI CcSetReadAheadGranularity(IN PFILE_OBJECT FileObject, IN ULONG Granularity)
Definition: cachesub.c:36