xref: /reactos/drivers/filesystems/udfs/read.cpp (revision 34593d93)
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