Something went wrong. Try again.
Reactos
Something went wrong. Try again.
43 kB · 1155 lines
C++
at master
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156////////////////////////////////////////////////////////////////////// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine// All rights reserved// This file was released under the GPLv2 on June 2015./////////////////////////////////////////////////////////////////////*************************************************************************** File: Read.cpp** Module: UDF File System Driver (Kernel mode execution only)** Description:* Contains code to handle the "Read" dispatch entry point.**************************************************************************/
#include "udffs.h"
// define the file specific bug-check id#define UDF_BUG_CHECK_ID UDF_FILE_READ
#ifdef _M_IX86#if DBG#define OVERFLOW_READ_THRESHHOLD (0xE00)#else#define OVERFLOW_READ_THRESHHOLD (0xA00)#endif // UDF_DBG#else // defined(_M_IX86)#define OVERFLOW_READ_THRESHHOLD (0x1000)#endif // defined(_M_IX86)
//#define POST_LOCK_PAGES
/*************************************************************************** Function: UDFRead()** Description:* The I/O Manager will invoke this routine to handle a read* request** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution* to be deferred to a worker thread context)** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSNTAPIUDFRead( PDEVICE_OBJECT DeviceObject, // the logical volume device object PIRP Irp) // I/O Request Packet{ NTSTATUS RC = STATUS_SUCCESS; PtrUDFIrpContext PtrIrpContext = NULL; BOOLEAN AreWeTopLevel = FALSE;
TmPrint(("UDFRead: \n"));
FsRtlEnterFileSystem(); ASSERT(DeviceObject); ASSERT(Irp);
// set the top level context AreWeTopLevel = UDFIsIrpTopLevel(Irp); ASSERT(!UDFIsFSDevObj(DeviceObject));
_SEH2_TRY {
// get an IRP context structure and issue the request PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); if(PtrIrpContext) { RC = UDFCommonRead(PtrIrpContext, Irp); } else { RC = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = RC; Irp->IoStatus.Information = 0; // complete the IRP IoCompleteRequest(Irp, IO_DISK_INCREMENT); }
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); } _SEH2_END;
if (AreWeTopLevel) { IoSetTopLevelIrp(NULL); }
FsRtlExitFileSystem();
return(RC);} // end UDFRead()
/*************************************************************************** Function: UDFPostStackOverflowRead()** Description:* Post a read request that could not be processed by* the fsp thread because of stack overflow potential.** Arguments:* Irp - Supplies the request to process.* Fcb - Supplies the file.** Return Value: STATUS_PENDING.**************************************************************************/NTSTATUSUDFPostStackOverflowRead( IN PtrUDFIrpContext PtrIrpContext, IN PIRP Irp, IN PtrUDFFCB Fcb ){ PKEVENT Event; PERESOURCE Resource;
UDFPrint(("Getting too close to stack limit pass request to Fsp\n"));
// Allocate an event and get shared on the resource we will // be later using the common read. Event = (PKEVENT)MyAllocatePool__(NonPagedPool, sizeof(KEVENT)); if(!Event) return STATUS_INSUFFICIENT_RESOURCES; KeInitializeEvent( Event, NotificationEvent, FALSE );
if ((Irp->Flags & IRP_PAGING_IO) && (Fcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource)) { Resource = Fcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource; } else { Resource = Fcb->NTRequiredFCB->CommonFCBHeader.Resource; }
UDFAcquireResourceShared( Resource, TRUE );
_SEH2_TRY { // If this read is the result of a verify, we have to // tell the overflow read routne to temporarily // hijack the Vcb->VerifyThread field so that reads // can go through. FsRtlPostStackOverflow(PtrIrpContext, Event, UDFStackOverflowRead); // And wait for the worker thread to complete the item DbgWaitForSingleObject(Event, NULL);
} _SEH2_FINALLY {
UDFReleaseResource( Resource ); MyFreePool__( Event ); } _SEH2_END;
return STATUS_PENDING;
} // end UDFPostStackOverflowRead()
/*************************************************************************** Function: UDFStackOverflowRead()** Description:* Process a read request that could not be processed by* the fsp thread because of stack overflow potential.** Arguments:* Context - Supplies the IrpContext being processed* Event - Supplies the event to be signaled when we are done processing this* request.** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: None.**************************************************************************/VOIDNTAPIUDFStackOverflowRead( IN PVOID Context, IN PKEVENT Event ){ PtrUDFIrpContext PtrIrpContext = (PtrUDFIrpContext)Context; NTSTATUS RC;
UDFPrint(("UDFStackOverflowRead: \n")); // Make it now look like we can wait for I/O to complete PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
// Do the read operation protected by a try-except clause _SEH2_TRY { UDFCommonRead(PtrIrpContext, PtrIrpContext->Irp); } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { RC = UDFExceptionHandler(PtrIrpContext, PtrIrpContext->Irp); UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); } _SEH2_END;
// Set the stack overflow item's event to tell the original // thread that we're done. KeSetEvent( Event, 0, FALSE );} // end UDFStackOverflowRead()
/*************************************************************************** Function: UDFCommonRead()** Description:* The actual work is performed here. This routine may be invoked in one* of the two possible contexts:* (a) in the context of a system worker thread* (b) in the context of the original caller** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSUDFCommonRead( PtrUDFIrpContext PtrIrpContext, PIRP Irp ){ NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = NULL; LARGE_INTEGER ByteOffset; ULONG ReadLength = 0, TruncatedLength = 0; SIZE_T NumberBytesRead = 0; PFILE_OBJECT FileObject = NULL; PtrUDFFCB Fcb = NULL; PtrUDFCCB Ccb = NULL; PVCB Vcb = NULL; PtrUDFNTRequiredFCB NtReqFcb = NULL; PERESOURCE PtrResourceAcquired = NULL; PERESOURCE PtrResourceAcquired2 = NULL; PVOID SystemBuffer = NULL; PIRP TopIrp;// uint32 KeyValue = 0;
ULONG Res1Acq = 0; ULONG Res2Acq = 0;
BOOLEAN CacheLocked = FALSE;
BOOLEAN CanWait = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN NonBufferedIo = FALSE; BOOLEAN SynchronousIo = FALSE;
TmPrint(("UDFCommonRead: irp %x\n", Irp));
_SEH2_TRY {
TopIrp = IoGetTopLevelIrp(); switch((ULONG_PTR)TopIrp) { case FSRTL_FSP_TOP_LEVEL_IRP: UDFPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n")); break; case FSRTL_CACHE_TOP_LEVEL_IRP: UDFPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n")); break; case FSRTL_MOD_WRITE_TOP_LEVEL_IRP: UDFPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n"));// BrutePoint() break; case FSRTL_FAST_IO_TOP_LEVEL_IRP: UDFPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n"));// BrutePoint() break; case NULL: UDFPrint((" NULL TOP_LEVEL_IRP\n")); break; default: if(TopIrp == Irp) { UDFPrint((" TOP_LEVEL_IRP\n")); } else { UDFPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp)); } break; } // First, get a pointer to the current I/O stack location IrpSp = IoGetCurrentIrpStackLocation(Irp); ASSERT(IrpSp); MmPrint((" Enter Irp, MDL=%x\n", Irp->MdlAddress)); if(Irp->MdlAddress) { UDFTouch(Irp->MdlAddress); }
// If this happens to be a MDL read complete request, then // there is not much processing that the FSD has to do. if (IrpSp->MinorFunction & IRP_MN_COMPLETE) { // Caller wants to tell the Cache Manager that a previously // allocated MDL can be freed. UDFMdlComplete(PtrIrpContext, Irp, IrpSp, TRUE); // The IRP has been completed. try_return(RC = STATUS_SUCCESS); }
// If this is a request at IRQL DISPATCH_LEVEL, then post // the request (your FSD may choose to process it synchronously // if you implement the support correctly; obviously you will be // quite constrained in what you can do at such IRQL). if (IrpSp->MinorFunction & IRP_MN_DPC) { try_return(RC = STATUS_PENDING); }
FileObject = IrpSp->FileObject; ASSERT(FileObject);
// Get the FCB and CCB pointers Ccb = (PtrUDFCCB)(FileObject->FsContext2); ASSERT(Ccb); Fcb = Ccb->Fcb; ASSERT(Fcb); Vcb = Fcb->Vcb;
if(Fcb->FCBFlags & UDF_FCB_DELETED) { ASSERT(FALSE); try_return(RC = STATUS_ACCESS_DENIED); }
// check for stack overflow if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) { RC = UDFPostStackOverflowRead( PtrIrpContext, Irp, Fcb ); try_return(RC); }
// Disk based file systems might decide to verify the logical volume // (if required and only if removable media are supported) at this time // As soon as Tray is locked, we needn't call UDFVerifyVcb()
ByteOffset = IrpSp->Parameters.Read.ByteOffset;
CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; PagingIo = (Irp->Flags & IRP_PAGING_IO) ? TRUE : FALSE; NonBufferedIo = (Irp->Flags & IRP_NOCACHE) ? TRUE : FALSE; SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE; UDFPrint((" Flags: %s %s %s %s\n", CanWait ? "W" : "w", PagingIo ? "Pg" : "pg", NonBufferedIo ? "NBuf" : "buff", SynchronousIo ? "Snc" : "Asc"));
if(!NonBufferedIo && (Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) { if(UDFIsAStream(Fcb->FileInfo)) { UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, FILE_NOTIFY_CHANGE_LAST_ACCESS, FILE_ACTION_MODIFIED_STREAM); } else { UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, FILE_NOTIFY_CHANGE_LAST_ACCESS, FILE_ACTION_MODIFIED); } }
// Get some of the parameters supplied to us ReadLength = IrpSp->Parameters.Read.Length; if (ReadLength == 0) { // a 0 byte read can be immediately succeeded try_return(RC); } UDFPrint((" ByteOffset = %I64x, ReadLength = %x\n", ByteOffset.QuadPart, ReadLength));
// Is this a read of the volume itself ? if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { // Yup, we need to send this on to the disk driver after // validation of the offset and length. Vcb = (PVCB)Fcb; Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; if(!CanWait) try_return(RC = STATUS_PENDING);
if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) {
UDFPrint((" UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED;
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); }#ifdef UDF_DELAYED_CLOSE UDFCloseAllDelayed(Vcb);#endif //UDF_DELAYED_CLOSE
}
if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH_REQUIRED) {
UDFPrint((" UDF_IRP_CONTEXT_FLUSH_REQUIRED\n")); PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH_REQUIRED;
// Acquire the volume resource exclusive UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); PtrResourceAcquired = &(Vcb->VCBResource);
UDFFlushLogicalVolume(NULL, NULL, Vcb, 0);
UDFReleaseResource(PtrResourceAcquired); PtrResourceAcquired = NULL; }
// Acquire the volume resource shared ... UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); PtrResourceAcquired = &(Vcb->VCBResource);
#if 0 if(PagingIo) { CollectStatistics(Vcb, MetaDataReads); CollectStatisticsEx(Vcb, MetaDataReadBytes, NumberBytesRead); }#endif
// Forward the request to the lower level driver // Lock the callers buffer if (!NT_SUCCESS(RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, ReadLength))) { try_return(RC); } SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); if(!SystemBuffer) { try_return(RC = STATUS_INVALID_USER_BUFFER); } if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) { RC = UDFReadData(Vcb, TRUE, ByteOffset.QuadPart, ReadLength, FALSE, (PCHAR)SystemBuffer, &NumberBytesRead); } else { RC = UDFTRead(Vcb, SystemBuffer, ReadLength, (ULONG)(ByteOffset.QuadPart >> Vcb->BlockSizeBits), &NumberBytesRead); } UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); try_return(RC); } Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
// If the read request is directed to a page file (if your FSD // supports paging files), send the request directly to the disk // driver. For requests directed to a page file, you have to trust // that the offsets will be set correctly by the VMM. You should not // attempt to acquire any FSD resources either. if(Fcb->FCBFlags & UDF_FCB_PAGE_FILE) { NonBufferedIo = TRUE; }
if(ByteOffset.HighPart == -1) { if(ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) { ByteOffset = FileObject->CurrentByteOffset; } }
// If this read is directed to a directory, it is not allowed // by the UDF FSD. if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { RC = STATUS_INVALID_DEVICE_REQUEST; try_return(RC); }
NtReqFcb = Fcb->NTRequiredFCB;
Res1Acq = UDFIsResourceAcquired(&(NtReqFcb->MainResource)); if(!Res1Acq) { Res1Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES1_ACQ; } Res2Acq = UDFIsResourceAcquired(&(NtReqFcb->PagingIoResource)); if(!Res2Acq) { Res2Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES2_ACQ; }
#if 0 if(PagingIo) { CollectStatistics(Vcb, UserFileReads); CollectStatisticsEx(Vcb, UserFileReadBytes, NumberBytesRead); }#endif
// This is a good place for oplock related processing.
// If this is the normal file we have to check for // write access according to the current state of the file locks. if (!PagingIo && !FsRtlCheckLockForReadAccess( &(NtReqFcb->FileLock), Irp )) { try_return( RC = STATUS_FILE_LOCK_CONFLICT ); }
// Validate start offset and length supplied. // If start offset is > end-of-file, return an appropriate error. Note // that since a FCB resource has already been acquired, and since all // file size changes require acquisition of both FCB resources, // the contents of the FCB and associated data structures // can safely be examined.
// Also note that we are using the file size in the "Common FCB Header" // to perform the check. However, your FSD might decide to keep a // separate copy in the FCB (or some other representation of the // file associated with the FCB).
TruncatedLength = ReadLength; if (ByteOffset.QuadPart >= NtReqFcb->CommonFCBHeader.FileSize.QuadPart) { // Starting offset is >= file size try_return(RC = STATUS_END_OF_FILE); } // We can also go ahead and truncate the read length here // such that it is contained within the file size if( NtReqFcb->CommonFCBHeader.FileSize.QuadPart < (ByteOffset.QuadPart + ReadLength) ) { TruncatedLength = (ULONG)(NtReqFcb->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart); // we can't get ZERO here } UDFPrint((" TruncatedLength = %x\n", TruncatedLength));
// There are certain complications that arise when the same file stream // has been opened for cached and non-cached access. The FSD is then // responsible for maintaining a consistent view of the data seen by // the caller. // Also, it is possible for file streams to be mapped in both as data files // and as an executable. This could also lead to consistency problems since // there now exist two separate sections (and pages) containing file // information.
// The test below flushes the data cached in system memory if the current // request madates non-cached access (file stream must be cached) and // (a) the current request is not paging-io which indicates it is not // a recursive I/O operation OR originating in the Cache Manager // (b) OR the current request is paging-io BUT it did not originate via // the Cache Manager (or is a recursive I/O operation) and we do // have an image section that has been initialized.#define UDF_REQ_NOT_VIA_CACHE_MGR(ptr) (!MmIsRecursiveIoFault() && ((ptr)->ImageSectionObject != NULL))
if(NonBufferedIo && (NtReqFcb->SectionObject.DataSectionObject != NULL)) { if(!PagingIo) {
/* // We hold the main resource exclusive here because the flush // may generate a recursive write in this thread. The PagingIo // resource is held shared so the drop-and-release serialization // below will work. if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { try_return(RC = STATUS_PENDING); } PtrResourceAcquired = &(NtReqFcb->MainResource);
// We hold PagingIo shared around the flush to fix a // cache coherency problem. UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), TRUE );*/
MmPrint((" CcFlushCache()\n")); CcFlushCache(&(NtReqFcb->SectionObject), &ByteOffset, TruncatedLength, &(Irp->IoStatus));
/* UDFReleaseResource(&(NtReqFcb->PagingIoResource)); UDFReleaseResource(PtrResourceAcquired); PtrResourceAcquired = NULL; // If the flush failed, return error to the caller if(!NT_SUCCESS(RC = Irp->IoStatus.Status)) { try_return(RC); }
// Acquiring and immediately dropping the resource serializes // us behind any other writes taking place (either from the // lazy writer or modified page writer).*/ if(!Res2Acq) { UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE ); UDFReleaseResource(&(NtReqFcb->PagingIoResource)); } } }
// Acquire the appropriate FCB resource shared if (PagingIo) { // Try to acquire the FCB PagingIoResource shared if(!Res2Acq) { if (!UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), CanWait)) { try_return(RC = STATUS_PENDING); } // Remember the resource that was acquired PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); } } else { // Try to acquire the FCB MainResource shared if(NonBufferedIo) { if(!Res2Acq) { if(!UDFAcquireSharedWaitForExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { try_return(RC = STATUS_PENDING); } PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); } } else { if(!Res1Acq) { UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { try_return(RC = STATUS_PENDING); } // Remember the resource that was acquired PtrResourceAcquired = &(NtReqFcb->MainResource); } } }
// This is also a good place to set whether fast-io can be performed // on this particular file or not. Your FSD must make it's own // determination on whether or not to allow fast-io operations. // Commonly, fast-io is not allowed if any byte range locks exist // on the file or if oplocks prevent fast-io. Practically any reason // choosen by your FSD could result in your setting FastIoIsNotPossible // OR FastIoIsQuestionable instead of FastIoIsPossible.
NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);/* if(NtReqFcb->CommonFCBHeader.IsFastIoPossible == FastIoIsPossible) NtReqFcb->CommonFCBHeader.IsFastIoPossible = FastIoIsQuestionable;*/
#ifdef UDF_DISABLE_SYSTEM_CACHE_MANAGER NonBufferedIo = TRUE;#endif
if(Fcb && Fcb->FileInfo && Fcb->FileInfo->Dloc) { AdPrint(("UDFCommonRead: DataLoc %x, Mapping %x\n", &Fcb->FileInfo->Dloc->DataLoc, Fcb->FileInfo->Dloc->DataLoc.Mapping)); }
// Branch here for cached vs non-cached I/O if (!NonBufferedIo) {
if(FileObject->Flags & FO_WRITE_THROUGH) { CanWait = TRUE; } // The caller wishes to perform cached I/O. Initiate caching if // this is the first cached I/O operation using this file object if (!(FileObject->PrivateCacheMap)) { // This is the first cached I/O operation. You must ensure // that the FCB Common FCB Header contains valid sizes at this time MmPrint((" CcInitializeCacheMap()\n")); CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)(&(NtReqFcb->CommonFCBHeader.AllocationSize)), FALSE, // We will not utilize pin access for this file &(UDFGlobalData.CacheMgrCallBacks), // callbacks NtReqFcb); // The context used in callbacks MmPrint((" CcSetReadAheadGranularity()\n")); CcSetReadAheadGranularity(FileObject, Vcb->SystemCacheGran); }
// Check and see if this request requires a MDL returned to the caller if (IrpSp->MinorFunction & IRP_MN_MDL) { // Caller does want a MDL returned. Note that this mode // implies that the caller is prepared to block MmPrint((" CcMdlRead()\n"));// CcMdlRead(FileObject, &ByteOffset, TruncatedLength, &(Irp->MdlAddress), &(Irp->IoStatus));// NumberBytesRead = Irp->IoStatus.Information;// RC = Irp->IoStatus.Status; NumberBytesRead = 0; RC = STATUS_INVALID_PARAMETER;
try_return(RC); }
// This is a regular run-of-the-mill cached I/O request. Let the // Cache Manager worry about it! // First though, we need a buffer pointer (address) that is valid SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); if(!SystemBuffer) try_return(RC = STATUS_INVALID_USER_BUFFER); ASSERT(SystemBuffer); MmPrint((" CcCopyRead()\n")); if (!CcCopyRead(FileObject, &(ByteOffset), TruncatedLength, CanWait, SystemBuffer, &(Irp->IoStatus))) { // The caller was not prepared to block and data is not immediately // available in the system cache try_return(RC = STATUS_PENDING); }
UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); // We have the data RC = Irp->IoStatus.Status; NumberBytesRead = Irp->IoStatus.Information;
try_return(RC);
} else {
MmPrint((" Read NonBufferedIo\n"));
#if 1 if((ULONG_PTR)TopIrp == FSRTL_MOD_WRITE_TOP_LEVEL_IRP) { UDFPrint(("FSRTL_MOD_WRITE_TOP_LEVEL_IRP => CanWait\n")); CanWait = TRUE; } else if((ULONG_PTR)TopIrp == FSRTL_CACHE_TOP_LEVEL_IRP) { UDFPrint(("FSRTL_CACHE_TOP_LEVEL_IRP => CanWait\n")); CanWait = TRUE; }
if(NtReqFcb->AcqSectionCount || NtReqFcb->AcqFlushCount) { MmPrint((" AcqCount (%d/%d)=> CanWait ?\n", NtReqFcb->AcqSectionCount, NtReqFcb->AcqFlushCount)); CanWait = TRUE; } else {}/* if((TopIrp != Irp)) { UDFPrint(("(TopIrp != Irp) => CanWait\n")); CanWait = TRUE; } else*/#endif if(KeGetCurrentIrql() > PASSIVE_LEVEL) { MmPrint((" !PASSIVE_LEVEL\n")); CanWait = FALSE; PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FORCED_POST; } if(!CanWait && UDFIsFileCached__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, FALSE)) { MmPrint((" Locked => CanWait\n")); CacheLocked = TRUE; CanWait = TRUE; }
// Send the request to lower level drivers if(!CanWait) { try_return(RC = STATUS_PENDING); }
// ASSERT(NT_SUCCESS(RC)); if(!Res2Acq) { if(UDFAcquireResourceSharedWithCheck(&(NtReqFcb->PagingIoResource))) PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); }
RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, TruncatedLength); if(!NT_SUCCESS(RC)) { try_return(RC); }
SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); if(!SystemBuffer) { try_return(RC = STATUS_INVALID_USER_BUFFER); }
RC = UDFReadFile__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, CacheLocked, (PCHAR)SystemBuffer, &NumberBytesRead);/* // AFAIU, CacheManager wants this: if(!NT_SUCCESS(RC)) { NumberBytesRead = 0; }*/
UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer);
#if 0 if(PagingIo) { CollectStatistics(Vcb, UserDiskReads); } else { CollectStatistics2(Vcb, NonCachedDiskReads); }#endif
try_return(RC);
// For paging-io, the FSD has to trust the VMM to do the right thing
// Here is a common method used by Windows NT native file systems // that are in the process of sending a request to the disk driver. // First, mark the IRP as pending, then invoke the lower level driver // after setting a completion routine. // Meanwhile, this particular thread can immediately return a // STATUS_PENDING return code. // The completion routine is then responsible for completing the IRP // and unlocking appropriate resources
// Also, at this point, the FSD might choose to utilize the // information contained in the ValidDataLength field to simply // return zeroes to the caller for reads extending beyond current // valid data length.
}
try_exit: NOTHING;
} _SEH2_FINALLY {
if(CacheLocked) { WCacheEODirect__(&(Vcb->FastCache), Vcb); }
// Release any resources acquired here ... if(PtrResourceAcquired2) { UDFReleaseResource(PtrResourceAcquired2); } if(PtrResourceAcquired) { if(NtReqFcb && (PtrResourceAcquired == &(NtReqFcb->MainResource))) { UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); } UDFReleaseResource(PtrResourceAcquired); }
// Post IRP if required if(RC == STATUS_PENDING) {
// Lock the callers buffer here. Then invoke a common routine to // perform the post operation. if (!(IrpSp->MinorFunction & IRP_MN_MDL)) { RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, ReadLength); ASSERT(NT_SUCCESS(RC)); } if(PagingIo) { if(Res1Acq) { PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES1_ACQ; } if(Res2Acq) { PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES2_ACQ; } } // Perform the post operation which will mark the IRP pending // and will return STATUS_PENDING back to us RC = UDFPostRequest(PtrIrpContext, Irp);
} else { // For synchronous I/O, the FSD must maintain the current byte offset // Do not do this however, if I/O is marked as paging-io if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + NumberBytesRead; } // If the read completed successfully and this was not a paging-io // operation, set a flag in the CCB that indicates that a read was // performed and that the file time should be updated at cleanup if (NT_SUCCESS(RC) && !PagingIo) { FileObject->Flags |= FO_FILE_FAST_IO_READ; Ccb->CCBFlags |= UDF_CCB_ACCESSED; }
if(!_SEH2_AbnormalTermination()) { Irp->IoStatus.Status = RC; Irp->IoStatus.Information = NumberBytesRead; UDFPrint((" NumberBytesRead = %x\n", NumberBytesRead)); // Free up the Irp Context UDFReleaseIrpContext(PtrIrpContext); // complete the IRP MmPrint((" Complete Irp, MDL=%x\n", Irp->MdlAddress)); if(Irp->MdlAddress) { UDFTouch(Irp->MdlAddress); } IoCompleteRequest(Irp, IO_DISK_INCREMENT); } } // can we complete the IRP ? } _SEH2_END; // end of "__finally" processing
return(RC);} // end UDFCommonRead()
#ifdef UDF_DBGULONG LockBufferCounter = 0;ULONG BuildMdlCounter = 0;#endif //UDF_DBG
/*************************************************************************** Function: UDFGetCallersBuffer()** Description:* Obtain a pointer to the caller's buffer.** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/PVOIDUDFGetCallersBuffer( PtrUDFIrpContext PtrIrpContext, PIRP Irp ){ VOID *ReturnedBuffer = NULL;
UDFPrint(("UDFGetCallersBuffer: \n"));
// If an MDL is supplied, use it. if(Irp->MdlAddress) { MmPrint((" UDFGetCallersBuffer: MmGetSystemAddressForMdl(Irp->MdlAddress) MDL=%x\n", Irp->MdlAddress));// ReturnedBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); ReturnedBuffer = MmGetSystemAddressForMdlSafer(Irp->MdlAddress); } else if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_BUFFER_LOCKED) { // Free buffer#ifndef POST_LOCK_PAGES MmPrint((" UDFGetCallersBuffer: MmGetSystemAddressForMdl(PtrIrpContext->PtrMdl) MDL=%x\n", PtrIrpContext->PtrMdl)); ReturnedBuffer = MmGetSystemAddressForMdlSafe(PtrIrpContext->PtrMdl, NormalPagePriority);#else //POST_LOCK_PAGES if(PtrIrpContext->TransitionBuffer) { MmPrint((" UDFGetCallersBuffer: TransitionBuffer\n")); return PtrIrpContext->TransitionBuffer; }
_SEH2_TRY { MmPrint((" MmProbeAndLockPages()\n")); MmProbeAndLockPages(PtrIrpContext->PtrMdl, Irp->RequestorMode, ((PtrIrpContext->MajorFunction == IRP_MJ_READ) ? IoWriteAccess:IoReadAccess));#ifdef UDF_DBG LockBufferCounter++;#endif //UDF_DBG } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { //RC = STATUS_INVALID_USER_BUFFER; BrutePoint(); return NULL; } _SEH2_END;
MmPrint((" MmGetSystemAddressForMdlSafer()\n")); ReturnedBuffer = MmGetSystemAddressForMdlSafer(PtrIrpContext->PtrMdl);#endif //POST_LOCK_PAGES } else { MmPrint((" UDFGetCallersBuffer: Irp->UserBuffer\n")); ReturnedBuffer = Irp->UserBuffer; }
return(ReturnedBuffer);} // end UDFGetCallersBuffer()
/*************************************************************************** Function: UDFLockCallersBuffer()** Description:* Obtain a MDL that describes the buffer. Lock pages for I/O** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSUDFLockCallersBuffer( PtrUDFIrpContext PtrIrpContext, PIRP Irp, BOOLEAN IsReadOperation, uint32 Length ){ NTSTATUS RC = STATUS_SUCCESS; PMDL PtrMdl = NULL;
UDFPrint(("UDFLockCallersBuffer: \n"));
ASSERT(Irp);
_SEH2_TRY { // Is a MDL already present in the IRP if (!(Irp->MdlAddress)) { // Allocate a MDL/* if(!IsReadOperation) { MmPrint((" Allocate TransitionBuffer\n")); PtrIrpContext->TransitionBuffer = (PCHAR)DbgAllocatePool(NonPagedPool, Length); if(!PtrIrpContext->TransitionBuffer) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(RC); } _SEH2_TRY { RtlCopyMemory(PtrIrpContext->TransitionBuffer, Irp->UserBuffer, Length); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { RC = STATUS_INVALID_USER_BUFFER; } _SEH2_END; } else*/ {
MmPrint((" IoAllocateMdl()\n"));// if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, NULL))) {
// This will place allocated Mdl to Irp if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp))) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(RC); } MmPrint((" Alloc MDL=%x\n", PtrMdl));#ifdef UDF_DBG BuildMdlCounter++;#endif //UDF_DBG } // Probe and lock the pages described by the MDL // We could encounter an exception doing so, swallow the exception // NOTE: The exception could be due to an unexpected (from our // perspective), invalidation of the virtual addresses that comprise // the passed in buffer#ifndef POST_LOCK_PAGES _SEH2_TRY { MmPrint((" MmProbeAndLockPages()\n")); MmProbeAndLockPages(PtrMdl, Irp->RequestorMode, (IsReadOperation ? IoWriteAccess:IoReadAccess)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { MmPrint((" MmProbeAndLockPages() failed\n")); Irp->MdlAddress = NULL; RC = STATUS_INVALID_USER_BUFFER; } _SEH2_END;#endif //POST_LOCK_PAGES
if(NT_SUCCESS(RC)) { PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_BUFFER_LOCKED; PtrIrpContext->PtrMdl = PtrMdl; } } else { MmPrint((" UDFLockCallersBuffer: do nothing, MDL=%x\n", Irp->MdlAddress)); UDFTouch(Irp->MdlAddress); }
try_exit: NOTHING;
} _SEH2_FINALLY { if (!NT_SUCCESS(RC) && PtrMdl) { MmPrint((" Free MDL=%x\n", PtrMdl)); IoFreeMdl(PtrMdl); } } _SEH2_END;
return(RC);} // end UDFLockCallersBuffer()
/*************************************************************************** Function: UDFUnlockCallersBuffer()** Description:* Obtain a MDL that describes the buffer. Lock pages for I/O** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSUDFUnlockCallersBuffer( PtrUDFIrpContext PtrIrpContext, PIRP Irp, PVOID SystemBuffer ){ NTSTATUS RC = STATUS_SUCCESS;
UDFPrint(("UDFUnlockCallersBuffer: \n"));
ASSERT(Irp);
_SEH2_TRY { // Is a nonPaged buffer already present in the IRP if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_BUFFER_LOCKED) {
UDFPrint((" UDF_IRP_CONTEXT_BUFFER_LOCKED MDL=%x, Irp MDL=%x\n", PtrIrpContext->PtrMdl, Irp->MdlAddress)); if(PtrIrpContext->TransitionBuffer) { MmPrint((" UDFUnlockCallersBuffer: free TransitionBuffer\n")); DbgFreePool(PtrIrpContext->TransitionBuffer); PtrIrpContext->TransitionBuffer = NULL; PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_BUFFER_LOCKED; try_return(RC); } // Free buffer KeFlushIoBuffers( PtrIrpContext->PtrMdl, TRUE, FALSE );// MmPrint((" IrpCtx->Mdl, MmUnmapLockedPages()\n"));// MmUnmapLockedPages(SystemBuffer, PtrIrpContext->PtrMdl);
// This will be done in IoCompleteIrp !!!
//MmPrint((" MmUnlockPages()\n")); //MmUnlockPages(PtrIrpContext->PtrMdl);
#ifdef UDF_DBG LockBufferCounter--;#endif //UDF_DBG
// This will be done in IoCompleteIrp !!!
//IoFreeMdl(PtrIrpContext->PtrMdl);
#ifdef UDF_DBG BuildMdlCounter--;#endif //UDF_DBG UDFTouch(PtrIrpContext->PtrMdl); PtrIrpContext->PtrMdl = NULL; PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_BUFFER_LOCKED; } else if(Irp->MdlAddress) {// MmPrint((" Irp->Mdl, MmUnmapLockedPages()\n"));// MmUnmapLockedPages(SystemBuffer, Irp->MdlAddress); UDFPrint((" UDF_IRP_CONTEXT_BUFFER_LOCKED MDL=%x, Irp MDL=%x\n", PtrIrpContext->PtrMdl, Irp->MdlAddress)); UDFTouch(Irp->MdlAddress); KeFlushIoBuffers( Irp->MdlAddress, ((IoGetCurrentIrpStackLocation(Irp))->MajorFunction) == IRP_MJ_READ, FALSE ); } else { ; }
try_exit: NOTHING;
} _SEH2_FINALLY { NOTHING; } _SEH2_END;
return(RC);} // end UDFUnlockCallersBuffer()
/*************************************************************************** Function: UDFMdlComplete()** Description:* Tell Cache Manager to release MDL (and possibly flush).** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: None.**************************************************************************/VOID UDFMdlComplete(PtrUDFIrpContext PtrIrpContext,PIRP Irp,PIO_STACK_LOCATION IrpSp,BOOLEAN ReadCompletion){ NTSTATUS RC = STATUS_SUCCESS; PFILE_OBJECT FileObject = NULL;
UDFPrint(("UDFMdlComplete: \n"));
FileObject = IrpSp->FileObject; ASSERT(FileObject);
UDFTouch(Irp->MdlAddress); // Not much to do here. if (ReadCompletion) { MmPrint((" CcMdlReadComplete() MDL=%x\n", Irp->MdlAddress)); CcMdlReadComplete(FileObject, Irp->MdlAddress); } else { // The Cache Manager needs the byte offset in the I/O stack location. MmPrint((" CcMdlWriteComplete() MDL=%x\n", Irp->MdlAddress)); CcMdlWriteComplete(FileObject, &(IrpSp->Parameters.Write.ByteOffset), Irp->MdlAddress); }
// Clear the MDL address field in the IRP so the IoCompleteRequest() // does not __try to play around with the MDL. Irp->MdlAddress = NULL;
// Free up the Irp Context. UDFReleaseIrpContext(PtrIrpContext);
// Complete the IRP. Irp->IoStatus.Status = RC; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return;}