1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: Read.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 * Contains code to handle the "Read" dispatch entry point.
14 *
15 *************************************************************************/
16
17 #include "udffs.h"
18
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_READ
21
22 #ifdef _M_IX86
23 #if DBG
24 #define OVERFLOW_READ_THRESHHOLD (0xE00)
25 #else
26 #define OVERFLOW_READ_THRESHHOLD (0xA00)
27 #endif // UDF_DBG
28 #else // defined(_M_IX86)
29 #define OVERFLOW_READ_THRESHHOLD (0x1000)
30 #endif // defined(_M_IX86)
31
32 //#define POST_LOCK_PAGES
33
34
35 /*************************************************************************
36 *
37 * Function: UDFRead()
38 *
39 * Description:
40 * The I/O Manager will invoke this routine to handle a read
41 * request
42 *
43 * Expected Interrupt Level (for execution) :
44 *
45 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
46 * to be deferred to a worker thread context)
47 *
48 * Return Value: STATUS_SUCCESS/Error
49 *
50 *************************************************************************/
51 NTSTATUS
52 NTAPI
UDFRead(PDEVICE_OBJECT DeviceObject,PIRP Irp)53 UDFRead(
54 PDEVICE_OBJECT DeviceObject, // the logical volume device object
55 PIRP Irp) // I/O Request Packet
56 {
57 NTSTATUS RC = STATUS_SUCCESS;
58 PtrUDFIrpContext PtrIrpContext = NULL;
59 BOOLEAN AreWeTopLevel = FALSE;
60
61 TmPrint(("UDFRead: \n"));
62
63 FsRtlEnterFileSystem();
64 ASSERT(DeviceObject);
65 ASSERT(Irp);
66
67 // set the top level context
68 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
69 ASSERT(!UDFIsFSDevObj(DeviceObject));
70
71 _SEH2_TRY {
72
73 // get an IRP context structure and issue the request
74 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
75 if(PtrIrpContext) {
76 RC = UDFCommonRead(PtrIrpContext, Irp);
77 } else {
78 RC = STATUS_INSUFFICIENT_RESOURCES;
79 Irp->IoStatus.Status = RC;
80 Irp->IoStatus.Information = 0;
81 // complete the IRP
82 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
83 }
84
85 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
86
87 RC = UDFExceptionHandler(PtrIrpContext, Irp);
88
89 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
90 } _SEH2_END;
91
92 if (AreWeTopLevel) {
93 IoSetTopLevelIrp(NULL);
94 }
95
96 FsRtlExitFileSystem();
97
98 return(RC);
99 } // end UDFRead()
100
101
102 /*************************************************************************
103 *
104 * Function: UDFPostStackOverflowRead()
105 *
106 * Description:
107 * Post a read request that could not be processed by
108 * the fsp thread because of stack overflow potential.
109 *
110 * Arguments:
111 * Irp - Supplies the request to process.
112 * Fcb - Supplies the file.
113 *
114 * Return Value: STATUS_PENDING.
115 *
116 *************************************************************************/
117 NTSTATUS
UDFPostStackOverflowRead(IN PtrUDFIrpContext PtrIrpContext,IN PIRP Irp,IN PtrUDFFCB Fcb)118 UDFPostStackOverflowRead(
119 IN PtrUDFIrpContext PtrIrpContext,
120 IN PIRP Irp,
121 IN PtrUDFFCB Fcb
122 )
123 {
124 PKEVENT Event;
125 PERESOURCE Resource;
126
127 UDFPrint(("Getting too close to stack limit pass request to Fsp\n"));
128
129 // Allocate an event and get shared on the resource we will
130 // be later using the common read.
131 Event = (PKEVENT)MyAllocatePool__(NonPagedPool, sizeof(KEVENT));
132 if(!Event)
133 return STATUS_INSUFFICIENT_RESOURCES;
134 KeInitializeEvent( Event, NotificationEvent, FALSE );
135
136 if ((Irp->Flags & IRP_PAGING_IO) && (Fcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource)) {
137 Resource = Fcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource;
138 } else {
139 Resource = Fcb->NTRequiredFCB->CommonFCBHeader.Resource;
140 }
141
142 UDFAcquireResourceShared( Resource, TRUE );
143
144 _SEH2_TRY {
145 // If this read is the result of a verify, we have to
146 // tell the overflow read routne to temporarily
147 // hijack the Vcb->VerifyThread field so that reads
148 // can go through.
149 FsRtlPostStackOverflow(PtrIrpContext, Event, UDFStackOverflowRead);
150 // And wait for the worker thread to complete the item
151 DbgWaitForSingleObject(Event, NULL);
152
153 } _SEH2_FINALLY {
154
155 UDFReleaseResource( Resource );
156 MyFreePool__( Event );
157 } _SEH2_END;
158
159 return STATUS_PENDING;
160
161 } // end UDFPostStackOverflowRead()
162
163 /*************************************************************************
164 *
165 * Function: UDFStackOverflowRead()
166 *
167 * Description:
168 * Process a read request that could not be processed by
169 * the fsp thread because of stack overflow potential.
170 *
171 * Arguments:
172 * Context - Supplies the IrpContext being processed
173 * Event - Supplies the event to be signaled when we are done processing this
174 * request.
175 *
176 * Expected Interrupt Level (for execution) :
177 *
178 * IRQL_PASSIVE_LEVEL
179 *
180 * Return Value: None.
181 *
182 *************************************************************************/
183 VOID
184 NTAPI
UDFStackOverflowRead(IN PVOID Context,IN PKEVENT Event)185 UDFStackOverflowRead(
186 IN PVOID Context,
187 IN PKEVENT Event
188 )
189 {
190 PtrUDFIrpContext PtrIrpContext = (PtrUDFIrpContext)Context;
191 NTSTATUS RC;
192
193 UDFPrint(("UDFStackOverflowRead: \n"));
194 // Make it now look like we can wait for I/O to complete
195 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
196
197 // Do the read operation protected by a try-except clause
198 _SEH2_TRY {
199 UDFCommonRead(PtrIrpContext, PtrIrpContext->Irp);
200 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
201 RC = UDFExceptionHandler(PtrIrpContext, PtrIrpContext->Irp);
202 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
203 } _SEH2_END;
204
205 // Set the stack overflow item's event to tell the original
206 // thread that we're done.
207 KeSetEvent( Event, 0, FALSE );
208 } // end UDFStackOverflowRead()
209
210
211 /*************************************************************************
212 *
213 * Function: UDFCommonRead()
214 *
215 * Description:
216 * The actual work is performed here. This routine may be invoked in one
217 * of the two possible contexts:
218 * (a) in the context of a system worker thread
219 * (b) in the context of the original caller
220 *
221 * Expected Interrupt Level (for execution) :
222 *
223 * IRQL_PASSIVE_LEVEL
224 *
225 * Return Value: STATUS_SUCCESS/Error
226 *
227 *************************************************************************/
228 NTSTATUS
UDFCommonRead(PtrUDFIrpContext PtrIrpContext,PIRP Irp)229 UDFCommonRead(
230 PtrUDFIrpContext PtrIrpContext,
231 PIRP Irp
232 )
233 {
234 NTSTATUS RC = STATUS_SUCCESS;
235 PIO_STACK_LOCATION IrpSp = NULL;
236 LARGE_INTEGER ByteOffset;
237 ULONG ReadLength = 0, TruncatedLength = 0;
238 SIZE_T NumberBytesRead = 0;
239 PFILE_OBJECT FileObject = NULL;
240 PtrUDFFCB Fcb = NULL;
241 PtrUDFCCB Ccb = NULL;
242 PVCB Vcb = NULL;
243 PtrUDFNTRequiredFCB NtReqFcb = NULL;
244 PERESOURCE PtrResourceAcquired = NULL;
245 PERESOURCE PtrResourceAcquired2 = NULL;
246 PVOID SystemBuffer = NULL;
247 PIRP TopIrp;
248 // uint32 KeyValue = 0;
249
250 ULONG Res1Acq = 0;
251 ULONG Res2Acq = 0;
252
253 BOOLEAN CacheLocked = FALSE;
254
255 BOOLEAN CanWait = FALSE;
256 BOOLEAN PagingIo = FALSE;
257 BOOLEAN NonBufferedIo = FALSE;
258 BOOLEAN SynchronousIo = FALSE;
259
260 TmPrint(("UDFCommonRead: irp %x\n", Irp));
261
262 _SEH2_TRY {
263
264 TopIrp = IoGetTopLevelIrp();
265 switch((ULONG_PTR)TopIrp) {
266 case FSRTL_FSP_TOP_LEVEL_IRP:
267 UDFPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n"));
268 break;
269 case FSRTL_CACHE_TOP_LEVEL_IRP:
270 UDFPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n"));
271 break;
272 case FSRTL_MOD_WRITE_TOP_LEVEL_IRP:
273 UDFPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n"));
274 // BrutePoint()
275 break;
276 case FSRTL_FAST_IO_TOP_LEVEL_IRP:
277 UDFPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n"));
278 // BrutePoint()
279 break;
280 case NULL:
281 UDFPrint((" NULL TOP_LEVEL_IRP\n"));
282 break;
283 default:
284 if(TopIrp == Irp) {
285 UDFPrint((" TOP_LEVEL_IRP\n"));
286 } else {
287 UDFPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp));
288 }
289 break;
290 }
291 // First, get a pointer to the current I/O stack location
292 IrpSp = IoGetCurrentIrpStackLocation(Irp);
293 ASSERT(IrpSp);
294 MmPrint((" Enter Irp, MDL=%x\n", Irp->MdlAddress));
295 if(Irp->MdlAddress) {
296 UDFTouch(Irp->MdlAddress);
297 }
298
299 // If this happens to be a MDL read complete request, then
300 // there is not much processing that the FSD has to do.
301 if (IrpSp->MinorFunction & IRP_MN_COMPLETE) {
302 // Caller wants to tell the Cache Manager that a previously
303 // allocated MDL can be freed.
304 UDFMdlComplete(PtrIrpContext, Irp, IrpSp, TRUE);
305 // The IRP has been completed.
306 try_return(RC = STATUS_SUCCESS);
307 }
308
309 // If this is a request at IRQL DISPATCH_LEVEL, then post
310 // the request (your FSD may choose to process it synchronously
311 // if you implement the support correctly; obviously you will be
312 // quite constrained in what you can do at such IRQL).
313 if (IrpSp->MinorFunction & IRP_MN_DPC) {
314 try_return(RC = STATUS_PENDING);
315 }
316
317 FileObject = IrpSp->FileObject;
318 ASSERT(FileObject);
319
320 // Get the FCB and CCB pointers
321 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
322 ASSERT(Ccb);
323 Fcb = Ccb->Fcb;
324 ASSERT(Fcb);
325 Vcb = Fcb->Vcb;
326
327 if(Fcb->FCBFlags & UDF_FCB_DELETED) {
328 ASSERT(FALSE);
329 try_return(RC = STATUS_ACCESS_DENIED);
330 }
331
332 // check for stack overflow
333 if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
334 RC = UDFPostStackOverflowRead( PtrIrpContext, Irp, Fcb );
335 try_return(RC);
336 }
337
338 // Disk based file systems might decide to verify the logical volume
339 // (if required and only if removable media are supported) at this time
340 // As soon as Tray is locked, we needn't call UDFVerifyVcb()
341
342 ByteOffset = IrpSp->Parameters.Read.ByteOffset;
343
344 CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
345 PagingIo = (Irp->Flags & IRP_PAGING_IO) ? TRUE : FALSE;
346 NonBufferedIo = (Irp->Flags & IRP_NOCACHE) ? TRUE : FALSE;
347 SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE;
348 UDFPrint((" Flags: %s %s %s %s\n",
349 CanWait ? "W" : "w", PagingIo ? "Pg" : "pg",
350 NonBufferedIo ? "NBuf" : "buff", SynchronousIo ? "Snc" : "Asc"));
351
352 if(!NonBufferedIo &&
353 (Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) {
354 if(UDFIsAStream(Fcb->FileInfo)) {
355 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo,
356 FILE_NOTIFY_CHANGE_LAST_ACCESS,
357 FILE_ACTION_MODIFIED_STREAM);
358 } else {
359 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo,
360 FILE_NOTIFY_CHANGE_LAST_ACCESS,
361 FILE_ACTION_MODIFIED);
362 }
363 }
364
365 // Get some of the parameters supplied to us
366 ReadLength = IrpSp->Parameters.Read.Length;
367 if (ReadLength == 0) {
368 // a 0 byte read can be immediately succeeded
369 try_return(RC);
370 }
371 UDFPrint((" ByteOffset = %I64x, ReadLength = %x\n", ByteOffset.QuadPart, ReadLength));
372
373 // Is this a read of the volume itself ?
374 if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
375 // Yup, we need to send this on to the disk driver after
376 // validation of the offset and length.
377 Vcb = (PVCB)Fcb;
378 Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
379 if(!CanWait)
380 try_return(RC = STATUS_PENDING);
381
382
383 if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) {
384
385 UDFPrint((" UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n"));
386 PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED;
387
388 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) {
389 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
390 }
391 #ifdef UDF_DELAYED_CLOSE
392 UDFCloseAllDelayed(Vcb);
393 #endif //UDF_DELAYED_CLOSE
394
395 }
396
397 if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH_REQUIRED) {
398
399 UDFPrint((" UDF_IRP_CONTEXT_FLUSH_REQUIRED\n"));
400 PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH_REQUIRED;
401
402 // Acquire the volume resource exclusive
403 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
404 PtrResourceAcquired = &(Vcb->VCBResource);
405
406 UDFFlushLogicalVolume(NULL, NULL, Vcb, 0);
407
408 UDFReleaseResource(PtrResourceAcquired);
409 PtrResourceAcquired = NULL;
410 }
411
412 // Acquire the volume resource shared ...
413 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
414 PtrResourceAcquired = &(Vcb->VCBResource);
415
416 #if 0
417 if(PagingIo) {
418 CollectStatistics(Vcb, MetaDataReads);
419 CollectStatisticsEx(Vcb, MetaDataReadBytes, NumberBytesRead);
420 }
421 #endif
422
423 // Forward the request to the lower level driver
424 // Lock the callers buffer
425 if (!NT_SUCCESS(RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, ReadLength))) {
426 try_return(RC);
427 }
428 SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp);
429 if(!SystemBuffer) {
430 try_return(RC = STATUS_INVALID_USER_BUFFER);
431 }
432 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) {
433 RC = UDFReadData(Vcb, TRUE, ByteOffset.QuadPart,
434 ReadLength, FALSE, (PCHAR)SystemBuffer,
435 &NumberBytesRead);
436 } else {
437 RC = UDFTRead(Vcb, SystemBuffer, ReadLength,
438 (ULONG)(ByteOffset.QuadPart >> Vcb->BlockSizeBits),
439 &NumberBytesRead);
440 }
441 UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer);
442 try_return(RC);
443 }
444 Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
445
446 // If the read request is directed to a page file (if your FSD
447 // supports paging files), send the request directly to the disk
448 // driver. For requests directed to a page file, you have to trust
449 // that the offsets will be set correctly by the VMM. You should not
450 // attempt to acquire any FSD resources either.
451 if(Fcb->FCBFlags & UDF_FCB_PAGE_FILE) {
452 NonBufferedIo = TRUE;
453 }
454
455 if(ByteOffset.HighPart == -1) {
456 if(ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) {
457 ByteOffset = FileObject->CurrentByteOffset;
458 }
459 }
460
461 // If this read is directed to a directory, it is not allowed
462 // by the UDF FSD.
463 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
464 RC = STATUS_INVALID_DEVICE_REQUEST;
465 try_return(RC);
466 }
467
468 NtReqFcb = Fcb->NTRequiredFCB;
469
470 Res1Acq = UDFIsResourceAcquired(&(NtReqFcb->MainResource));
471 if(!Res1Acq) {
472 Res1Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES1_ACQ;
473 }
474 Res2Acq = UDFIsResourceAcquired(&(NtReqFcb->PagingIoResource));
475 if(!Res2Acq) {
476 Res2Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES2_ACQ;
477 }
478
479 #if 0
480 if(PagingIo) {
481 CollectStatistics(Vcb, UserFileReads);
482 CollectStatisticsEx(Vcb, UserFileReadBytes, NumberBytesRead);
483 }
484 #endif
485
486 // This is a good place for oplock related processing.
487
488 // If this is the normal file we have to check for
489 // write access according to the current state of the file locks.
490 if (!PagingIo &&
491 !FsRtlCheckLockForReadAccess( &(NtReqFcb->FileLock), Irp )) {
492 try_return( RC = STATUS_FILE_LOCK_CONFLICT );
493 }
494
495 // Validate start offset and length supplied.
496 // If start offset is > end-of-file, return an appropriate error. Note
497 // that since a FCB resource has already been acquired, and since all
498 // file size changes require acquisition of both FCB resources,
499 // the contents of the FCB and associated data structures
500 // can safely be examined.
501
502 // Also note that we are using the file size in the "Common FCB Header"
503 // to perform the check. However, your FSD might decide to keep a
504 // separate copy in the FCB (or some other representation of the
505 // file associated with the FCB).
506
507 TruncatedLength = ReadLength;
508 if (ByteOffset.QuadPart >= NtReqFcb->CommonFCBHeader.FileSize.QuadPart) {
509 // Starting offset is >= file size
510 try_return(RC = STATUS_END_OF_FILE);
511 }
512 // We can also go ahead and truncate the read length here
513 // such that it is contained within the file size
514 if( NtReqFcb->CommonFCBHeader.FileSize.QuadPart < (ByteOffset.QuadPart + ReadLength) ) {
515 TruncatedLength = (ULONG)(NtReqFcb->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart);
516 // we can't get ZERO here
517 }
518 UDFPrint((" TruncatedLength = %x\n", TruncatedLength));
519
520 // There are certain complications that arise when the same file stream
521 // has been opened for cached and non-cached access. The FSD is then
522 // responsible for maintaining a consistent view of the data seen by
523 // the caller.
524 // Also, it is possible for file streams to be mapped in both as data files
525 // and as an executable. This could also lead to consistency problems since
526 // there now exist two separate sections (and pages) containing file
527 // information.
528
529 // The test below flushes the data cached in system memory if the current
530 // request madates non-cached access (file stream must be cached) and
531 // (a) the current request is not paging-io which indicates it is not
532 // a recursive I/O operation OR originating in the Cache Manager
533 // (b) OR the current request is paging-io BUT it did not originate via
534 // the Cache Manager (or is a recursive I/O operation) and we do
535 // have an image section that has been initialized.
536 #define UDF_REQ_NOT_VIA_CACHE_MGR(ptr) (!MmIsRecursiveIoFault() && ((ptr)->ImageSectionObject != NULL))
537
538 if(NonBufferedIo &&
539 (NtReqFcb->SectionObject.DataSectionObject != NULL)) {
540 if(!PagingIo) {
541
542 /* // We hold the main resource exclusive here because the flush
543 // may generate a recursive write in this thread. The PagingIo
544 // resource is held shared so the drop-and-release serialization
545 // below will work.
546 if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
547 try_return(RC = STATUS_PENDING);
548 }
549 PtrResourceAcquired = &(NtReqFcb->MainResource);
550
551 // We hold PagingIo shared around the flush to fix a
552 // cache coherency problem.
553 UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), TRUE );*/
554
555 MmPrint((" CcFlushCache()\n"));
556 CcFlushCache(&(NtReqFcb->SectionObject), &ByteOffset, TruncatedLength, &(Irp->IoStatus));
557
558 /* UDFReleaseResource(&(NtReqFcb->PagingIoResource));
559 UDFReleaseResource(PtrResourceAcquired);
560 PtrResourceAcquired = NULL;
561 // If the flush failed, return error to the caller
562 if(!NT_SUCCESS(RC = Irp->IoStatus.Status)) {
563 try_return(RC);
564 }
565
566 // Acquiring and immediately dropping the resource serializes
567 // us behind any other writes taking place (either from the
568 // lazy writer or modified page writer).*/
569 if(!Res2Acq) {
570 UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE );
571 UDFReleaseResource(&(NtReqFcb->PagingIoResource));
572 }
573 }
574 }
575
576 // Acquire the appropriate FCB resource shared
577 if (PagingIo) {
578 // Try to acquire the FCB PagingIoResource shared
579 if(!Res2Acq) {
580 if (!UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), CanWait)) {
581 try_return(RC = STATUS_PENDING);
582 }
583 // Remember the resource that was acquired
584 PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource);
585 }
586 } else {
587 // Try to acquire the FCB MainResource shared
588 if(NonBufferedIo) {
589 if(!Res2Acq) {
590 if(!UDFAcquireSharedWaitForExclusive(&(NtReqFcb->PagingIoResource), CanWait)) {
591 try_return(RC = STATUS_PENDING);
592 }
593 PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource);
594 }
595 } else {
596 if(!Res1Acq) {
597 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
598 if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) {
599 try_return(RC = STATUS_PENDING);
600 }
601 // Remember the resource that was acquired
602 PtrResourceAcquired = &(NtReqFcb->MainResource);
603 }
604 }
605 }
606
607 // This is also a good place to set whether fast-io can be performed
608 // on this particular file or not. Your FSD must make it's own
609 // determination on whether or not to allow fast-io operations.
610 // Commonly, fast-io is not allowed if any byte range locks exist
611 // on the file or if oplocks prevent fast-io. Practically any reason
612 // choosen by your FSD could result in your setting FastIoIsNotPossible
613 // OR FastIoIsQuestionable instead of FastIoIsPossible.
614
615 NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
616 /* if(NtReqFcb->CommonFCBHeader.IsFastIoPossible == FastIoIsPossible)
617 NtReqFcb->CommonFCBHeader.IsFastIoPossible = FastIoIsQuestionable;*/
618
619 #ifdef UDF_DISABLE_SYSTEM_CACHE_MANAGER
620 NonBufferedIo = TRUE;
621 #endif
622
623 if(Fcb && Fcb->FileInfo && Fcb->FileInfo->Dloc) {
624 AdPrint(("UDFCommonRead: DataLoc %x, Mapping %x\n", &Fcb->FileInfo->Dloc->DataLoc, Fcb->FileInfo->Dloc->DataLoc.Mapping));
625 }
626
627 // Branch here for cached vs non-cached I/O
628 if (!NonBufferedIo) {
629
630 if(FileObject->Flags & FO_WRITE_THROUGH) {
631 CanWait = TRUE;
632 }
633 // The caller wishes to perform cached I/O. Initiate caching if
634 // this is the first cached I/O operation using this file object
635 if (!(FileObject->PrivateCacheMap)) {
636 // This is the first cached I/O operation. You must ensure
637 // that the FCB Common FCB Header contains valid sizes at this time
638 MmPrint((" CcInitializeCacheMap()\n"));
639 CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)(&(NtReqFcb->CommonFCBHeader.AllocationSize)),
640 FALSE, // We will not utilize pin access for this file
641 &(UDFGlobalData.CacheMgrCallBacks), // callbacks
642 NtReqFcb); // The context used in callbacks
643 MmPrint((" CcSetReadAheadGranularity()\n"));
644 CcSetReadAheadGranularity(FileObject, Vcb->SystemCacheGran);
645 }
646
647 // Check and see if this request requires a MDL returned to the caller
648 if (IrpSp->MinorFunction & IRP_MN_MDL) {
649 // Caller does want a MDL returned. Note that this mode
650 // implies that the caller is prepared to block
651 MmPrint((" CcMdlRead()\n"));
652 // CcMdlRead(FileObject, &ByteOffset, TruncatedLength, &(Irp->MdlAddress), &(Irp->IoStatus));
653 // NumberBytesRead = Irp->IoStatus.Information;
654 // RC = Irp->IoStatus.Status;
655 NumberBytesRead = 0;
656 RC = STATUS_INVALID_PARAMETER;
657
658 try_return(RC);
659 }
660
661 // This is a regular run-of-the-mill cached I/O request. Let the
662 // Cache Manager worry about it!
663 // First though, we need a buffer pointer (address) that is valid
664 SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp);
665 if(!SystemBuffer)
666 try_return(RC = STATUS_INVALID_USER_BUFFER);
667 ASSERT(SystemBuffer);
668 MmPrint((" CcCopyRead()\n"));
669 if (!CcCopyRead(FileObject, &(ByteOffset), TruncatedLength, CanWait, SystemBuffer, &(Irp->IoStatus))) {
670 // The caller was not prepared to block and data is not immediately
671 // available in the system cache
672 try_return(RC = STATUS_PENDING);
673 }
674
675 UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer);
676 // We have the data
677 RC = Irp->IoStatus.Status;
678 NumberBytesRead = Irp->IoStatus.Information;
679
680 try_return(RC);
681
682 } else {
683
684 MmPrint((" Read NonBufferedIo\n"));
685
686 #if 1
687 if((ULONG_PTR)TopIrp == FSRTL_MOD_WRITE_TOP_LEVEL_IRP) {
688 UDFPrint(("FSRTL_MOD_WRITE_TOP_LEVEL_IRP => CanWait\n"));
689 CanWait = TRUE;
690 } else
691 if((ULONG_PTR)TopIrp == FSRTL_CACHE_TOP_LEVEL_IRP) {
692 UDFPrint(("FSRTL_CACHE_TOP_LEVEL_IRP => CanWait\n"));
693 CanWait = TRUE;
694 }
695
696 if(NtReqFcb->AcqSectionCount || NtReqFcb->AcqFlushCount) {
697 MmPrint((" AcqCount (%d/%d)=> CanWait ?\n", NtReqFcb->AcqSectionCount, NtReqFcb->AcqFlushCount));
698 CanWait = TRUE;
699 } else
700 {}
701 /* if((TopIrp != Irp)) {
702 UDFPrint(("(TopIrp != Irp) => CanWait\n"));
703 CanWait = TRUE;
704 } else*/
705 #endif
706 if(KeGetCurrentIrql() > PASSIVE_LEVEL) {
707 MmPrint((" !PASSIVE_LEVEL\n"));
708 CanWait = FALSE;
709 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FORCED_POST;
710 }
711 if(!CanWait && UDFIsFileCached__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, FALSE)) {
712 MmPrint((" Locked => CanWait\n"));
713 CacheLocked = TRUE;
714 CanWait = TRUE;
715 }
716
717 // Send the request to lower level drivers
718 if(!CanWait) {
719 try_return(RC = STATUS_PENDING);
720 }
721
722 // ASSERT(NT_SUCCESS(RC));
723 if(!Res2Acq) {
724 if(UDFAcquireResourceSharedWithCheck(&(NtReqFcb->PagingIoResource)))
725 PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource);
726 }
727
728 RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, TruncatedLength);
729 if(!NT_SUCCESS(RC)) {
730 try_return(RC);
731 }
732
733 SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp);
734 if(!SystemBuffer) {
735 try_return(RC = STATUS_INVALID_USER_BUFFER);
736 }
737
738 RC = UDFReadFile__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength,
739 CacheLocked, (PCHAR)SystemBuffer, &NumberBytesRead);
740 /* // AFAIU, CacheManager wants this:
741 if(!NT_SUCCESS(RC)) {
742 NumberBytesRead = 0;
743 }*/
744
745 UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer);
746
747 #if 0
748 if(PagingIo) {
749 CollectStatistics(Vcb, UserDiskReads);
750 } else {
751 CollectStatistics2(Vcb, NonCachedDiskReads);
752 }
753 #endif
754
755 try_return(RC);
756
757 // For paging-io, the FSD has to trust the VMM to do the right thing
758
759 // Here is a common method used by Windows NT native file systems
760 // that are in the process of sending a request to the disk driver.
761 // First, mark the IRP as pending, then invoke the lower level driver
762 // after setting a completion routine.
763 // Meanwhile, this particular thread can immediately return a
764 // STATUS_PENDING return code.
765 // The completion routine is then responsible for completing the IRP
766 // and unlocking appropriate resources
767
768 // Also, at this point, the FSD might choose to utilize the
769 // information contained in the ValidDataLength field to simply
770 // return zeroes to the caller for reads extending beyond current
771 // valid data length.
772
773 }
774
775 try_exit: NOTHING;
776
777 } _SEH2_FINALLY {
778
779 if(CacheLocked) {
780 WCacheEODirect__(&(Vcb->FastCache), Vcb);
781 }
782
783 // Release any resources acquired here ...
784 if(PtrResourceAcquired2) {
785 UDFReleaseResource(PtrResourceAcquired2);
786 }
787 if(PtrResourceAcquired) {
788 if(NtReqFcb &&
789 (PtrResourceAcquired ==
790 &(NtReqFcb->MainResource))) {
791 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
792 }
793 UDFReleaseResource(PtrResourceAcquired);
794 }
795
796 // Post IRP if required
797 if(RC == STATUS_PENDING) {
798
799 // Lock the callers buffer here. Then invoke a common routine to
800 // perform the post operation.
801 if (!(IrpSp->MinorFunction & IRP_MN_MDL)) {
802 RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, ReadLength);
803 ASSERT(NT_SUCCESS(RC));
804 }
805 if(PagingIo) {
806 if(Res1Acq) {
807 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES1_ACQ;
808 }
809 if(Res2Acq) {
810 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES2_ACQ;
811 }
812 }
813 // Perform the post operation which will mark the IRP pending
814 // and will return STATUS_PENDING back to us
815 RC = UDFPostRequest(PtrIrpContext, Irp);
816
817 } else {
818 // For synchronous I/O, the FSD must maintain the current byte offset
819 // Do not do this however, if I/O is marked as paging-io
820 if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) {
821 FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + NumberBytesRead;
822 }
823 // If the read completed successfully and this was not a paging-io
824 // operation, set a flag in the CCB that indicates that a read was
825 // performed and that the file time should be updated at cleanup
826 if (NT_SUCCESS(RC) && !PagingIo) {
827 FileObject->Flags |= FO_FILE_FAST_IO_READ;
828 Ccb->CCBFlags |= UDF_CCB_ACCESSED;
829 }
830
831 if(!_SEH2_AbnormalTermination()) {
832 Irp->IoStatus.Status = RC;
833 Irp->IoStatus.Information = NumberBytesRead;
834 UDFPrint((" NumberBytesRead = %x\n", NumberBytesRead));
835 // Free up the Irp Context
836 UDFReleaseIrpContext(PtrIrpContext);
837 // complete the IRP
838 MmPrint((" Complete Irp, MDL=%x\n", Irp->MdlAddress));
839 if(Irp->MdlAddress) {
840 UDFTouch(Irp->MdlAddress);
841 }
842 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
843 }
844 } // can we complete the IRP ?
845 } _SEH2_END; // end of "__finally" processing
846
847 return(RC);
848 } // end UDFCommonRead()
849
850
851 #ifdef UDF_DBG
852 ULONG LockBufferCounter = 0;
853 ULONG BuildMdlCounter = 0;
854 #endif //UDF_DBG
855
856 /*************************************************************************
857 *
858 * Function: UDFGetCallersBuffer()
859 *
860 * Description:
861 * Obtain a pointer to the caller's buffer.
862 *
863 * Expected Interrupt Level (for execution) :
864 *
865 * IRQL_PASSIVE_LEVEL
866 *
867 * Return Value: STATUS_SUCCESS/Error
868 *
869 *************************************************************************/
870 PVOID
UDFGetCallersBuffer(PtrUDFIrpContext PtrIrpContext,PIRP Irp)871 UDFGetCallersBuffer(
872 PtrUDFIrpContext PtrIrpContext,
873 PIRP Irp
874 )
875 {
876 VOID *ReturnedBuffer = NULL;
877
878 UDFPrint(("UDFGetCallersBuffer: \n"));
879
880 // If an MDL is supplied, use it.
881 if(Irp->MdlAddress) {
882 MmPrint((" UDFGetCallersBuffer: MmGetSystemAddressForMdl(Irp->MdlAddress) MDL=%x\n", Irp->MdlAddress));
883 // ReturnedBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
884 ReturnedBuffer = MmGetSystemAddressForMdlSafer(Irp->MdlAddress);
885 } else
886 if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_BUFFER_LOCKED) {
887 // Free buffer
888 #ifndef POST_LOCK_PAGES
889 MmPrint((" UDFGetCallersBuffer: MmGetSystemAddressForMdl(PtrIrpContext->PtrMdl) MDL=%x\n", PtrIrpContext->PtrMdl));
890 ReturnedBuffer = MmGetSystemAddressForMdlSafe(PtrIrpContext->PtrMdl, NormalPagePriority);
891 #else //POST_LOCK_PAGES
892 if(PtrIrpContext->TransitionBuffer) {
893 MmPrint((" UDFGetCallersBuffer: TransitionBuffer\n"));
894 return PtrIrpContext->TransitionBuffer;
895 }
896
897 _SEH2_TRY {
898 MmPrint((" MmProbeAndLockPages()\n"));
899 MmProbeAndLockPages(PtrIrpContext->PtrMdl, Irp->RequestorMode,
900 ((PtrIrpContext->MajorFunction == IRP_MJ_READ) ? IoWriteAccess:IoReadAccess));
901 #ifdef UDF_DBG
902 LockBufferCounter++;
903 #endif //UDF_DBG
904 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
905 //RC = STATUS_INVALID_USER_BUFFER;
906 BrutePoint();
907 return NULL;
908 } _SEH2_END;
909
910 MmPrint((" MmGetSystemAddressForMdlSafer()\n"));
911 ReturnedBuffer = MmGetSystemAddressForMdlSafer(PtrIrpContext->PtrMdl);
912 #endif //POST_LOCK_PAGES
913 } else {
914 MmPrint((" UDFGetCallersBuffer: Irp->UserBuffer\n"));
915 ReturnedBuffer = Irp->UserBuffer;
916 }
917
918 return(ReturnedBuffer);
919 } // end UDFGetCallersBuffer()
920
921 /*************************************************************************
922 *
923 * Function: UDFLockCallersBuffer()
924 *
925 * Description:
926 * Obtain a MDL that describes the buffer. Lock pages for I/O
927 *
928 * Expected Interrupt Level (for execution) :
929 *
930 * IRQL_PASSIVE_LEVEL
931 *
932 * Return Value: STATUS_SUCCESS/Error
933 *
934 *************************************************************************/
935 NTSTATUS
UDFLockCallersBuffer(PtrUDFIrpContext PtrIrpContext,PIRP Irp,BOOLEAN IsReadOperation,uint32 Length)936 UDFLockCallersBuffer(
937 PtrUDFIrpContext PtrIrpContext,
938 PIRP Irp,
939 BOOLEAN IsReadOperation,
940 uint32 Length
941 )
942 {
943 NTSTATUS RC = STATUS_SUCCESS;
944 PMDL PtrMdl = NULL;
945
946 UDFPrint(("UDFLockCallersBuffer: \n"));
947
948 ASSERT(Irp);
949
950 _SEH2_TRY {
951 // Is a MDL already present in the IRP
952 if (!(Irp->MdlAddress)) {
953 // Allocate a MDL
954 /*
955 if(!IsReadOperation) {
956 MmPrint((" Allocate TransitionBuffer\n"));
957 PtrIrpContext->TransitionBuffer = (PCHAR)DbgAllocatePool(NonPagedPool, Length);
958 if(!PtrIrpContext->TransitionBuffer) {
959 RC = STATUS_INSUFFICIENT_RESOURCES;
960 try_return(RC);
961 }
962 _SEH2_TRY {
963 RtlCopyMemory(PtrIrpContext->TransitionBuffer, Irp->UserBuffer, Length);
964 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
965 RC = STATUS_INVALID_USER_BUFFER;
966 } _SEH2_END;
967 } else*/ {
968
969 MmPrint((" IoAllocateMdl()\n"));
970 // if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, NULL))) {
971
972 // This will place allocated Mdl to Irp
973 if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp))) {
974 RC = STATUS_INSUFFICIENT_RESOURCES;
975 try_return(RC);
976 }
977 MmPrint((" Alloc MDL=%x\n", PtrMdl));
978 #ifdef UDF_DBG
979 BuildMdlCounter++;
980 #endif //UDF_DBG
981 }
982 // Probe and lock the pages described by the MDL
983 // We could encounter an exception doing so, swallow the exception
984 // NOTE: The exception could be due to an unexpected (from our
985 // perspective), invalidation of the virtual addresses that comprise
986 // the passed in buffer
987 #ifndef POST_LOCK_PAGES
988 _SEH2_TRY {
989 MmPrint((" MmProbeAndLockPages()\n"));
990 MmProbeAndLockPages(PtrMdl, Irp->RequestorMode, (IsReadOperation ? IoWriteAccess:IoReadAccess));
991 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
992 MmPrint((" MmProbeAndLockPages() failed\n"));
993 Irp->MdlAddress = NULL;
994 RC = STATUS_INVALID_USER_BUFFER;
995 } _SEH2_END;
996 #endif //POST_LOCK_PAGES
997
998 if(NT_SUCCESS(RC)) {
999 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_BUFFER_LOCKED;
1000 PtrIrpContext->PtrMdl = PtrMdl;
1001 }
1002 } else {
1003 MmPrint((" UDFLockCallersBuffer: do nothing, MDL=%x\n", Irp->MdlAddress));
1004 UDFTouch(Irp->MdlAddress);
1005 }
1006
1007 try_exit: NOTHING;
1008
1009 } _SEH2_FINALLY {
1010 if (!NT_SUCCESS(RC) && PtrMdl) {
1011 MmPrint((" Free MDL=%x\n", PtrMdl));
1012 IoFreeMdl(PtrMdl);
1013 }
1014 } _SEH2_END;
1015
1016 return(RC);
1017 } // end UDFLockCallersBuffer()
1018
1019 /*************************************************************************
1020 *
1021 * Function: UDFUnlockCallersBuffer()
1022 *
1023 * Description:
1024 * Obtain a MDL that describes the buffer. Lock pages for I/O
1025 *
1026 * Expected Interrupt Level (for execution) :
1027 *
1028 * IRQL_PASSIVE_LEVEL
1029 *
1030 * Return Value: STATUS_SUCCESS/Error
1031 *
1032 *************************************************************************/
1033 NTSTATUS
UDFUnlockCallersBuffer(PtrUDFIrpContext PtrIrpContext,PIRP Irp,PVOID SystemBuffer)1034 UDFUnlockCallersBuffer(
1035 PtrUDFIrpContext PtrIrpContext,
1036 PIRP Irp,
1037 PVOID SystemBuffer
1038 )
1039 {
1040 NTSTATUS RC = STATUS_SUCCESS;
1041
1042 UDFPrint(("UDFUnlockCallersBuffer: \n"));
1043
1044 ASSERT(Irp);
1045
1046 _SEH2_TRY {
1047 // Is a nonPaged buffer already present in the IRP
1048 if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_BUFFER_LOCKED) {
1049
1050 UDFPrint((" UDF_IRP_CONTEXT_BUFFER_LOCKED MDL=%x, Irp MDL=%x\n", PtrIrpContext->PtrMdl, Irp->MdlAddress));
1051 if(PtrIrpContext->TransitionBuffer) {
1052 MmPrint((" UDFUnlockCallersBuffer: free TransitionBuffer\n"));
1053 DbgFreePool(PtrIrpContext->TransitionBuffer);
1054 PtrIrpContext->TransitionBuffer = NULL;
1055 PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_BUFFER_LOCKED;
1056 try_return(RC);
1057 }
1058 // Free buffer
1059 KeFlushIoBuffers( PtrIrpContext->PtrMdl, TRUE, FALSE );
1060 // MmPrint((" IrpCtx->Mdl, MmUnmapLockedPages()\n"));
1061 // MmUnmapLockedPages(SystemBuffer, PtrIrpContext->PtrMdl);
1062
1063 // This will be done in IoCompleteIrp !!!
1064
1065 //MmPrint((" MmUnlockPages()\n"));
1066 //MmUnlockPages(PtrIrpContext->PtrMdl);
1067
1068 #ifdef UDF_DBG
1069 LockBufferCounter--;
1070 #endif //UDF_DBG
1071
1072 // This will be done in IoCompleteIrp !!!
1073
1074 //IoFreeMdl(PtrIrpContext->PtrMdl);
1075
1076 #ifdef UDF_DBG
1077 BuildMdlCounter--;
1078 #endif //UDF_DBG
1079 UDFTouch(PtrIrpContext->PtrMdl);
1080 PtrIrpContext->PtrMdl = NULL;
1081 PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_BUFFER_LOCKED;
1082 } else
1083 if(Irp->MdlAddress) {
1084 // MmPrint((" Irp->Mdl, MmUnmapLockedPages()\n"));
1085 // MmUnmapLockedPages(SystemBuffer, Irp->MdlAddress);
1086 UDFPrint((" UDF_IRP_CONTEXT_BUFFER_LOCKED MDL=%x, Irp MDL=%x\n", PtrIrpContext->PtrMdl, Irp->MdlAddress));
1087 UDFTouch(Irp->MdlAddress);
1088 KeFlushIoBuffers( Irp->MdlAddress,
1089 ((IoGetCurrentIrpStackLocation(Irp))->MajorFunction) == IRP_MJ_READ,
1090 FALSE );
1091 } else
1092 { ; }
1093
1094 try_exit: NOTHING;
1095
1096 } _SEH2_FINALLY {
1097 NOTHING;
1098 } _SEH2_END;
1099
1100 return(RC);
1101 } // end UDFUnlockCallersBuffer()
1102
1103 /*************************************************************************
1104 *
1105 * Function: UDFMdlComplete()
1106 *
1107 * Description:
1108 * Tell Cache Manager to release MDL (and possibly flush).
1109 *
1110 * Expected Interrupt Level (for execution) :
1111 *
1112 * IRQL_PASSIVE_LEVEL
1113 *
1114 * Return Value: None.
1115 *
1116 *************************************************************************/
UDFMdlComplete(PtrUDFIrpContext PtrIrpContext,PIRP Irp,PIO_STACK_LOCATION IrpSp,BOOLEAN ReadCompletion)1117 VOID UDFMdlComplete(
1118 PtrUDFIrpContext PtrIrpContext,
1119 PIRP Irp,
1120 PIO_STACK_LOCATION IrpSp,
1121 BOOLEAN ReadCompletion)
1122 {
1123 NTSTATUS RC = STATUS_SUCCESS;
1124 PFILE_OBJECT FileObject = NULL;
1125
1126 UDFPrint(("UDFMdlComplete: \n"));
1127
1128 FileObject = IrpSp->FileObject;
1129 ASSERT(FileObject);
1130
1131 UDFTouch(Irp->MdlAddress);
1132 // Not much to do here.
1133 if (ReadCompletion) {
1134 MmPrint((" CcMdlReadComplete() MDL=%x\n", Irp->MdlAddress));
1135 CcMdlReadComplete(FileObject, Irp->MdlAddress);
1136 } else {
1137 // The Cache Manager needs the byte offset in the I/O stack location.
1138 MmPrint((" CcMdlWriteComplete() MDL=%x\n", Irp->MdlAddress));
1139 CcMdlWriteComplete(FileObject, &(IrpSp->Parameters.Write.ByteOffset), Irp->MdlAddress);
1140 }
1141
1142 // Clear the MDL address field in the IRP so the IoCompleteRequest()
1143 // does not __try to play around with the MDL.
1144 Irp->MdlAddress = NULL;
1145
1146 // Free up the Irp Context.
1147 UDFReleaseIrpContext(PtrIrpContext);
1148
1149 // Complete the IRP.
1150 Irp->IoStatus.Status = RC;
1151 Irp->IoStatus.Information = 0;
1152 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1153
1154 return;
1155 }
1156