1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "Read" dispatch entry point.
15 *************************************************************************/
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_READ
24 #define OVERFLOW_READ_THRESHHOLD (0xE00)
26 #define OVERFLOW_READ_THRESHHOLD (0xA00)
28 #else // defined(_M_IX86)
29 #define OVERFLOW_READ_THRESHHOLD (0x1000)
30 #endif // defined(_M_IX86)
32 //#define POST_LOCK_PAGES
35 /*************************************************************************
40 * The I/O Manager will invoke this routine to handle a read
43 * Expected Interrupt Level (for execution) :
45 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
46 * to be deferred to a worker thread context)
48 * Return Value: STATUS_SUCCESS/Error
50 *************************************************************************/
54 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
55 PIRP Irp
) // I/O Request Packet
57 NTSTATUS RC
= STATUS_SUCCESS
;
58 PtrUDFIrpContext PtrIrpContext
= NULL
;
59 BOOLEAN AreWeTopLevel
= FALSE
;
61 TmPrint(("UDFRead: \n"));
63 FsRtlEnterFileSystem();
67 // set the top level context
68 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
69 ASSERT(!UDFIsFSDevObj(DeviceObject
));
73 // get an IRP context structure and issue the request
74 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
76 RC
= UDFCommonRead(PtrIrpContext
, Irp
);
78 RC
= STATUS_INSUFFICIENT_RESOURCES
;
79 Irp
->IoStatus
.Status
= RC
;
80 Irp
->IoStatus
.Information
= 0;
82 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
85 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
87 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
89 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
93 IoSetTopLevelIrp(NULL
);
96 FsRtlExitFileSystem();
102 /*************************************************************************
104 * Function: UDFPostStackOverflowRead()
107 * Post a read request that could not be processed by
108 * the fsp thread because of stack overflow potential.
111 * Irp - Supplies the request to process.
112 * Fcb - Supplies the file.
114 * Return Value: STATUS_PENDING.
116 *************************************************************************/
118 UDFPostStackOverflowRead(
119 IN PtrUDFIrpContext PtrIrpContext
,
127 UDFPrint(("Getting too close to stack limit pass request to Fsp\n"));
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
));
133 return STATUS_INSUFFICIENT_RESOURCES
;
134 KeInitializeEvent( Event
, NotificationEvent
, FALSE
);
136 if ((Irp
->Flags
& IRP_PAGING_IO
) && (Fcb
->NTRequiredFCB
->CommonFCBHeader
.PagingIoResource
)) {
137 Resource
= Fcb
->NTRequiredFCB
->CommonFCBHeader
.PagingIoResource
;
139 Resource
= Fcb
->NTRequiredFCB
->CommonFCBHeader
.Resource
;
142 UDFAcquireResourceShared( Resource
, TRUE
);
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
149 FsRtlPostStackOverflow(PtrIrpContext
, Event
, UDFStackOverflowRead
);
150 // And wait for the worker thread to complete the item
151 DbgWaitForSingleObject(Event
, NULL
);
155 UDFReleaseResource( Resource
);
156 MyFreePool__( Event
);
159 return STATUS_PENDING
;
161 } // end UDFPostStackOverflowRead()
163 /*************************************************************************
165 * Function: UDFStackOverflowRead()
168 * Process a read request that could not be processed by
169 * the fsp thread because of stack overflow potential.
172 * Context - Supplies the IrpContext being processed
173 * Event - Supplies the event to be signaled when we are done processing this
176 * Expected Interrupt Level (for execution) :
180 * Return Value: None.
182 *************************************************************************/
185 UDFStackOverflowRead(
190 PtrUDFIrpContext PtrIrpContext
= (PtrUDFIrpContext
)Context
;
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
;
197 // Do the read operation protected by a try-except clause
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
);
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()
211 /*************************************************************************
213 * Function: UDFCommonRead()
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
221 * Expected Interrupt Level (for execution) :
225 * Return Value: STATUS_SUCCESS/Error
227 *************************************************************************/
230 PtrUDFIrpContext PtrIrpContext
,
234 NTSTATUS RC
= STATUS_SUCCESS
;
235 PIO_STACK_LOCATION IrpSp
= NULL
;
236 LARGE_INTEGER ByteOffset
;
237 ULONG ReadLength
= 0, TruncatedLength
= 0;
238 ULONG NumberBytesRead
= 0;
239 PFILE_OBJECT FileObject
= NULL
;
240 PtrUDFFCB Fcb
= NULL
;
241 PtrUDFCCB Ccb
= NULL
;
243 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
244 PERESOURCE PtrResourceAcquired
= NULL
;
245 PERESOURCE PtrResourceAcquired2
= NULL
;
246 PVOID SystemBuffer
= NULL
;
248 // uint32 KeyValue = 0;
253 BOOLEAN CacheLocked
= FALSE
;
255 BOOLEAN CanWait
= FALSE
;
256 BOOLEAN PagingIo
= FALSE
;
257 BOOLEAN NonBufferedIo
= FALSE
;
258 BOOLEAN SynchronousIo
= FALSE
;
260 TmPrint(("UDFCommonRead: irp %x\n", Irp
));
264 TopIrp
= IoGetTopLevelIrp();
265 switch((ULONG
)TopIrp
) {
266 case FSRTL_FSP_TOP_LEVEL_IRP
:
267 UDFPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n"));
269 case FSRTL_CACHE_TOP_LEVEL_IRP
:
270 UDFPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n"));
272 case FSRTL_MOD_WRITE_TOP_LEVEL_IRP
:
273 UDFPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n"));
276 case FSRTL_FAST_IO_TOP_LEVEL_IRP
:
277 UDFPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n"));
281 UDFPrint((" NULL TOP_LEVEL_IRP\n"));
285 UDFPrint((" TOP_LEVEL_IRP\n"));
287 UDFPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp
));
291 // First, get a pointer to the current I/O stack location
292 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
294 MmPrint((" Enter Irp, MDL=%x\n", Irp
->MdlAddress
));
295 if(Irp
->MdlAddress
) {
296 UDFTouch(Irp
->MdlAddress
);
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
);
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
);
317 FileObject
= IrpSp
->FileObject
;
320 // Get the FCB and CCB pointers
321 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
327 if(Fcb
->FCBFlags
& UDF_FCB_DELETED
) {
329 try_return(RC
= STATUS_ACCESS_DENIED
);
332 // check for stack overflow
333 if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD
) {
334 RC
= UDFPostStackOverflowRead( PtrIrpContext
, Irp
, Fcb
);
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()
342 ByteOffset
= IrpSp
->Parameters
.Read
.ByteOffset
;
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"));
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
);
359 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
360 FILE_NOTIFY_CHANGE_LAST_ACCESS
,
361 FILE_ACTION_MODIFIED
);
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
371 UDFPrint((" ByteOffset = %I64x, ReadLength = %x\n", ByteOffset
.QuadPart
, ReadLength
));
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.
378 Vcb
->VCBFlags
|= UDF_VCB_SKIP_EJECT_CHECK
;
380 try_return(RC
= STATUS_PENDING
);
383 if(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_FLUSH2_REQUIRED
) {
385 UDFPrint((" UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n"));
386 PtrIrpContext
->IrpContextFlags
&= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED
;
388 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
)) {
389 UDFCloseAllSystemDelayedInDir(Vcb
, Vcb
->RootDirFCB
->FileInfo
);
391 #ifdef UDF_DELAYED_CLOSE
392 UDFCloseAllDelayed(Vcb
);
393 #endif //UDF_DELAYED_CLOSE
397 if(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_FLUSH_REQUIRED
) {
399 UDFPrint((" UDF_IRP_CONTEXT_FLUSH_REQUIRED\n"));
400 PtrIrpContext
->IrpContextFlags
&= ~UDF_IRP_CONTEXT_FLUSH_REQUIRED
;
402 // Acquire the volume resource exclusive
403 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
404 PtrResourceAcquired
= &(Vcb
->VCBResource
);
406 UDFFlushLogicalVolume(NULL
, NULL
, Vcb
, 0);
408 UDFReleaseResource(PtrResourceAcquired
);
409 PtrResourceAcquired
= NULL
;
412 // Acquire the volume resource shared ...
413 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
414 PtrResourceAcquired
= &(Vcb
->VCBResource
);
418 CollectStatistics(Vcb
, MetaDataReads
);
419 CollectStatisticsEx(Vcb
, MetaDataReadBytes
, NumberBytesRead
);
423 // Forward the request to the lower level driver
424 // Lock the callers buffer
425 if (!NT_SUCCESS(RC
= UDFLockCallersBuffer(PtrIrpContext
, Irp
, TRUE
, ReadLength
))) {
428 SystemBuffer
= UDFGetCallersBuffer(PtrIrpContext
, Irp
);
430 try_return(RC
= STATUS_INVALID_USER_BUFFER
);
432 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) {
433 RC
= UDFReadData(Vcb
, TRUE
, ByteOffset
.QuadPart
,
434 ReadLength
, FALSE
, (PCHAR
)SystemBuffer
,
437 RC
= UDFTRead(Vcb
, SystemBuffer
, ReadLength
,
438 (ULONG
)(ByteOffset
.QuadPart
>> Vcb
->BlockSizeBits
),
441 UDFUnlockCallersBuffer(PtrIrpContext
, Irp
, SystemBuffer
);
444 Vcb
->VCBFlags
|= UDF_VCB_SKIP_EJECT_CHECK
;
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
;
455 if(ByteOffset
.HighPart
== -1) {
456 if(ByteOffset
.LowPart
== FILE_USE_FILE_POINTER_POSITION
) {
457 ByteOffset
= FileObject
->CurrentByteOffset
;
461 // If this read is directed to a directory, it is not allowed
463 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
464 RC
= STATUS_INVALID_DEVICE_REQUEST
;
468 NtReqFcb
= Fcb
->NTRequiredFCB
;
470 Res1Acq
= UDFIsResourceAcquired(&(NtReqFcb
->MainResource
));
472 Res1Acq
= PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_RES1_ACQ
;
474 Res2Acq
= UDFIsResourceAcquired(&(NtReqFcb
->PagingIoResource
));
476 Res2Acq
= PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_RES2_ACQ
;
481 CollectStatistics(Vcb
, UserFileReads
);
482 CollectStatisticsEx(Vcb
, UserFileReadBytes
, NumberBytesRead
);
486 // This is a good place for oplock related processing.
488 // If this is the normal file we have to check for
489 // write access according to the current state of the file locks.
491 !FsRtlCheckLockForReadAccess( &(NtReqFcb
->FileLock
), Irp
)) {
492 try_return( RC
= STATUS_FILE_LOCK_CONFLICT
);
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.
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).
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
);
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
518 UDFPrint((" TruncatedLength = %x\n", TruncatedLength
));
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
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
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))
539 (NtReqFcb
->SectionObject
.DataSectionObject
!= NULL
)) {
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
546 if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
547 try_return(RC = STATUS_PENDING);
549 PtrResourceAcquired = &(NtReqFcb->MainResource);
551 // We hold PagingIo shared around the flush to fix a
552 // cache coherency problem.
553 UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), TRUE );*/
555 MmPrint((" CcFlushCache()\n"));
556 CcFlushCache(&(NtReqFcb
->SectionObject
), &ByteOffset
, TruncatedLength
, &(Irp
->IoStatus
));
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)) {
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).*/
570 UDFAcquireResourceExclusive(&(NtReqFcb
->PagingIoResource
), TRUE
);
571 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
576 // Acquire the appropriate FCB resource shared
578 // Try to acquire the FCB PagingIoResource shared
580 if (!UDFAcquireResourceShared(&(NtReqFcb
->PagingIoResource
), CanWait
)) {
581 try_return(RC
= STATUS_PENDING
);
583 // Remember the resource that was acquired
584 PtrResourceAcquired2
= &(NtReqFcb
->PagingIoResource
);
587 // Try to acquire the FCB MainResource shared
590 if(!UDFAcquireSharedWaitForExclusive(&(NtReqFcb
->PagingIoResource
), CanWait
)) {
591 try_return(RC
= STATUS_PENDING
);
593 PtrResourceAcquired2
= &(NtReqFcb
->PagingIoResource
);
597 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
598 if(!UDFAcquireResourceShared(&(NtReqFcb
->MainResource
), CanWait
)) {
599 try_return(RC
= STATUS_PENDING
);
601 // Remember the resource that was acquired
602 PtrResourceAcquired
= &(NtReqFcb
->MainResource
);
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.
615 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
616 /* if(NtReqFcb->CommonFCBHeader.IsFastIoPossible == FastIoIsPossible)
617 NtReqFcb->CommonFCBHeader.IsFastIoPossible = FastIoIsQuestionable;*/
619 #ifdef UDF_DISABLE_SYSTEM_CACHE_MANAGER
620 NonBufferedIo
= TRUE
;
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
));
627 // Branch here for cached vs non-cached I/O
628 if (!NonBufferedIo
) {
630 if(FileObject
->Flags
& FO_WRITE_THROUGH
) {
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
);
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;
656 RC
= STATUS_INVALID_PARAMETER
;
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
);
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
);
675 UDFUnlockCallersBuffer(PtrIrpContext
, Irp
, SystemBuffer
);
677 RC
= Irp
->IoStatus
.Status
;
678 NumberBytesRead
= Irp
->IoStatus
.Information
;
684 MmPrint((" Read NonBufferedIo\n"));
687 if((ULONG
)TopIrp
== FSRTL_MOD_WRITE_TOP_LEVEL_IRP
) {
688 UDFPrint(("FSRTL_MOD_WRITE_TOP_LEVEL_IRP => CanWait\n"));
691 if((ULONG
)TopIrp
== FSRTL_CACHE_TOP_LEVEL_IRP
) {
692 UDFPrint(("FSRTL_CACHE_TOP_LEVEL_IRP => CanWait\n"));
696 if(NtReqFcb
->AcqSectionCount
|| NtReqFcb
->AcqFlushCount
) {
697 MmPrint((" AcqCount (%d/%d)=> CanWait ?\n", NtReqFcb
->AcqSectionCount
, NtReqFcb
->AcqFlushCount
));
701 /* if((TopIrp != Irp)) {
702 UDFPrint(("(TopIrp != Irp) => CanWait\n"));
706 if(KeGetCurrentIrql() > PASSIVE_LEVEL
) {
707 MmPrint((" !PASSIVE_LEVEL\n"));
709 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_FORCED_POST
;
711 if(!CanWait
&& UDFIsFileCached__(Vcb
, Fcb
->FileInfo
, ByteOffset
.QuadPart
, TruncatedLength
, FALSE
)) {
712 MmPrint((" Locked => CanWait\n"));
717 // Send the request to lower level drivers
719 try_return(RC
= STATUS_PENDING
);
722 // ASSERT(NT_SUCCESS(RC));
724 if(UDFAcquireResourceSharedWithCheck(&(NtReqFcb
->PagingIoResource
)))
725 PtrResourceAcquired2
= &(NtReqFcb
->PagingIoResource
);
728 RC
= UDFLockCallersBuffer(PtrIrpContext
, Irp
, TRUE
, TruncatedLength
);
729 if(!NT_SUCCESS(RC
)) {
733 SystemBuffer
= UDFGetCallersBuffer(PtrIrpContext
, Irp
);
735 try_return(RC
= STATUS_INVALID_USER_BUFFER
);
738 RC
= UDFReadFile__(Vcb
, Fcb
->FileInfo
, ByteOffset
.QuadPart
, TruncatedLength
,
739 CacheLocked
, (PCHAR
)SystemBuffer
, &NumberBytesRead
);
740 /* // AFAIU, CacheManager wants this:
741 if(!NT_SUCCESS(RC)) {
745 UDFUnlockCallersBuffer(PtrIrpContext
, Irp
, SystemBuffer
);
749 CollectStatistics(Vcb
, UserDiskReads
);
751 CollectStatistics2(Vcb
, NonCachedDiskReads
);
757 // For paging-io, the FSD has to trust the VMM to do the right thing
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
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.
780 WCacheEODirect__(&(Vcb
->FastCache
), Vcb
);
783 // Release any resources acquired here ...
784 if(PtrResourceAcquired2
) {
785 UDFReleaseResource(PtrResourceAcquired2
);
787 if(PtrResourceAcquired
) {
789 (PtrResourceAcquired
==
790 &(NtReqFcb
->MainResource
))) {
791 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
793 UDFReleaseResource(PtrResourceAcquired
);
796 // Post IRP if required
797 if(RC
== STATUS_PENDING
) {
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
));
807 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_RES1_ACQ
;
810 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_RES2_ACQ
;
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
);
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
;
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
;
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
);
838 MmPrint((" Complete Irp, MDL=%x\n", Irp
->MdlAddress
));
839 if(Irp
->MdlAddress
) {
840 UDFTouch(Irp
->MdlAddress
);
842 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
844 } // can we complete the IRP ?
845 } _SEH2_END
; // end of "__finally" processing
848 } // end UDFCommonRead()
852 ULONG LockBufferCounter
= 0;
853 ULONG BuildMdlCounter
= 0;
856 /*************************************************************************
858 * Function: UDFGetCallersBuffer()
861 * Obtain a pointer to the caller's buffer.
863 * Expected Interrupt Level (for execution) :
867 * Return Value: STATUS_SUCCESS/Error
869 *************************************************************************/
872 PtrUDFIrpContext PtrIrpContext
,
876 VOID
*ReturnedBuffer
= NULL
;
878 UDFPrint(("UDFGetCallersBuffer: \n"));
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
);
886 if (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_BUFFER_LOCKED
) {
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
;
898 MmPrint((" MmProbeAndLockPages()\n"));
899 MmProbeAndLockPages(PtrIrpContext
->PtrMdl
, Irp
->RequestorMode
,
900 ((PtrIrpContext
->MajorFunction
== IRP_MJ_READ
) ? IoWriteAccess
:IoReadAccess
));
904 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
905 //RC = STATUS_INVALID_USER_BUFFER;
910 MmPrint((" MmGetSystemAddressForMdlSafer()\n"));
911 ReturnedBuffer
= MmGetSystemAddressForMdlSafer(PtrIrpContext
->PtrMdl
);
912 #endif //POST_LOCK_PAGES
914 MmPrint((" UDFGetCallersBuffer: Irp->UserBuffer\n"));
915 ReturnedBuffer
= Irp
->UserBuffer
;
918 return(ReturnedBuffer
);
919 } // end UDFGetCallersBuffer()
921 /*************************************************************************
923 * Function: UDFLockCallersBuffer()
926 * Obtain a MDL that describes the buffer. Lock pages for I/O
928 * Expected Interrupt Level (for execution) :
932 * Return Value: STATUS_SUCCESS/Error
934 *************************************************************************/
936 UDFLockCallersBuffer(
937 PtrUDFIrpContext PtrIrpContext
,
939 BOOLEAN IsReadOperation
,
943 NTSTATUS RC
= STATUS_SUCCESS
;
946 UDFPrint(("UDFLockCallersBuffer: \n"));
951 // Is a MDL already present in the IRP
952 if (!(Irp
->MdlAddress
)) {
955 if(!IsReadOperation) {
956 MmPrint((" Allocate TransitionBuffer\n"));
957 PtrIrpContext->TransitionBuffer = (PCHAR)DbgAllocatePool(NonPagedPool, Length);
958 if(!PtrIrpContext->TransitionBuffer) {
959 RC = STATUS_INSUFFICIENT_RESOURCES;
963 RtlCopyMemory(PtrIrpContext->TransitionBuffer, Irp->UserBuffer, Length);
964 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
965 RC = STATUS_INVALID_USER_BUFFER;
969 MmPrint((" IoAllocateMdl()\n"));
970 // if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, NULL))) {
972 // This will place allocated Mdl to Irp
973 if (!(PtrMdl
= IoAllocateMdl(Irp
->UserBuffer
, Length
, FALSE
, FALSE
, Irp
))) {
974 RC
= STATUS_INSUFFICIENT_RESOURCES
;
977 MmPrint((" Alloc MDL=%x\n", PtrMdl
));
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
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
;
996 #endif //POST_LOCK_PAGES
999 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_BUFFER_LOCKED
;
1000 PtrIrpContext
->PtrMdl
= PtrMdl
;
1003 MmPrint((" UDFLockCallersBuffer: do nothing, MDL=%x\n", Irp
->MdlAddress
));
1004 UDFTouch(Irp
->MdlAddress
);
1010 if (!NT_SUCCESS(RC
) && PtrMdl
) {
1011 MmPrint((" Free MDL=%x\n", PtrMdl
));
1017 } // end UDFLockCallersBuffer()
1019 /*************************************************************************
1021 * Function: UDFUnlockCallersBuffer()
1024 * Obtain a MDL that describes the buffer. Lock pages for I/O
1026 * Expected Interrupt Level (for execution) :
1028 * IRQL_PASSIVE_LEVEL
1030 * Return Value: STATUS_SUCCESS/Error
1032 *************************************************************************/
1034 UDFUnlockCallersBuffer(
1035 PtrUDFIrpContext PtrIrpContext
,
1040 NTSTATUS RC
= STATUS_SUCCESS
;
1042 UDFPrint(("UDFUnlockCallersBuffer: \n"));
1047 // Is a nonPaged buffer already present in the IRP
1048 if (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_BUFFER_LOCKED
) {
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
;
1059 KeFlushIoBuffers( PtrIrpContext
->PtrMdl
, TRUE
, FALSE
);
1060 // MmPrint((" IrpCtx->Mdl, MmUnmapLockedPages()\n"));
1061 // MmUnmapLockedPages(SystemBuffer, PtrIrpContext->PtrMdl);
1063 // This will be done in IoCompleteIrp !!!
1065 //MmPrint((" MmUnlockPages()\n"));
1066 //MmUnlockPages(PtrIrpContext->PtrMdl);
1069 LockBufferCounter
--;
1072 // This will be done in IoCompleteIrp !!!
1074 //IoFreeMdl(PtrIrpContext->PtrMdl);
1079 UDFTouch(PtrIrpContext
->PtrMdl
);
1080 PtrIrpContext
->PtrMdl
= NULL
;
1081 PtrIrpContext
->IrpContextFlags
&= ~UDF_IRP_CONTEXT_BUFFER_LOCKED
;
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
,
1101 } // end UDFUnlockCallersBuffer()
1103 /*************************************************************************
1105 * Function: UDFMdlComplete()
1108 * Tell Cache Manager to release MDL (and possibly flush).
1110 * Expected Interrupt Level (for execution) :
1112 * IRQL_PASSIVE_LEVEL
1114 * Return Value: None.
1116 *************************************************************************/
1117 VOID
UDFMdlComplete(
1118 PtrUDFIrpContext PtrIrpContext
,
1120 PIO_STACK_LOCATION IrpSp
,
1121 BOOLEAN ReadCompletion
)
1123 NTSTATUS RC
= STATUS_SUCCESS
;
1124 PFILE_OBJECT FileObject
= NULL
;
1126 UDFPrint(("UDFMdlComplete: \n"));
1128 FileObject
= IrpSp
->FileObject
;
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
);
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
);
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
;
1146 // Free up the Irp Context.
1147 UDFReleaseIrpContext(PtrIrpContext
);
1149 // Complete the IRP.
1150 Irp
->IoStatus
.Status
= RC
;
1151 Irp
->IoStatus
.Information
= 0;
1152 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);