You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1373 lines
42 KiB
1373 lines
42 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Read.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the File Read routine for Read called by the
|
|
dispatch driver.
|
|
|
|
Author:
|
|
|
|
Joe Linn [JoeLinn] 11-Oct-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_READ)
|
|
|
|
//
|
|
// The following procedures are the handle the procedureal interface with lowio.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
RxLowIoReadShell (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
);
|
|
|
|
NTSTATUS
|
|
RxLowIoReadShellCompletion (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
#if DBG
|
|
VOID CheckForLoudOperations (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PFCB Fcb
|
|
);
|
|
#else
|
|
#define CheckForLoudOperations(___r)
|
|
#endif
|
|
|
|
//
|
|
// This macro just puts a nice little try-except around RtlZeroMemory
|
|
//
|
|
|
|
#define SafeZeroMemory(AT,BYTE_COUNT) { \
|
|
try { \
|
|
RtlZeroMemory((AT), (BYTE_COUNT)); \
|
|
} except(EXCEPTION_EXECUTE_HANDLER) { \
|
|
RxRaiseStatus( RxContext, STATUS_INVALID_USER_BUFFER ); \
|
|
} \
|
|
}
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RxStackOverflowRead)
|
|
#pragma alloc_text(PAGE, RxPostStackOverflowRead)
|
|
#pragma alloc_text(PAGE, RxCommonRead)
|
|
#pragma alloc_text(PAGE, RxLowIoReadShellCompletion)
|
|
#pragma alloc_text(PAGE, RxLowIoReadShell)
|
|
#if DBG
|
|
#pragma alloc_text(PAGE, CheckForLoudOperations)
|
|
#endif //DBG
|
|
#endif
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
NTSTATUS
|
|
RxPostStackOverflowRead (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PFCB Fcb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine posts a read request that could not be processed by
|
|
the fsp thread because of stack overflow potential.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the usual
|
|
|
|
Return Value:
|
|
|
|
RxStatus(PENDING).
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP Irp = RxContext->CurrentIrp;
|
|
|
|
KEVENT Event;
|
|
PERESOURCE Resource;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( 0, Dbg, ("Getting too close to stack limit pass request to Fsp\n", 0 ) );
|
|
|
|
//
|
|
// Initialize the event
|
|
//
|
|
|
|
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
|
|
|
if (FlagOn( Irp->Flags, IRP_PAGING_IO ) && (Fcb->Header.PagingIoResource != NULL)) {
|
|
|
|
Resource = Fcb->Header.PagingIoResource;
|
|
|
|
} else {
|
|
|
|
Resource = Fcb->Header.Resource;
|
|
}
|
|
|
|
ExAcquireResourceSharedLite( Resource, TRUE );
|
|
|
|
try {
|
|
|
|
//
|
|
// Make the Irp just like a regular post request and
|
|
// then send the Irp to the special overflow thread.
|
|
// After the post we will wait for the stack overflow
|
|
// read routine to set the event so that we can
|
|
// then release the fcb resource and return.
|
|
//
|
|
|
|
RxPrePostIrp( RxContext, Irp );
|
|
|
|
FsRtlPostStackOverflow( RxContext, &Event, RxStackOverflowRead );
|
|
|
|
//
|
|
// And wait for the worker thread to complete the item
|
|
//
|
|
|
|
(VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
|
|
|
|
} finally {
|
|
|
|
ExReleaseResourceLite( Resource );
|
|
}
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
VOID
|
|
RxStackOverflowRead (
|
|
IN PVOID Context,
|
|
IN PKEVENT Event
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a read request that could not be processed by
|
|
the fsp thread because of stack overflow potential.
|
|
|
|
Arguments:
|
|
|
|
Context - the RxContext being processed
|
|
|
|
Event - the event to be signaled when we've finished this request.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRX_CONTEXT RxContext = Context;
|
|
PIRP Irp = RxContext->CurrentIrp;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Make it now look like we can wait for I/O to complete
|
|
//
|
|
|
|
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
|
|
|
|
//
|
|
// Do the read operation protected by a try-except clause
|
|
//
|
|
|
|
try {
|
|
|
|
(VOID) RxCommonRead( RxContext, Irp );
|
|
|
|
} except(RxExceptionFilter( RxContext, GetExceptionInformation() )) {
|
|
|
|
NTSTATUS ExceptionCode;
|
|
|
|
//
|
|
// We had some trouble trying to perform the requested
|
|
// operation, so we'll abort the I/O request with the
|
|
// error status that we get back from the execption code
|
|
|
|
ExceptionCode = GetExceptionCode();
|
|
|
|
if (ExceptionCode == STATUS_FILE_DELETED) {
|
|
|
|
RxContext->StoredStatus = ExceptionCode = STATUS_END_OF_FILE;
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
(VOID) RxProcessException( RxContext, ExceptionCode );
|
|
}
|
|
|
|
//
|
|
// Signal the original thread that we're done.
|
|
|
|
KeSetEvent( Event, 0, FALSE );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxCommonRead (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common read routine for NtReadFile, called from both
|
|
the Fsd, or from the Fsp if a request could not be completed without
|
|
blocking in the Fsd. This routine has no code where it determines
|
|
whether it is running in the Fsd or Fsp. Instead, its actions are
|
|
conditionalized by the Wait input parameter, which determines whether
|
|
it is allowed to block or not. If a blocking condition is encountered
|
|
with Wait == FALSE, however, the request is posted to the Fsp, who
|
|
always calls with WAIT == TRUE.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the Irp to process
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
PFCB Fcb;
|
|
PFOBX Fobx;
|
|
PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
|
|
|
|
NODE_TYPE_CODE TypeOfOpen;
|
|
|
|
LARGE_INTEGER StartingByte;
|
|
RXVBO StartingVbo;
|
|
ULONG ByteCount;
|
|
|
|
ULONG CapturedRxContextSerialNumber = RxContext->SerialNumber;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
BOOLEAN PostIrp = FALSE;
|
|
|
|
BOOLEAN FcbAcquired = FALSE;
|
|
BOOLEAN RefdContextForTracker = FALSE;
|
|
|
|
BOOLEAN Wait;
|
|
BOOLEAN PagingIo;
|
|
BOOLEAN NonCachedIo;
|
|
BOOLEAN SynchronousIo;
|
|
|
|
PNET_ROOT NetRoot;
|
|
BOOLEAN PipeRead;
|
|
BOOLEAN BlockingResume = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME );
|
|
BOOLEAN fSetResourceOwner = FALSE;
|
|
BOOLEAN InFsp = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
TypeOfOpen = RxDecodeFileObject( FileObject, &Fcb, &Fobx );
|
|
NetRoot = (PNET_ROOT)Fcb->NetRoot;
|
|
|
|
//
|
|
// Initialize the local decision variables.
|
|
//
|
|
|
|
PipeRead = (BOOLEAN)(NetRoot->Type == NET_ROOT_PIPE);
|
|
Wait = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
|
|
PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
|
|
NonCachedIo = BooleanFlagOn( Irp->Flags,IRP_NOCACHE );
|
|
SynchronousIo = !BooleanFlagOn( RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION );
|
|
InFsp = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP );
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxCommonRead...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
|
|
RxContext, Fobx, Fcb ));
|
|
RxDbgTrace( 0, Dbg, (" ->ByteCount = %08lx, ByteOffset = %08lx %lx\n",
|
|
IrpSp->Parameters.Read.Length,
|
|
IrpSp->Parameters.Read.ByteOffset.LowPart,
|
|
IrpSp->Parameters.Read.ByteOffset.HighPart) );
|
|
RxDbgTrace( 0, Dbg,(" ->%s%s%s%s\n",
|
|
Wait ?"Wait ":"",
|
|
PagingIo ?"PagingIo ":"",
|
|
NonCachedIo ?"NonCachedIo ":"",
|
|
SynchronousIo ?"SynchronousIo ":"") );
|
|
|
|
RxLog(( "CommonRead %lx %lx %lx\n", RxContext, Fobx, Fcb ));
|
|
RxWmiLog( LOG,
|
|
RxCommonRead_1,
|
|
LOGPTR( RxContext )
|
|
LOGPTR( Fobx )
|
|
LOGPTR( Fcb ) );
|
|
RxLog(( " read %lx@%lx %lx %s%s%s%s\n",
|
|
IrpSp->Parameters.Read.Length,
|
|
IrpSp->Parameters.Read.ByteOffset.LowPart,
|
|
IrpSp->Parameters.Read.ByteOffset.HighPart,
|
|
Wait?"Wt":"",
|
|
PagingIo?"Pg":"",
|
|
NonCachedIo?"Nc":"",
|
|
SynchronousIo?"Sync":"" ));
|
|
RxWmiLog( LOG,
|
|
RxCommonRead_2,
|
|
LOGULONG( IrpSp->Parameters.Read.Length )
|
|
LOGULONG( IrpSp->Parameters.Read.ByteOffset.LowPart )
|
|
LOGULONG( IrpSp->Parameters.Read.ByteOffset.HighPart )
|
|
LOGUCHAR( Wait )
|
|
LOGUCHAR( PagingIo )
|
|
LOGUCHAR( NonCachedIo )
|
|
LOGUCHAR( SynchronousIo ) );
|
|
|
|
RxItsTheSameContext();
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Extract starting Vbo and offset.
|
|
//
|
|
|
|
StartingByte = IrpSp->Parameters.Read.ByteOffset;
|
|
StartingVbo = StartingByte.QuadPart;
|
|
|
|
ByteCount = IrpSp->Parameters.Read.Length;
|
|
|
|
#if DBG
|
|
|
|
CheckForLoudOperations( RxContext, Fcb );
|
|
|
|
if (FlagOn( LowIoContext->Flags,LOWIO_CONTEXT_FLAG_LOUDOPS )){
|
|
DbgPrint( "LoudRead %lx/%lx on %lx vdl/size/alloc %lx/%lx/%lx\n",
|
|
StartingByte.LowPart,ByteCount,Fcb,
|
|
Fcb->Header.ValidDataLength.LowPart,
|
|
Fcb->Header.FileSize.LowPart,
|
|
Fcb->Header.AllocationSize.LowPart );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Statistics............
|
|
//
|
|
|
|
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP ) &&
|
|
(Fcb->CachedNetRootType == NET_ROOT_DISK)) {
|
|
|
|
InterlockedIncrement( &RxDeviceObject->ReadOperations );
|
|
|
|
if (StartingVbo != Fobx->Specific.DiskFile.PredictedReadOffset) {
|
|
InterlockedIncrement( &RxDeviceObject->RandomReadOperations );
|
|
}
|
|
|
|
Fobx->Specific.DiskFile.PredictedReadOffset = StartingVbo + ByteCount;
|
|
|
|
if (PagingIo) {
|
|
ExInterlockedAddLargeStatistic( &RxDeviceObject->PagingReadBytesRequested, ByteCount );
|
|
} else if (NonCachedIo) {
|
|
ExInterlockedAddLargeStatistic( &RxDeviceObject->NonPagingReadBytesRequested, ByteCount );
|
|
} else {
|
|
ExInterlockedAddLargeStatistic( &RxDeviceObject->CacheReadBytesRequested, ByteCount );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for a null, invalid request, and return immediately
|
|
//
|
|
|
|
if (PipeRead && PagingIo) {
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
if (ByteCount == 0) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Get rid of invalid read requests right now.
|
|
//
|
|
|
|
if ((TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) &&
|
|
(TypeOfOpen != RDBSS_NTC_VOLUME_FCB)) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Invalid file object for read, type=%08lx\n", TypeOfOpen ));
|
|
RxDbgTrace( -1, Dbg, ("RxCommonRead: Exit -> %08lx\n", STATUS_INVALID_DEVICE_REQUEST ));
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// Initialize LowIO_CONTEXT block in the RxContext
|
|
//
|
|
|
|
RxInitializeLowIoContext( RxContext, LOWIO_OP_READ, LowIoContext );
|
|
|
|
//
|
|
// Use a try-finally to release Fcb and free buffers on the way out.
|
|
//
|
|
|
|
try {
|
|
|
|
//
|
|
// This case corresponds to a normal user read file.
|
|
//
|
|
|
|
LONGLONG FileSize;
|
|
LONGLONG ValidDataLength;
|
|
|
|
RxDbgTrace( 0, Dbg, ("Type of read is user file open, fcbstate is %08lx\n", Fcb->FcbState ));
|
|
|
|
//
|
|
// for stackoverflowreads, we will already have the pagingio resource shared as it's
|
|
// paging io. this doesn't cause a problem here....the resource is just acquired twice.
|
|
//
|
|
|
|
if ((NonCachedIo || !FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED )) &&
|
|
!PagingIo &&
|
|
(FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
|
|
|
|
//
|
|
// We hold the main resource exclusive here because the flush
|
|
// may generate a recursive write in this thread
|
|
//
|
|
|
|
Status = RxAcquireExclusiveFcb( RxContext, Fcb );
|
|
|
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|
|
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb for flush = %08lx excl without waiting - lock not granted\n",Fcb) );
|
|
try_return( PostIrp = TRUE );
|
|
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
|
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb = %08lx shared without waiting - other\n",Fcb) );
|
|
try_return( PostIrp = FALSE );
|
|
}
|
|
|
|
ExAcquireResourceSharedLite( Fcb->Header.PagingIoResource, TRUE );
|
|
|
|
CcFlushCache( FileObject->SectionObjectPointer,
|
|
&StartingByte,
|
|
ByteCount,
|
|
&Irp->IoStatus );
|
|
|
|
RxReleasePagingIoResource( RxContext, Fcb );
|
|
RxReleaseFcb( RxContext, Fcb );
|
|
|
|
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
try_return( Irp->IoStatus.Status );
|
|
}
|
|
|
|
RxAcquirePagingIoResource( RxContext, Fcb );
|
|
RxReleasePagingIoResource( RxContext, Fcb );
|
|
}
|
|
|
|
//
|
|
// We need shared access to the Fcb before proceeding.
|
|
//
|
|
|
|
if (PagingIo) {
|
|
|
|
ASSERT( !PipeRead );
|
|
|
|
if (!ExAcquireResourceSharedLite( Fcb->Header.PagingIoResource, Wait )) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", Fcb) );
|
|
try_return( PostIrp = TRUE );
|
|
}
|
|
|
|
if (!Wait) {
|
|
LowIoContext->Resource = Fcb->Header.PagingIoResource;
|
|
}
|
|
|
|
} else if (!BlockingResume) {
|
|
|
|
//
|
|
// If this is unbuffered async I/O we need to check that
|
|
// we don't exhaust the number of times a single thread can
|
|
// acquire the resource. Also, we will wait if there is an
|
|
// exclusive waiter.
|
|
//
|
|
|
|
if (!Wait && NonCachedIo) {
|
|
|
|
Status = RxAcquireSharedFcbWaitForEx( RxContext, Fcb );
|
|
|
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - lock not granted\n", Fcb) );
|
|
RxLog(( "RdAsyLNG %x\n", RxContext ));
|
|
RxWmiLog( LOG,
|
|
RxCommonRead_3,
|
|
LOGPTR( RxContext ) );
|
|
try_return( PostIrp = TRUE );
|
|
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - other\n", Fcb) );
|
|
RxLog(( "RdAsyOthr %x\n", RxContext ));
|
|
RxWmiLog( LOG,
|
|
RxCommonRead_4,
|
|
LOGPTR( RxContext ) );
|
|
try_return( PostIrp = FALSE );
|
|
}
|
|
|
|
if (ExIsResourceAcquiredSharedLite( Fcb->Header.Resource ) > MAX_FCB_ASYNC_ACQUIRE) {
|
|
|
|
FcbAcquired = TRUE;
|
|
try_return( PostIrp = TRUE );
|
|
}
|
|
|
|
LowIoContext->Resource = Fcb->Header.Resource;
|
|
|
|
} else {
|
|
|
|
Status = RxAcquireSharedFcb( RxContext, Fcb );
|
|
|
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - lock not granted\n", Fcb) );
|
|
try_return( PostIrp = TRUE );
|
|
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting - other\n", Fcb) );
|
|
try_return( PostIrp = FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
RxItsTheSameContext();
|
|
|
|
FcbAcquired = !BlockingResume;
|
|
|
|
//
|
|
// for pipe reads, bail out now. we avoid a goto by duplicating the calldown
|
|
//
|
|
|
|
if (PipeRead) {
|
|
|
|
//
|
|
// In order to prevent corruption on multi-threaded multi-block
|
|
// message mode pipe reads, we do this little dance with the fcb resource
|
|
//
|
|
|
|
if (!BlockingResume) {
|
|
|
|
if ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_MESSAGE_TYPE) ||
|
|
((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_BYTE_STREAM_TYPE) &&
|
|
!FlagOn( Fobx->Specific.NamedPipe.CompletionMode, FILE_PIPE_COMPLETE_OPERATION))) {
|
|
|
|
//
|
|
// Synchronization is effected here that will prevent other
|
|
// threads from coming in and reading from this file while the
|
|
// message pipe read is continuing.
|
|
//
|
|
// This is necessary because we will release the FCB lock while
|
|
// actually performing the I/O to allow open (and other) requests
|
|
// to continue on this file while the I/O is in progress.
|
|
//
|
|
|
|
RxDbgTrace( 0, Dbg, ("Message pipe read: Fobx: %lx, Fcb: %lx, Enqueuing...\n", Fobx, Fcb) );
|
|
|
|
Status = RxSynchronizeBlockingOperationsAndDropFcbLock( RxContext,
|
|
Fcb,
|
|
&Fobx->Specific.NamedPipe.ReadSerializationQueue );
|
|
|
|
RxItsTheSameContext();
|
|
|
|
FcbAcquired = FALSE;
|
|
|
|
if (!NT_SUCCESS( Status ) ||
|
|
(Status == STATUS_PENDING)) {
|
|
|
|
try_return( Status );
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("Succeeded: Fobx: %lx\n", Fobx) );
|
|
}
|
|
}
|
|
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
|
|
LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
|
|
SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION );
|
|
|
|
//
|
|
// Set the resource owner pointers (there is no PagingIoResource here !)
|
|
// if we are in FSP so that even if the FSP thread goes away, we dont run
|
|
// into issues with the resource package trying to boost the thread priority.
|
|
//
|
|
if( InFsp && FcbAcquired ) {
|
|
|
|
LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
|
|
ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId);
|
|
fSetResourceOwner = TRUE;
|
|
}
|
|
|
|
Status = RxLowIoReadShell( RxContext, Irp, Fcb );
|
|
|
|
try_return( Status );
|
|
}
|
|
|
|
RxGetFileSizeWithLock( Fcb, &FileSize );
|
|
ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
|
|
|
|
|
|
//
|
|
// We set the fastio state state to questionable
|
|
// at initialization time and answer the question in realtime
|
|
// this should be a policy so that local minis can do it this way
|
|
//
|
|
|
|
//
|
|
// We have to check for read access according to the current
|
|
// state of the file locks, and set FileSize from the Fcb.
|
|
//
|
|
|
|
if (!PagingIo &&
|
|
!FsRtlCheckLockForReadAccess( &Fcb->FileLock, Irp )) {
|
|
|
|
try_return( Status = STATUS_FILE_LOCK_CONFLICT );
|
|
}
|
|
|
|
|
|
//
|
|
// adjust the length if we know the eof...also, don't issue reads past the EOF
|
|
// if we know the eof
|
|
//
|
|
|
|
if (FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED )) {
|
|
|
|
//
|
|
// If the read starts beyond End of File, return EOF.
|
|
//
|
|
|
|
if (StartingVbo >= FileSize) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("End of File\n", 0 ) );
|
|
|
|
try_return ( Status = STATUS_END_OF_FILE );
|
|
}
|
|
|
|
//
|
|
// If the read extends beyond EOF, truncate the read
|
|
//
|
|
|
|
if (ByteCount > FileSize - StartingVbo) {
|
|
ByteCount = (ULONG)(FileSize - StartingVbo);
|
|
}
|
|
}
|
|
|
|
if (!PagingIo &&
|
|
!NonCachedIo && // this part is not discretionary
|
|
FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED ) &&
|
|
!FlagOn( Fobx->SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING )) {
|
|
|
|
//
|
|
// HANDLE CACHED CASE
|
|
//
|
|
// We delay setting up the file cache until now, in case the
|
|
// caller never does any I/O to the file, and thus
|
|
// FileObject->PrivateCacheMap == NULL.
|
|
//
|
|
|
|
if (FileObject->PrivateCacheMap == NULL) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Initialize cache mapping.\n", 0) );
|
|
|
|
//
|
|
// If this FileObject has gone through CleanUp, we cannot
|
|
// CcInitializeCacheMap it.
|
|
//
|
|
if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
|
|
Status = STATUS_FILE_CLOSED;
|
|
try_return( Status );
|
|
}
|
|
|
|
RxAdjustAllocationSizeforCC( Fcb );
|
|
|
|
//
|
|
// Now initialize the cache map.
|
|
//
|
|
|
|
try {
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
CcInitializeCacheMap( FileObject,
|
|
(PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
|
|
FALSE,
|
|
&RxData.CacheManagerCallbacks,
|
|
Fcb );
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
try_return( Status );
|
|
}
|
|
|
|
if (!FlagOn( Fcb->MRxDispatch->MRxFlags, RDBSS_NO_DEFERRED_CACHE_READAHEAD )) {
|
|
|
|
//
|
|
// Start out with read ahead disabled
|
|
//
|
|
|
|
CcSetAdditionalCacheAttributes( FileObject, TRUE, FALSE );
|
|
|
|
SetFlag( Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED );
|
|
|
|
} else {
|
|
|
|
//
|
|
// this mini doesn't want deferred readahead
|
|
//
|
|
|
|
CcSetAdditionalCacheAttributes( FileObject, FALSE, FALSE );
|
|
}
|
|
|
|
CcSetReadAheadGranularity( FileObject, NetRoot->DiskParameters.ReadAheadGranularity );
|
|
|
|
} else {
|
|
|
|
//
|
|
// if we have wandered off the first page and haven't started reading ahead
|
|
// then start now
|
|
//
|
|
|
|
if (FlagOn( Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED ) &&
|
|
(StartingVbo >= PAGE_SIZE)) {
|
|
|
|
CcSetAdditionalCacheAttributes( FileObject, FALSE, FALSE );
|
|
ClearFlag( Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED );
|
|
}
|
|
}
|
|
|
|
//
|
|
// DO A NORMAL CACHED READ, if the MDL bit is not set,
|
|
//
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cached read.\n", 0) );
|
|
|
|
if (!FlagOn( RxContext->MinorFunction, IRP_MN_MDL )) {
|
|
|
|
PVOID SystemBuffer;
|
|
|
|
#if DBG
|
|
ULONG SaveExceptionFlag;
|
|
#endif
|
|
|
|
//
|
|
// Get hold of the user's buffer.
|
|
//
|
|
|
|
SystemBuffer = RxMapUserBuffer( RxContext, Irp );
|
|
if (SystemBuffer == NULL) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
try_return( Status );
|
|
}
|
|
|
|
//
|
|
// Make sure that a returned exception clears the breakpoint in the filter
|
|
//
|
|
|
|
RxSaveAndSetExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
|
|
RxItsTheSameContext();
|
|
|
|
//
|
|
// Now try to do the copy.
|
|
//
|
|
|
|
if (!CcCopyRead( FileObject,
|
|
&StartingByte,
|
|
ByteCount,
|
|
Wait,
|
|
SystemBuffer,
|
|
&Irp->IoStatus )) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Cached Read could not wait\n", 0 ) );
|
|
RxRestoreExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
|
|
|
|
RxItsTheSameContext();
|
|
|
|
try_return( PostIrp = TRUE );
|
|
}
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
|
|
RxRestoreExceptionNoBreakpointFlag( RxContext, SaveExceptionFlag );
|
|
RxItsTheSameContext();
|
|
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
try_return( Status );
|
|
|
|
} else {
|
|
|
|
//
|
|
// HANDLE A MDL READ
|
|
//
|
|
|
|
RxDbgTrace(0, Dbg, ("MDL read.\n", 0));
|
|
|
|
ASSERT( FALSE ); // not yet ready for MDL reads
|
|
ASSERT( Wait );
|
|
|
|
CcMdlRead( FileObject,
|
|
&StartingByte,
|
|
ByteCount,
|
|
&Irp->MdlAddress,
|
|
&Irp->IoStatus );
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
try_return( Status );
|
|
}
|
|
}
|
|
|
|
//
|
|
// HANDLE THE NON-CACHED CASE
|
|
//
|
|
// Bt first, a ValidDataLength check.
|
|
//
|
|
// If the file in question is a disk file, and it is currently cached,
|
|
// and the read offset is greater than valid data length, then
|
|
// return 0s to the application.
|
|
//
|
|
|
|
if ((Fcb->CachedNetRootType == NET_ROOT_DISK) &&
|
|
FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED ) &&
|
|
(StartingVbo >= ValidDataLength)) {
|
|
|
|
//
|
|
// check if zeroing is really needed.
|
|
//
|
|
|
|
if (StartingVbo >= FileSize) {
|
|
ByteCount = 0;
|
|
} else {
|
|
|
|
PBYTE SystemBuffer;
|
|
|
|
//
|
|
// There is at least one byte available. Truncate
|
|
// the transfer length if it goes beyond EOF.
|
|
//
|
|
|
|
if (StartingVbo + ByteCount > FileSize) {
|
|
ByteCount = (ULONG)(FileSize - StartingVbo);
|
|
}
|
|
|
|
SystemBuffer = RxMapUserBuffer( RxContext, Irp );
|
|
SafeZeroMemory( SystemBuffer, ByteCount ); // this could raise!!
|
|
}
|
|
|
|
Irp->IoStatus.Information = ByteCount;
|
|
try_return( Status = STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
|
|
LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
|
|
|
|
RxItsTheSameContext();
|
|
|
|
//
|
|
// Set the resource owner pointers.
|
|
// if we are in FSP so that even if the FSP thread goes away, we dont run
|
|
// into issues with the resource package trying to boost the thread priority.
|
|
//
|
|
|
|
if ( InFsp && FcbAcquired ) {
|
|
|
|
LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
|
|
if ( PagingIo ) {
|
|
|
|
ExSetResourceOwnerPointer( Fcb->Header.PagingIoResource, (PVOID)LowIoContext->ResourceThreadId );
|
|
|
|
} else {
|
|
|
|
ExSetResourceOwnerPointer( Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId );
|
|
}
|
|
|
|
fSetResourceOwner = TRUE;
|
|
}
|
|
|
|
Status = RxLowIoReadShell( RxContext, Irp, Fcb );
|
|
|
|
RxItsTheSameContext();
|
|
try_return( Status );
|
|
|
|
try_exit: NOTHING;
|
|
|
|
//
|
|
// If the request was not posted, deal with it.
|
|
//
|
|
|
|
RxItsTheSameContext();
|
|
|
|
if (!PostIrp) {
|
|
|
|
if (!PipeRead) {
|
|
|
|
RxDbgTrace( 0, Dbg, ("CommonRead InnerFinally-> %08lx %08lx\n",
|
|
Status, Irp->IoStatus.Information) );
|
|
|
|
//
|
|
// If the file was opened for Synchronous IO, update the current
|
|
// file position. this works becuase info==0 for errors
|
|
//
|
|
|
|
if (!PagingIo &&
|
|
FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO )) {
|
|
|
|
FileObject->CurrentByteOffset.QuadPart =
|
|
StartingVbo + Irp->IoStatus.Information;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
RxDbgTrace( 0, Dbg, ("Passing request to Fsp\n", 0 ));
|
|
|
|
InterlockedIncrement( &RxContext->ReferenceCount );
|
|
RefdContextForTracker = TRUE;
|
|
|
|
Status = RxFsdPostRequest( RxContext );
|
|
}
|
|
} finally {
|
|
|
|
DebugUnwind( RxCommonRead );
|
|
|
|
//
|
|
// If this was not PagingIo, mark that the last access
|
|
// time on the dirent needs to be updated on close.
|
|
//
|
|
|
|
if (NT_SUCCESS( Status ) && (Status != STATUS_PENDING) && !PagingIo && !PipeRead) {
|
|
SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
|
|
|
|
}
|
|
|
|
//
|
|
// If resources have been acquired, release them under the right conditions.
|
|
// the right conditions are these:
|
|
// 1) if we have abnormal termination. here we obviously release the since no one else will.
|
|
// 2) if the underlying call did not succeed: Status==Pending.
|
|
// 3) if we posted the request
|
|
//
|
|
// Completion for this case is not handled in the common dispatch routine
|
|
//
|
|
|
|
if (AbnormalTermination() || (Status != STATUS_PENDING) || PostIrp) {
|
|
|
|
if (FcbAcquired) {
|
|
|
|
if ( PagingIo ) {
|
|
|
|
if( fSetResourceOwner ) {
|
|
|
|
RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
|
|
|
|
} else {
|
|
|
|
RxReleasePagingIoResource( RxContext, Fcb );
|
|
}
|
|
|
|
} else {
|
|
if( fSetResourceOwner ) {
|
|
|
|
RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
|
|
|
|
} else {
|
|
|
|
RxReleaseFcb( RxContext, Fcb );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RefdContextForTracker) {
|
|
RxDereferenceAndDeleteRxContext( RxContext );
|
|
}
|
|
|
|
if (!PostIrp) {
|
|
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION )) {
|
|
|
|
RxResumeBlockedOperations_Serially( RxContext,
|
|
&Fobx->Specific.NamedPipe.ReadSerializationQueue );
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
ASSERT( Irp->IoStatus.Information <= IrpSp->Parameters.Read.Length );
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// here the guy below is going to handle the completion....but, we don't know the finish
|
|
// order....in all likelihood the deletecontext call below just reduces the refcount
|
|
// but the guy may already have finished in which case this will really delete the context.
|
|
//
|
|
|
|
ASSERT( !SynchronousIo );
|
|
|
|
RxDereferenceAndDeleteRxContext( RxContext );
|
|
}
|
|
|
|
RxDbgTrace( -1, Dbg, ("CommonRead -> %08lx\n", Status) );
|
|
} // finally
|
|
|
|
IF_DEBUG {
|
|
if ((Status == STATUS_END_OF_FILE) &&
|
|
FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS )){
|
|
|
|
DbgPrint( "Returning end of file on %wZ\n", &(Fcb->PrivateAlreadyPrefixedName) );
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxLowIoReadShellCompletion (
|
|
IN PRX_CONTEXT RxContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine postprocesses a read request after it comes back from the
|
|
minirdr. It does callouts to handle compression, buffering and
|
|
shadowing. It is the opposite number of LowIoReadShell.
|
|
|
|
This will be called from LowIo; for async, originally in the
|
|
completion routine. If RxStatus(MORE_PROCESSING_REQUIRED) is returned,
|
|
LowIo will call again in a thread. If this was syncIo, you'll be back
|
|
in the user's thread; if async, lowIo will requeue to a thread.
|
|
Currrently, we always get to a thread before anything; this is a bit slower
|
|
than completing at DPC time,
|
|
but it's aheckuva lot safer and we may often have stuff to do
|
|
(like decompressing, shadowing, etc) that we don't want to do at DPC
|
|
time.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the usual
|
|
|
|
Return Value:
|
|
|
|
whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PIRP Irp = RxContext->CurrentIrp;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
PFCB Fcb;
|
|
PFOBX Fobx;
|
|
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
|
|
BOOLEAN PagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO );
|
|
BOOLEAN PipeOperation = BooleanFlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION );
|
|
BOOLEAN SynchronousPipe = BooleanFlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION );
|
|
|
|
//
|
|
// we will want to revisit this....not taking this at dpc time would cause
|
|
// two extra context swaps IF MINIRDRS MADE THE CALL FROM THE INDICATION
|
|
// CRRRENTLY, THEY DO NOT.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDecodeFileObject( FileObject, &Fcb, &Fobx );
|
|
|
|
Status = RxContext->StoredStatus;
|
|
Irp->IoStatus.Information = RxContext->InformationToReturn;
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxLowIoReadShellCompletion entry Status = %08lx\n", Status) );
|
|
RxLog(( "RdShlComp %lx %lx %lx\n", RxContext, Status, Irp->IoStatus.Information ));
|
|
RxWmiLog( LOG,
|
|
RxLowIoReadShellCompletion_1,
|
|
LOGPTR( RxContext )
|
|
LOGULONG( Status )
|
|
LOGPTR( Irp->IoStatus.Information ) );
|
|
|
|
if (PagingIo) {
|
|
|
|
//
|
|
// for paging io, it's nonsense to have 0bytes and success...map it!
|
|
//
|
|
|
|
if (NT_SUCCESS(Status) &&
|
|
(Irp->IoStatus.Information == 0)) {
|
|
|
|
Status = STATUS_END_OF_FILE;
|
|
}
|
|
}
|
|
|
|
|
|
ASSERT( RxLowIoIsBufferLocked( LowIoContext ) );
|
|
switch (Status) {
|
|
case STATUS_SUCCESS:
|
|
|
|
if(FlagOn( RxContext->Flags, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED )){
|
|
|
|
if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED )){
|
|
|
|
ASSERT( FALSE ); // NOT YET IMPLEMENTED should decompress and put away
|
|
|
|
} else if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED )){
|
|
|
|
ASSERT( FALSE ); // NOT YET IMPLEMENTED should decompress and put away
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STATUS_FILE_LOCK_CONFLICT:
|
|
|
|
if(FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_READ_ENLARGED )){
|
|
ASSERT( FALSE ); // disenlarge the read
|
|
return STATUS_RETRY;
|
|
}
|
|
break;
|
|
|
|
case STATUS_CONNECTION_INVALID:
|
|
|
|
//
|
|
// NOT YET IMPLEMENTED here is where the failover will happen
|
|
// first we give the local guy current minirdr another chance...then we go
|
|
// to fullscale retry
|
|
// return(RxStatus(DISCONNECTED)); //special....let LowIo get us back
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_READAHEAD )) {
|
|
ASSERT( FALSE ); // RxUnwaitReadAheadWaiters(RxContext);
|
|
}
|
|
|
|
if (FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL )){
|
|
|
|
//
|
|
// if we're being called from lowioubmit then just get out
|
|
//
|
|
|
|
RxDbgTrace(-1, Dbg, ("RxLowIoReadShellCompletion syncexit Status = %08lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// otherwise we have to do the end of the read from here
|
|
//
|
|
|
|
//
|
|
// mark that the file has been read accessed
|
|
//
|
|
|
|
if (NT_SUCCESS( Status ) && !PagingIo && !PipeOperation) {
|
|
SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
|
|
}
|
|
|
|
if ( PagingIo ) {
|
|
|
|
RxReleasePagingIoResourceForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
|
|
|
|
} else if (!SynchronousPipe) {
|
|
|
|
RxReleaseFcbForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
|
|
|
|
} else {
|
|
|
|
RxResumeBlockedOperations_Serially( RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue );
|
|
}
|
|
|
|
if (PipeOperation) {
|
|
|
|
if (Irp->IoStatus.Information == 0) {
|
|
|
|
//
|
|
// if this is a nowait pipe, initiate throttling to keep from flooding the net
|
|
//
|
|
|
|
if (Fobx->Specific.NamedPipe.CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
|
|
|
|
RxInitiateOrContinueThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
|
|
|
|
RxLog(( "RThrottlYes %lx %lx %lx %ld\n",
|
|
RxContext,Fobx,&Fobx->Specific.NamedPipe.ThrottlingState,
|
|
Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
|
|
RxWmiLog( LOG,
|
|
RxLowIoReadShellCompletion_2,
|
|
LOGPTR( RxContext )
|
|
LOGPTR( Fobx )
|
|
LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
|
|
}
|
|
|
|
//
|
|
// translate the status if this is a msgmode pipe
|
|
//
|
|
|
|
if ((Fobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_MESSAGE_TYPE) &&
|
|
(Status == STATUS_SUCCESS)) {
|
|
|
|
Status = STATUS_PIPE_EMPTY;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// if we have been throttling on this pipe, stop because we got some data.....
|
|
//
|
|
|
|
RxTerminateThrottling( &Fobx->Specific.NamedPipe.ThrottlingState );
|
|
|
|
RxLog(( "RThrottlNo %lx %lx %lx %ld\n",
|
|
RxContext, Fobx, &Fobx->Specific.NamedPipe.ThrottlingState,
|
|
Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ));
|
|
RxWmiLog( LOG,
|
|
RxLowIoReadShellCompletion_3,
|
|
LOGPTR( RxContext )
|
|
LOGPTR( Fobx )
|
|
LOGULONG( Fobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries ) );
|
|
}
|
|
}
|
|
|
|
ASSERT( Status != STATUS_RETRY );
|
|
|
|
if (Status != STATUS_RETRY) {
|
|
|
|
ASSERT( Irp->IoStatus.Information <= IrpSp->Parameters.Read.Length );
|
|
ASSERT( RxContext->MajorFunction == IRP_MJ_READ );
|
|
}
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxLowIoReadShellCompletion asyncexit Status = %08lx\n", Status) );
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxLowIoReadShell (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine preprocesses a read request before it goes down to the minirdr. It does callouts
|
|
to handle compression, buffering and shadowing. It is the opposite number of LowIoReadShellCompletion.
|
|
By the time we get here, either the shadowing system will handle the read OR we are going to the wire.
|
|
Read buffering was already tried in the UncachedRead strategy
|
|
|
|
Arguments:
|
|
|
|
RxContext - the usual
|
|
|
|
Return Value:
|
|
|
|
whatever value is returned by a callout....or by LowIo.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace( +1, Dbg, ("RxLowIoReadShell entry %08lx\n") );
|
|
RxLog(( "RdShl in %lx\n", RxContext ));
|
|
RxWmiLog( LOG,
|
|
RxLowIoReadShell_1,
|
|
LOGPTR( RxContext ) );
|
|
|
|
if (Fcb->CachedNetRootType == NET_ROOT_DISK) {
|
|
|
|
ExInterlockedAddLargeStatistic( &RxContext->RxDeviceObject->NetworkReadBytesRequested,
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount );
|
|
}
|
|
|
|
Status = RxLowIoSubmit( RxContext, Irp, Fcb, RxLowIoReadShellCompletion );
|
|
|
|
RxDbgTrace( -1, Dbg, ("RxLowIoReadShell exit Status = %08lx\n", Status) );
|
|
RxLog(( "RdShl out %x %x\n", RxContext, Status ));
|
|
RxWmiLog( LOG,
|
|
RxLowIoReadShell_2,
|
|
LOGPTR( RxContext )
|
|
LOGULONG( Status ) );
|
|
|
|
return Status;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
ULONG RxLoudLowIoOpsEnabled = 0;
|
|
|
|
VOID CheckForLoudOperations (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PFCB Fcb
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (RxLoudLowIoOpsEnabled) {
|
|
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
PCHAR Buffer;
|
|
PWCHAR FileOfConcern = L"all.scr";
|
|
ULONG Length = 7*sizeof( WCHAR ); //7 is the length of all.scr;
|
|
|
|
Buffer = Add2Ptr( Fcb->PrivateAlreadyPrefixedName.Buffer, Fcb->PrivateAlreadyPrefixedName.Length - Length );
|
|
|
|
if (RtlCompareMemory( Buffer, FileOfConcern, Length ) == Length) {
|
|
|
|
SetFlag( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif //if DBG
|