[NTOSKRNL] Make the CcWaitForCurrentLazyWriterActivity() stub return success instead...
[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 // IN 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 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
38 try { \
39 RtlZeroMemory( (AT), (BYTE_COUNT) ); \
40 } except( EXCEPTION_EXECUTE_HANDLER ) { \
41 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
42 } \
43 }
44
45 //
46 // Read ahead amount used for normal data files
47 //
48
49 #define READ_AHEAD_GRANULARITY (0x10000)
50
51 #ifdef ALLOC_PRAGMA
52 #pragma alloc_text(PAGE, CdCommonRead)
53 #endif
54
55 \f
56 NTSTATUS
57 CdCommonRead (
58 IN PIRP_CONTEXT IrpContext,
59 IN PIRP Irp
60 )
61
62 /*++
63
64 Routine Description:
65
66 This is the common entry point for NtReadFile calls. For synchronous requests,
67 CommonRead will complete the request in the current thread. If not
68 synchronous the request will be passed to the Fsp if there is a need to
69 block.
70
71 Arguments:
72
73 Irp - Supplies the Irp to process
74
75 Return Value:
76
77 NTSTATUS - The result of this operation.
78
79 --*/
80
81 {
82 NTSTATUS Status = STATUS_SUCCESS; /* ReactOS Change: GCC Uninit var */
83 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
84
85 TYPE_OF_OPEN TypeOfOpen;
86 PFCB Fcb;
87 PCCB Ccb;
88
89 BOOLEAN Wait;
90 ULONG PagingIo;
91 ULONG SynchronousIo;
92 ULONG NonCachedIo;
93 PVOID UserBuffer;
94
95 LONGLONG StartingOffset;
96 LONGLONG ByteRange;
97 ULONG ByteCount;
98 ULONG ReadByteCount;
99 ULONG OriginalByteCount;
100
101 PVOID SystemBuffer;
102
103 BOOLEAN ReleaseFile = TRUE;
104
105 CD_IO_CONTEXT LocalIoContext;
106
107 PAGED_CODE();
108
109 //
110 // If this is a zero length read then return SUCCESS immediately.
111 //
112
113 if (IrpSp->Parameters.Read.Length == 0) {
114
115 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
116 return STATUS_SUCCESS;
117 }
118
119 //
120 // Decode the file object and verify we support read on this. It
121 // must be a user file, stream file or volume file (for a data disk).
122 //
123
124 TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
125
126 if ((TypeOfOpen == UnopenedFileObject) ||
127 (TypeOfOpen == UserDirectoryOpen)) {
128
129 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
130 return STATUS_INVALID_DEVICE_REQUEST;
131 }
132
133 //
134 // Examine our input parameters to determine if this is noncached and/or
135 // a paging io operation.
136 //
137
138 Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
139 PagingIo = FlagOn( Irp->Flags, IRP_PAGING_IO );
140 NonCachedIo = FlagOn( Irp->Flags, IRP_NOCACHE );
141 SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO );
142
143
144 //
145 // Extract the range of the Io.
146 //
147
148 StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart;
149 OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length;
150
151 ByteRange = StartingOffset + ByteCount;
152
153 //
154 // Make sure that Dasd access is always non-cached.
155 //
156
157 if (TypeOfOpen == UserVolumeOpen) {
158
159 NonCachedIo = TRUE;
160 }
161
162 //
163 // Acquire the file shared to perform the read. If we are doing paging IO,
164 // it may be the case that we would have a deadlock imminent because we may
165 // block on shared access, so starve out any exclusive waiters. This requires
166 // a degree of caution - we believe that any paging IO bursts will recede and
167 // allow the exclusive waiter in.
168 //
169
170 if (PagingIo) {
171
172 CdAcquireFileSharedStarveExclusive( IrpContext, Fcb );
173
174 } else {
175
176 CdAcquireFileShared( IrpContext, Fcb );
177 }
178
179 //
180 // Use a try-finally to facilitate cleanup.
181 //
182
183 try {
184
185 //
186 // Verify the Fcb. Allow reads if this is a DASD handle that is
187 // dismounting the volume.
188 //
189
190 if ((TypeOfOpen != UserVolumeOpen) || (NULL == Ccb) ||
191 !FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) {
192
193 CdVerifyFcbOperation( IrpContext, Fcb );
194 }
195
196 //
197 // If this is a non-cached then check whether we need to post this
198 // request if this thread can't block.
199 //
200
201 if (!Wait && NonCachedIo) {
202
203 //
204 // XA requests must always be waitable.
205 //
206
207 if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) {
208
209 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
210 try_return( Status = STATUS_CANT_WAIT );
211 }
212 }
213
214 //
215 // If this is a user request then verify the oplock and filelock state.
216 //
217
218 if (TypeOfOpen == UserFileOpen) {
219
220 //
221 // We check whether we can proceed
222 // based on the state of the file oplocks.
223 //
224
225 Status = FsRtlCheckOplock( &Fcb->Oplock,
226 Irp,
227 IrpContext,
228 (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
229 (PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */
230
231 //
232 // If the result is not STATUS_SUCCESS then the Irp was completed
233 // elsewhere.
234 //
235
236 if (Status != STATUS_SUCCESS) {
237
238 Irp = NULL;
239 IrpContext = NULL;
240
241 try_return( NOTHING );
242 }
243
244 if (!PagingIo &&
245 (Fcb->FileLock != NULL) &&
246 !FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) {
247
248 try_return( Status = STATUS_FILE_LOCK_CONFLICT );
249 }
250 }
251
252 //
253 // Complete the request if it begins beyond the end of file.
254 //
255
256 if (StartingOffset >= Fcb->FileSize.QuadPart) {
257
258 try_return( Status = STATUS_END_OF_FILE );
259 }
260
261 //
262 // Truncate the read if it extends beyond the end of the file.
263 //
264
265 if (ByteRange > Fcb->FileSize.QuadPart) {
266
267 ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
268 ByteRange = Fcb->FileSize.QuadPart;
269 }
270
271 //
272 // Handle the non-cached read first.
273 //
274
275 if (NonCachedIo) {
276
277 //
278 // If we have an unaligned transfer then post this request if
279 // we can't wait. Unaligned means that the starting offset
280 // is not on a sector boundary or the read is not integral
281 // sectors.
282 //
283
284 ReadByteCount = BlockAlign( Fcb->Vcb, ByteCount );
285
286 if (SectorOffset( StartingOffset ) ||
287 SectorOffset( ReadByteCount ) ||
288 (ReadByteCount > OriginalByteCount)) {
289
290 if (!Wait) {
291
292 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
293 }
294
295 //
296 // Make sure we don't overwrite the buffer.
297 //
298
299 ReadByteCount = ByteCount;
300 }
301
302 //
303 // Initialize the IoContext for the read.
304 // If there is a context pointer, we need to make sure it was
305 // allocated and not a stale stack pointer.
306 //
307
308 if (IrpContext->IoContext == NULL ||
309 !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
310
311 //
312 // If we can wait, use the context on the stack. Otherwise
313 // we need to allocate one.
314 //
315
316 if (Wait) {
317
318 IrpContext->IoContext = &LocalIoContext;
319 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
320
321 } else {
322
323 IrpContext->IoContext = CdAllocateIoContext();
324 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
325 }
326 }
327
328 RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT ));
329
330 //
331 // Store whether we allocated this context structure in the structure
332 // itself.
333 //
334
335 IrpContext->IoContext->AllocatedContext =
336 BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
337
338 if (Wait) {
339
340 KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
341 NotificationEvent,
342 FALSE );
343
344 } else {
345
346 IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
347 IrpContext->IoContext->Resource = Fcb->Resource;
348 IrpContext->IoContext->RequestedByteCount = ByteCount;
349 }
350
351 Irp->IoStatus.Information = ReadByteCount;
352
353 //
354 // Call one of the NonCacheIo routines to perform the actual
355 // read.
356 //
357
358 if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) {
359
360 Status = CdNonCachedXARead( IrpContext, Fcb, StartingOffset, ReadByteCount );
361
362 } else {
363
364 Status = CdNonCachedRead( IrpContext, Fcb, StartingOffset, ReadByteCount );
365 }
366
367 //
368 // Don't complete this request now if STATUS_PENDING was returned.
369 //
370
371 if (Status == STATUS_PENDING) {
372
373 Irp = NULL;
374 ReleaseFile = FALSE;
375
376 //
377 // Test is we should zero part of the buffer or update the
378 // synchronous file position.
379 //
380
381 } else {
382
383 //
384 // Convert any unknown error code to IO_ERROR.
385 //
386
387 if (!NT_SUCCESS( Status )) {
388
389 //
390 // Set the information field to zero.
391 //
392
393 Irp->IoStatus.Information = 0;
394
395 //
396 // Raise if this is a user induced error.
397 //
398
399 if (IoIsErrorUserInduced( Status )) {
400
401 CdRaiseStatus( IrpContext, Status );
402 }
403
404 Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR );
405
406 //
407 // Check if there is any portion of the user's buffer to zero.
408 //
409
410 } else if (ReadByteCount != ByteCount) {
411
412 CdMapUserBuffer( IrpContext, &UserBuffer);
413
414 SafeZeroMemory( IrpContext,
415 Add2Ptr( UserBuffer,
416 ByteCount,
417 PVOID ),
418 ReadByteCount - ByteCount );
419
420 Irp->IoStatus.Information = ByteCount;
421 }
422
423 //
424 // Update the file position if this is a synchronous request.
425 //
426
427 if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
428
429 IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
430 }
431 }
432
433 try_return( NOTHING );
434 }
435
436 //
437 // Handle the cached case. Start by initializing the private
438 // cache map.
439 //
440
441 if (IrpSp->FileObject->PrivateCacheMap == NULL) {
442
443 //
444 // Now initialize the cache map.
445 //
446
447 CcInitializeCacheMap( IrpSp->FileObject,
448 (PCC_FILE_SIZES) &Fcb->AllocationSize,
449 FALSE,
450 &CdData.CacheManagerCallbacks,
451 Fcb );
452
453 CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY );
454 }
455
456 //
457 // Read from the cache if this is not an Mdl read.
458 //
459
460 if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
461
462 //
463 // If we are in the Fsp now because we had to wait earlier,
464 // we must map the user buffer, otherwise we can use the
465 // user's buffer directly.
466 //
467
468 CdMapUserBuffer( IrpContext, &SystemBuffer );
469
470 //
471 // Now try to do the copy.
472 //
473
474 if (!CcCopyRead( IrpSp->FileObject,
475 (PLARGE_INTEGER) &StartingOffset,
476 ByteCount,
477 Wait,
478 SystemBuffer,
479 &Irp->IoStatus )) {
480
481 try_return( Status = STATUS_CANT_WAIT );
482 }
483
484 //
485 // If the call didn't succeed, raise the error status
486 //
487
488 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
489
490 CdNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status );
491 }
492
493 //
494 // Otherwise perform the MdlRead operation.
495 //
496
497 } else {
498
499 CcMdlRead( IrpSp->FileObject,
500 (PLARGE_INTEGER) &StartingOffset,
501 ByteCount,
502 &Irp->MdlAddress,
503 &Irp->IoStatus );
504
505 Status = Irp->IoStatus.Status;
506 }
507
508 //
509 // Update the current file position in the user file object.
510 //
511
512 if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
513
514 IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
515 }
516
517 try_exit: NOTHING;
518 } finally {
519
520 //
521 // Release the Fcb.
522 //
523
524 if (ReleaseFile) {
525
526 CdReleaseFile( IrpContext, Fcb );
527 }
528 }
529
530 //
531 // Post the request if we got CANT_WAIT.
532 //
533
534 if (Status == STATUS_CANT_WAIT) {
535
536 Status = CdFsdPostRequest( IrpContext, Irp );
537
538 //
539 // Otherwise complete the request.
540 //
541
542 } else {
543
544 CdCompleteRequest( IrpContext, Irp, Status );
545 }
546
547 return Status;
548 }
549
550