[CDFS_NEW] Address review comments:
[reactos.git] / drivers / filesystems / cdfs_new / read.c
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 \f
67
68 _Requires_lock_held_(_Global_critical_region_)
69 NTSTATUS
70 CdCommonRead (
71 _Inout_ PIRP_CONTEXT IrpContext,
72 _Inout_ PIRP Irp
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 {
95 NTSTATUS Status = STATUS_SUCCESS;
96 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
97
98 TYPE_OF_OPEN TypeOfOpen;
99 PFCB Fcb;
100 PCCB Ccb;
101
102 BOOLEAN Wait;
103 ULONG PagingIo;
104 ULONG SynchronousIo;
105 ULONG NonCachedIo;
106 PVOID UserBuffer;
107
108 LONGLONG StartingOffset;
109 LONGLONG ByteRange;
110 ULONG ByteCount;
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
140 _Analysis_suppress_lock_checking_(Fcb->Resource);
141
142 if ((TypeOfOpen == UnopenedFileObject) ||
143 (TypeOfOpen == UserDirectoryOpen)) {
144
145 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
146 return STATUS_INVALID_DEVICE_REQUEST;
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
188 CdAcquireFileSharedStarveExclusive( IrpContext, Fcb );
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) ||
207 !FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) {
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
223 if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) {
224
225 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
226 try_return( Status = STATUS_CANT_WAIT );
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
241 Status = FsRtlCheckOplock( CdGetFcbOplock(Fcb),
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) &&
262 !FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) {
263
264 try_return( Status = STATUS_FILE_LOCK_CONFLICT );
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) ||
274 (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO ))) {
275
276 //
277 // Complete the request if it begins beyond the end of file.
278 //
279
280 if (StartingOffset >= Fcb->FileSize.QuadPart) {
281
282 try_return( Status = STATUS_END_OF_FILE );
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,
366 NotificationEvent,
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
383 if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) {
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
429 Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR );
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
472 CcInitializeCacheMap( IrpSp->FileObject,
473 (PCC_FILE_SIZES) &Fcb->AllocationSize,
474 FALSE,
475 &CdData.CacheManagerCallbacks,
476 Fcb );
477
478 CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY );
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,
500 (PLARGE_INTEGER) &StartingOffset,
501 ByteCount,
502 Wait,
503 SystemBuffer,
504 &Irp->IoStatus )) {
505
506 try_return( Status = STATUS_CANT_WAIT );
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
524 CcMdlRead( IrpSp->FileObject,
525 (PLARGE_INTEGER) &StartingOffset,
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