1291 lines
39 KiB
C
1291 lines
39 KiB
C
|
/*++
|
|||
|
|
|||
|
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 handles read stack overflow operations.
|
|||
|
|
|||
|
VOID
|
|||
|
RxStackOverflowRead (
|
|||
|
IN PVOID Context,
|
|||
|
IN PKEVENT Event
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxPostStackOverflowRead (
|
|||
|
IN PRX_CONTEXT RxContext
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The following procedures are the handle the procedureal interface with lowio.
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxLowIoReadShell (
|
|||
|
IN PRX_CONTEXT RxContext
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxLowIoReadShellCompletion (
|
|||
|
IN PRX_CONTEXT RxContext
|
|||
|
);
|
|||
|
|
|||
|
#if DBG
|
|||
|
VOID CheckForLoudOperations(
|
|||
|
PRX_CONTEXT RxContext
|
|||
|
);
|
|||
|
#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
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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).
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
RxCaptureRequestPacket;
|
|||
|
RxCaptureFcb;
|
|||
|
|
|||
|
PKEVENT Event;
|
|||
|
PERESOURCE Resource;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
RxDbgTrace(0, Dbg, ("Getting too close to stack limit pass request to Fsp\n", 0 ));
|
|||
|
|
|||
|
//
|
|||
|
// Allocate an event and get shared on the resource we will
|
|||
|
// be later using the common read.
|
|||
|
|
|||
|
Event = RxAllocatePool( NonPagedPool, sizeof(KEVENT) );
|
|||
|
|
|||
|
if (Event != NULL) {
|
|||
|
KeInitializeEvent( Event, NotificationEvent, FALSE );
|
|||
|
|
|||
|
if (FlagOn(capReqPacket->Flags, IRP_PAGING_IO) && (capFcb->Header.PagingIoResource != NULL)) {
|
|||
|
|
|||
|
Resource = capFcb->Header.PagingIoResource;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Resource = capFcb->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, capReqPacket );
|
|||
|
|
|||
|
FsRtlPostStackOverflow( RxContext, Event, RxStackOverflowRead );
|
|||
|
|
|||
|
//
|
|||
|
// And wait for the worker thread to complete the item
|
|||
|
|
|||
|
(VOID) KeWaitForSingleObject( Event, Executive, KernelMode, FALSE, NULL );
|
|||
|
|
|||
|
} finally {
|
|||
|
|
|||
|
ExReleaseResourceLite( Resource );
|
|||
|
|
|||
|
RxFreePool( Event );
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_PENDING;
|
|||
|
} else {
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
RxCaptureRequestPacket;
|
|||
|
|
|||
|
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 );
|
|||
|
|
|||
|
} 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;
|
|||
|
capReqPacket->IoStatus.Information = 0;
|
|||
|
}
|
|||
|
|
|||
|
(VOID) RxProcessException( RxContext, ExceptionCode );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Signal the original thread that we're done.
|
|||
|
|
|||
|
KeSetEvent( Event, 0, FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxCommonRead ( RXCOMMON_SIGNATURE )
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
RxCaptureRequestPacket;
|
|||
|
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; RxCaptureFileObject;
|
|||
|
NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
|
|||
|
PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
|
|||
|
|
|||
|
LARGE_INTEGER StartingByte;
|
|||
|
RXVBO StartingVbo;
|
|||
|
ULONG ByteCount;
|
|||
|
|
|||
|
ULONG CapturedRxContextSerialNumber = RxContext->SerialNumber;
|
|||
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|||
|
|
|||
|
BOOLEAN PostIrp = FALSE;
|
|||
|
BOOLEAN OplockPostIrp = FALSE;
|
|||
|
|
|||
|
BOOLEAN FcbAcquired = FALSE;
|
|||
|
BOOLEAN RefdContextForTracker = FALSE;
|
|||
|
|
|||
|
BOOLEAN Wait;
|
|||
|
BOOLEAN PagingIo;
|
|||
|
BOOLEAN NonCachedIo;
|
|||
|
BOOLEAN SynchronousIo;
|
|||
|
|
|||
|
PNET_ROOT NetRoot = (PNET_ROOT)(capFcb->pNetRoot);
|
|||
|
BOOLEAN ThisIsAPipeRead = (BOOLEAN)(NetRoot->Type == NET_ROOT_PIPE);
|
|||
|
BOOLEAN ThisIsABlockingResume = BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME);
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the local decision variables.
|
|||
|
//
|
|||
|
|
|||
|
Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
|||
|
PagingIo = BooleanFlagOn(capReqPacket->Flags, IRP_PAGING_IO);
|
|||
|
NonCachedIo = BooleanFlagOn(capReqPacket->Flags,IRP_NOCACHE);
|
|||
|
SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
|
|||
|
|
|||
|
RxDbgTrace(+1, Dbg, ("RxCommonRead...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
|
|||
|
RxContext, capFobx, capFcb));
|
|||
|
RxDbgTrace( 0, Dbg, (" ->ByteCount = %08lx, ByteOffset = %08lx %lx\n",
|
|||
|
capPARAMS->Parameters.Read.Length,
|
|||
|
capPARAMS->Parameters.Read.ByteOffset.LowPart,
|
|||
|
capPARAMS->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, capFobx, capFcb));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxCommonRead_1,
|
|||
|
LOGPTR(RxContext)
|
|||
|
LOGPTR(capFobx)
|
|||
|
LOGPTR(capFcb));
|
|||
|
RxLog((" read %lx@%lx %lx %s%s%s%s\n",
|
|||
|
capPARAMS->Parameters.Read.Length,
|
|||
|
capPARAMS->Parameters.Read.ByteOffset.LowPart,
|
|||
|
capPARAMS->Parameters.Read.ByteOffset.HighPart,
|
|||
|
Wait?"Wt":"",
|
|||
|
PagingIo?"Pg":"",
|
|||
|
NonCachedIo?"Nc":"",
|
|||
|
SynchronousIo?"Sync":""
|
|||
|
));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxCommonRead_2,
|
|||
|
LOGULONG(capPARAMS->Parameters.Read.Length)
|
|||
|
LOGULONG(capPARAMS->Parameters.Read.ByteOffset.LowPart)
|
|||
|
LOGULONG(capPARAMS->Parameters.Read.ByteOffset.HighPart)
|
|||
|
LOGUCHAR(Wait)
|
|||
|
LOGUCHAR(PagingIo)
|
|||
|
LOGUCHAR(NonCachedIo)
|
|||
|
LOGUCHAR(SynchronousIo));
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
capReqPacket->IoStatus.Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Extract starting Vbo and offset.
|
|||
|
//
|
|||
|
|
|||
|
StartingByte = capPARAMS->Parameters.Read.ByteOffset;
|
|||
|
StartingVbo = StartingByte.QuadPart;
|
|||
|
|
|||
|
ByteCount = capPARAMS->Parameters.Read.Length;
|
|||
|
|
|||
|
DbgDoit(CheckForLoudOperations(RxContext););
|
|||
|
|
|||
|
IF_DEBUG{
|
|||
|
if (FlagOn(LowIoContext->Flags,LOWIO_CONTEXT_FLAG_LOUDOPS)){
|
|||
|
DbgPrint("LoudRead %lx/%lx on %lx vdl/size/alloc %lx/%lx/%lx\n",
|
|||
|
StartingByte.LowPart,ByteCount,capFcb,
|
|||
|
capFcb->Header.ValidDataLength.LowPart,
|
|||
|
capFcb->Header.FileSize.LowPart,
|
|||
|
capFcb->Header.AllocationSize.LowPart);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//Statistics............
|
|||
|
if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) &&
|
|||
|
(capFcb->CachedNetRootType == NET_ROOT_DISK)) {
|
|||
|
|
|||
|
InterlockedIncrement(&RxDeviceObject->ReadOperations);
|
|||
|
|
|||
|
if (StartingVbo != capFobx->Specific.DiskFile.PredictedReadOffset) {
|
|||
|
InterlockedIncrement(&RxDeviceObject->RandomReadOperations);
|
|||
|
}
|
|||
|
|
|||
|
capFobx->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 (ThisIsAPipeRead && 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(LowIoContext,LOWIO_OP_READ);
|
|||
|
|
|||
|
//
|
|||
|
// 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", capFcb->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 &&
|
|||
|
!PagingIo &&
|
|||
|
(capFileObject->SectionObjectPointer->DataSectionObject != NULL)) {
|
|||
|
|
|||
|
// We hold the main resource exclusive here because the flush
|
|||
|
// may generate a recursive write in this thread
|
|||
|
|
|||
|
Status = RxAcquireExclusiveFcb(RxContext, capFcb);
|
|||
|
|
|||
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|||
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb for flush = %08lx excl without waiting - lock not granted\n",capFcb ));
|
|||
|
try_return( PostIrp = TRUE );
|
|||
|
} else if (Status != STATUS_SUCCESS) {
|
|||
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb = %08lx shared without waiting - other\n",capFcb ));
|
|||
|
try_return(PostIrp = FALSE);
|
|||
|
}
|
|||
|
|
|||
|
ExAcquireResourceSharedLite(
|
|||
|
capFcb->Header.PagingIoResource,
|
|||
|
TRUE );
|
|||
|
|
|||
|
CcFlushCache(
|
|||
|
capFileObject->SectionObjectPointer,
|
|||
|
&StartingByte,
|
|||
|
ByteCount,
|
|||
|
&capReqPacket->IoStatus );
|
|||
|
|
|||
|
RxReleasePagingIoResource(capFcb,RxContext);
|
|||
|
|
|||
|
RxReleaseFcb( RxContext, capFcb );
|
|||
|
|
|||
|
if (!NT_SUCCESS( capReqPacket->IoStatus.Status)) {
|
|||
|
Status = capReqPacket->IoStatus.Status;
|
|||
|
try_return( capReqPacket->IoStatus.Status );
|
|||
|
}
|
|||
|
|
|||
|
RxAcquirePagingIoResource(capFcb,RxContext);
|
|||
|
RxReleasePagingIoResource(capFcb,RxContext);
|
|||
|
}
|
|||
|
|
|||
|
// We need shared access to the Fcb before proceeding.
|
|||
|
|
|||
|
if ( PagingIo ) {
|
|||
|
|
|||
|
ASSERT( !ThisIsAPipeRead );
|
|||
|
|
|||
|
if (!ExAcquireResourceSharedLite(
|
|||
|
capFcb->Header.PagingIoResource,
|
|||
|
Wait )) {
|
|||
|
|
|||
|
RxDbgTrace( 0, Dbg, ("Cannot acquire Fcb = %08lx shared without waiting\n", capFcb ));
|
|||
|
|
|||
|
try_return( PostIrp = TRUE );
|
|||
|
}
|
|||
|
|
|||
|
if (!Wait) {
|
|||
|
LowIoContext->Resource = capFcb->Header.PagingIoResource;
|
|||
|
}
|
|||
|
|
|||
|
} else if (!ThisIsABlockingResume) {
|
|||
|
|
|||
|
//
|
|||
|
// If this is async I/O directly to the disk 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, capFcb );
|
|||
|
|
|||
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|||
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb = %08lx shared without waiting - lock not granted\n",capFcb ));
|
|||
|
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",capFcb ));
|
|||
|
RxLog(("RdAsyOthr %x\n",RxContext));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxCommonRead_4,
|
|||
|
LOGPTR(RxContext));
|
|||
|
try_return( PostIrp = FALSE );
|
|||
|
}
|
|||
|
|
|||
|
if (ExIsResourceAcquiredSharedLite( capFcb->Header.Resource )
|
|||
|
> MAX_FCB_ASYNC_ACQUIRE) {
|
|||
|
|
|||
|
FcbAcquired = TRUE;
|
|||
|
try_return( PostIrp = TRUE );
|
|||
|
}
|
|||
|
|
|||
|
LowIoContext->Resource = capFcb->Header.Resource;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = RxAcquireSharedFcb(RxContext, capFcb);
|
|||
|
|
|||
|
if (Status == STATUS_LOCK_NOT_GRANTED) {
|
|||
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb = %08lx shared without waiting - lock not granted\n",capFcb ));
|
|||
|
try_return( PostIrp = TRUE );
|
|||
|
} else if (Status != STATUS_SUCCESS) {
|
|||
|
RxDbgTrace( 0,Dbg,("Cannot acquire Fcb = %08lx shared without waiting - other\n",capFcb ));
|
|||
|
try_return(PostIrp = FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
|
|||
|
FcbAcquired = !ThisIsABlockingResume;
|
|||
|
|
|||
|
// for pipe reads, bail out now. we avoid a goto by duplicating the calldown
|
|||
|
if (ThisIsAPipeRead) {
|
|||
|
//
|
|||
|
// In order to prevent corruption on multi-threaded multi-block
|
|||
|
// message mode pipe reads, we do this little dance with the fcb resource
|
|||
|
//
|
|||
|
|
|||
|
if (!ThisIsABlockingResume) {
|
|||
|
|
|||
|
if ((capFobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_MESSAGE_TYPE) ||
|
|||
|
((capFobx->Specific.NamedPipe.TypeOfPipe == FILE_PIPE_BYTE_STREAM_TYPE) &&
|
|||
|
!(capFobx->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", capFobx, capFcb ));
|
|||
|
|
|||
|
Status = RxSynchronizeBlockingOperationsAndDropFcbLock(
|
|||
|
RxContext,
|
|||
|
&capFobx->Specific.NamedPipe.ReadSerializationQueue);
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
|
|||
|
FcbAcquired = FALSE;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status) ||
|
|||
|
(Status == STATUS_PENDING)) {
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
RxDbgTrace( 0,Dbg,("Succeeded: Fobx: %lx\n", capFobx ));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
|
|||
|
LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
|
|||
|
SetFlag(RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
|
|||
|
|
|||
|
Status = RxLowIoReadShell(RxContext);
|
|||
|
|
|||
|
try_return( Status );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We check whether we can proceed based on the state of the file oplocks.
|
|||
|
//
|
|||
|
|
|||
|
Status = FsRtlCheckOplock(
|
|||
|
&capFcb->Specific.Fcb.Oplock,
|
|||
|
capReqPacket,
|
|||
|
RxContext,
|
|||
|
RxOplockComplete,
|
|||
|
RxPrePostIrp );
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
|
|||
|
OplockPostIrp = TRUE;
|
|||
|
PostIrp = TRUE;
|
|||
|
|
|||
|
try_return( NOTHING );
|
|||
|
}
|
|||
|
|
|||
|
RxGetFileSizeWithLock(capFcb,&FileSize);
|
|||
|
ValidDataLength = capFcb->Header.ValidDataLength.QuadPart;
|
|||
|
|
|||
|
|
|||
|
// Set the flag indicating if Fast I/O is possible
|
|||
|
//we no longer do this here....rather we set the 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
|
|||
|
|
|||
|
//capFcb->Header.IsFastIoPossible = RxIsFastIoPossible( capFcb );
|
|||
|
|
|||
|
//
|
|||
|
// 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(
|
|||
|
&capFcb->Specific.Fcb.FileLock,
|
|||
|
capReqPacket )) {
|
|||
|
|
|||
|
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(capFcb->FcbState,FCB_STATE_READCACHEING_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(capFcb->FcbState,FCB_STATE_READCACHEING_ENABLED) &&
|
|||
|
!FlagOn(capFobx->SrvOpen->Flags,SRVOPEN_FLAG_DONTUSE_READ_CACHEING) ) {
|
|||
|
|
|||
|
//
|
|||
|
// 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 (capFileObject->PrivateCacheMap == NULL) {
|
|||
|
|
|||
|
RxDbgTrace(0, Dbg, ("Initialize cache mapping.\n", 0));
|
|||
|
|
|||
|
RxAdjustAllocationSizeforCC(capFcb);
|
|||
|
|
|||
|
//
|
|||
|
// Now initialize the cache map.
|
|||
|
try {
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
CcInitializeCacheMap(
|
|||
|
capFileObject,
|
|||
|
(PCC_FILE_SIZES)&capFcb->Header.AllocationSize,
|
|||
|
FALSE,
|
|||
|
&RxData.CacheManagerCallbacks,
|
|||
|
capFcb );
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = GetExceptionCode();
|
|||
|
}
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
if (!FlagOn(capFcb->MRxDispatch->MRxFlags,
|
|||
|
RDBSS_NO_DEFERRED_CACHE_READAHEAD)) {
|
|||
|
|
|||
|
// Start out with read ahead disabled
|
|||
|
//
|
|||
|
|
|||
|
CcSetAdditionalCacheAttributes( capFileObject, TRUE, FALSE );
|
|||
|
|
|||
|
SetFlag(capFcb->FcbState,FCB_STATE_READAHEAD_DEFERRED);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//this mini doesn't want deferred readahead
|
|||
|
|
|||
|
CcSetAdditionalCacheAttributes( capFileObject, FALSE, FALSE );
|
|||
|
//DbgPrint("Nodeferred readahead\n");
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
CcSetReadAheadGranularity(
|
|||
|
capFileObject,
|
|||
|
NetRoot->DiskParameters.ReadAheadGranularity );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
// if we have wandered off the first page and haven't started reading ahead
|
|||
|
// then start now
|
|||
|
|
|||
|
if (FlagOn(capFcb->FcbState,FCB_STATE_READAHEAD_DEFERRED) &&
|
|||
|
(StartingVbo >= PAGE_SIZE) ) {
|
|||
|
|
|||
|
CcSetAdditionalCacheAttributes( capFileObject, FALSE, FALSE );
|
|||
|
|
|||
|
ClearFlag(capFcb->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;
|
|||
|
DEBUG_ONLY_DECL(ULONG SaveExceptionFlag;)
|
|||
|
|
|||
|
//
|
|||
|
// Get hold of the user's buffer.
|
|||
|
|
|||
|
SystemBuffer = RxNewMapUserBuffer( RxContext );
|
|||
|
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(
|
|||
|
capFileObject,
|
|||
|
&StartingByte,
|
|||
|
ByteCount,
|
|||
|
Wait,
|
|||
|
SystemBuffer,
|
|||
|
&capReqPacket->IoStatus )) {
|
|||
|
|
|||
|
RxDbgTrace( 0, Dbg, ("Cached Read could not wait\n", 0 ));
|
|||
|
RxRestoreExceptionNoBreakpointFlag(RxContext,SaveExceptionFlag);
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
|
|||
|
try_return( PostIrp = TRUE );
|
|||
|
}
|
|||
|
|
|||
|
Status = capReqPacket->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(
|
|||
|
capFileObject,
|
|||
|
&StartingByte,
|
|||
|
ByteCount,
|
|||
|
&capReqPacket->MdlAddress,
|
|||
|
&capReqPacket->IoStatus );
|
|||
|
|
|||
|
Status = capReqPacket->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 ((capFcb->CachedNetRootType == NET_ROOT_DISK) &&
|
|||
|
FlagOn(capFcb->FcbState,FCB_STATE_READCACHEING_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 = RxNewMapUserBuffer( RxContext );
|
|||
|
SafeZeroMemory(SystemBuffer, ByteCount); //this could raise!!
|
|||
|
}
|
|||
|
|
|||
|
capReqPacket->IoStatus.Information = ByteCount;
|
|||
|
|
|||
|
try_return(Status = STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LowIoContext->ParamsFor.ReadWrite.ByteCount = ByteCount;
|
|||
|
LowIoContext->ParamsFor.ReadWrite.ByteOffset = StartingVbo;
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
|
|||
|
Status = RxLowIoReadShell(RxContext);
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
try_return( Status );
|
|||
|
|
|||
|
try_exit: NOTHING;
|
|||
|
|
|||
|
//
|
|||
|
// If the request was not posted, deal with it.
|
|||
|
//
|
|||
|
|
|||
|
RxItsTheSameContext();
|
|||
|
|
|||
|
if ( !PostIrp ) {
|
|||
|
if (!ThisIsAPipeRead) {
|
|||
|
|
|||
|
RxDbgTrace( 0, Dbg, ("CommonRead InnerFinally-> %08lx %08lx\n",
|
|||
|
Status, capReqPacket->IoStatus.Information));
|
|||
|
|
|||
|
//
|
|||
|
// If the file was opened for Synchronous IO, update the current
|
|||
|
// file position. this works becuase info==0 for errors
|
|||
|
//
|
|||
|
|
|||
|
if (!PagingIo &&
|
|||
|
BooleanFlagOn(capFileObject->Flags, FO_SYNCHRONOUS_IO)) {
|
|||
|
capFileObject->CurrentByteOffset.QuadPart =
|
|||
|
StartingVbo + capReqPacket->IoStatus.Information;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
RxDbgTrace( 0, Dbg, ("Passing request to Fsp\n", 0 ));
|
|||
|
|
|||
|
if (!OplockPostIrp) {
|
|||
|
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 && !ThisIsAPipeRead) {
|
|||
|
SetFlag( capFileObject->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 ) {
|
|||
|
|
|||
|
RxReleasePagingIoResource(capFcb,RxContext);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
RxReleaseFcb( RxContext, capFcb );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (RefdContextForTracker) {
|
|||
|
RxDereferenceAndDeleteRxContext(RxContext);
|
|||
|
}
|
|||
|
|
|||
|
if (!PostIrp) {
|
|||
|
if (FlagOn(RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) {
|
|||
|
|
|||
|
RxResumeBlockedOperations_Serially(
|
|||
|
RxContext,
|
|||
|
&capFobx->Specific.NamedPipe.ReadSerializationQueue);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Status == STATUS_SUCCESS) {
|
|||
|
ASSERT ( capReqPacket->IoStatus.Information
|
|||
|
<= capPARAMS->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",&(capFcb->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;
|
|||
|
|
|||
|
RxCaptureRequestPacket;
|
|||
|
RxCaptureFcb; RxCaptureParamBlock; RxCaptureFileObject;
|
|||
|
|
|||
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|||
|
|
|||
|
BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
|
|||
|
|
|||
|
BOOLEAN PagingIo = BooleanFlagOn(capReqPacket->Flags, IRP_PAGING_IO);
|
|||
|
|
|||
|
BOOLEAN ThisIsAPipeOperation =
|
|||
|
BooleanFlagOn(RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION);
|
|||
|
|
|||
|
BOOLEAN ThisIsASynchronizedPipeOperation =
|
|||
|
BooleanFlagOn(RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
|
|||
|
|
|||
|
PAGED_CODE(); //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.
|
|||
|
|
|||
|
Status = RxContext->StoredStatus;
|
|||
|
capReqPacket->IoStatus.Information = RxContext->InformationToReturn;
|
|||
|
|
|||
|
RxDbgTrace(+1, Dbg, ("RxLowIoReadShellCompletion entry Status = %08lx\n", Status));
|
|||
|
RxLog(("RdShlComp %lx %lx %lx\n",RxContext,Status,capReqPacket->IoStatus.Information));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxLowIoReadShellCompletion_1,
|
|||
|
LOGPTR(RxContext)
|
|||
|
LOGULONG(Status)
|
|||
|
LOGPTR(capReqPacket->IoStatus.Information));
|
|||
|
|
|||
|
if ( PagingIo ) {
|
|||
|
//for paging io, it's nonsense to have 0bytes and success...map it!
|
|||
|
if (NT_SUCCESS(Status) &&
|
|||
|
(capReqPacket->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(capFcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED)){
|
|||
|
ASSERT(FALSE); // NOT YET IMPLEMENTED should decompress and put away
|
|||
|
} else if (FlagOn(capFcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED)){
|
|||
|
ASSERT(FALSE); // NOT YET IMPLEMENTED should decompress and put away
|
|||
|
}
|
|||
|
}
|
|||
|
if (FlagOn(capFcb->FcbState, FCB_STATE_FILE_IS_SHADOWED)) {
|
|||
|
ASSERT(FALSE); //RxSdwAddData(RxContext);
|
|||
|
}
|
|||
|
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 && !ThisIsAPipeOperation) {
|
|||
|
SetFlag( capFileObject->Flags, FO_FILE_FAST_IO_READ );
|
|||
|
}
|
|||
|
|
|||
|
if ( PagingIo ) {
|
|||
|
|
|||
|
RxReleasePagingIoResourceForThread(capFcb,LowIoContext->ResourceThreadId,RxContext);
|
|||
|
|
|||
|
} else if (!ThisIsASynchronizedPipeOperation) {
|
|||
|
|
|||
|
RxReleaseFcbForThread( RxContext, capFcb, LowIoContext->ResourceThreadId );
|
|||
|
|
|||
|
} else {
|
|||
|
RxCaptureFobx;
|
|||
|
|
|||
|
RxResumeBlockedOperations_Serially(
|
|||
|
RxContext,
|
|||
|
&capFobx->Specific.NamedPipe.ReadSerializationQueue);
|
|||
|
}
|
|||
|
|
|||
|
if (ThisIsAPipeOperation) {
|
|||
|
RxCaptureFobx;
|
|||
|
|
|||
|
if (capReqPacket->IoStatus.Information == 0) {
|
|||
|
|
|||
|
//if this is a nowait pipe, initiate throttling to keep from flooding the net
|
|||
|
|
|||
|
if (capFobx->Specific.NamedPipe.CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
|
|||
|
|
|||
|
RxInitiateOrContinueThrottling(
|
|||
|
&capFobx->Specific.NamedPipe.ThrottlingState);
|
|||
|
|
|||
|
RxLog(("RThrottlYes %lx %lx %lx %ld\n",
|
|||
|
RxContext,capFobx,&capFobx->Specific.NamedPipe.ThrottlingState,
|
|||
|
capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxLowIoReadShellCompletion_2,
|
|||
|
LOGPTR(RxContext)
|
|||
|
LOGPTR(capFobx)
|
|||
|
LOGULONG(capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
|
|||
|
}
|
|||
|
|
|||
|
//translate the status if this is a msgmode pipe
|
|||
|
|
|||
|
if ((capFobx->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(&capFobx->Specific.NamedPipe.ThrottlingState);
|
|||
|
|
|||
|
RxLog(("RThrottlNo %lx %lx %lx %ld\n",
|
|||
|
RxContext,capFobx,&capFobx->Specific.NamedPipe.ThrottlingState,
|
|||
|
capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxLowIoReadShellCompletion_3,
|
|||
|
LOGPTR(RxContext)
|
|||
|
LOGPTR(capFobx)
|
|||
|
LOGULONG(capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(Status != STATUS_RETRY);
|
|||
|
|
|||
|
if ( Status != STATUS_RETRY){
|
|||
|
ASSERT ( capReqPacket->IoStatus.Information
|
|||
|
<= capPARAMS->Parameters.Read.Length );
|
|||
|
ASSERT (RxContext->MajorFunction == IRP_MJ_READ);
|
|||
|
}
|
|||
|
|
|||
|
RxDbgTrace(-1, Dbg, ("RxLowIoReadShellCompletion asyncexit Status = %08lx\n", Status));
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
#define RxSdwRead(RXCONTEXT) STATUS_MORE_PROCESSING_REQUIRED
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxLowIoReadShell (
|
|||
|
IN PRX_CONTEXT RxContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
RxCaptureFcb;
|
|||
|
RxCaptureParamBlock;
|
|||
|
|
|||
|
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 (FlagOn(capFcb->FcbState, FCB_STATE_FILE_IS_SHADOWED)) {
|
|||
|
Status = RxSdwRead(RxContext);
|
|||
|
|
|||
|
if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (capFcb->CachedNetRootType == NET_ROOT_DISK) {
|
|||
|
ExInterlockedAddLargeStatistic(
|
|||
|
&RxContext->RxDeviceObject->NetworkReadBytesRequested,
|
|||
|
LowIoContext->ParamsFor.ReadWrite.ByteCount);
|
|||
|
}
|
|||
|
|
|||
|
Status = RxLowIoSubmit(RxContext,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(
|
|||
|
PRX_CONTEXT RxContext
|
|||
|
)
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (RxLoudLowIoOpsEnabled) {
|
|||
|
RxCaptureFcb;
|
|||
|
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 = (PCHAR)(capFcb->PrivateAlreadyPrefixedName.Buffer)
|
|||
|
+ capFcb->PrivateAlreadyPrefixedName.Length - Length;
|
|||
|
|
|||
|
if (RtlCompareMemory(Buffer,FileOfConcern,Length)==Length) {
|
|||
|
SetFlag(LowIoContext->Flags,LOWIO_CONTEXT_FLAG_LOUDOPS);
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif //if DBG
|