Leaked source code of windows server 2003
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.
 
 
 
 
 
 

883 lines
25 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
LowIo.c
Abstract:
This module implements buffer locking and mapping; also synchronous waiting for a lowlevelIO.
Author:
JoeLinn [JoeLinn] 12-Oct-94
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Local debug trace level
//
#define Dbg (DEBUG_TRACE_LOWIO)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxLockUserBuffer)
#pragma alloc_text(PAGE, RxMapUserBuffer)
#pragma alloc_text(PAGE, RxMapSystemBuffer)
#pragma alloc_text(PAGE, RxInitializeLowIoContext)
#pragma alloc_text(PAGE, RxLowIoGetBufferAddress)
#pragma alloc_text(PAGE, RxLowIoSubmitRETRY)
#pragma alloc_text(PAGE, RxLowIoPopulateFsctlInfo)
#pragma alloc_text(PAGE, RxLowIoSubmit)
#pragma alloc_text(PAGE, RxInitializeLowIoPerFcbInfo)
#pragma alloc_text(PAGE, RxInitializeLowIoPerFcbInfo)
#endif
//
// this is a crude implementation of the insertion, deletion, and coverup operations for wimp lowio
// we'll just use a linked list for now.........
//
#define RxInsertIntoOutStandingPagingOperationsList(RxContext,Operation) { \
PLIST_ENTRY WhichList = (Operation==LOWIO_OP_READ) \
?&Fcb->PagingIoReadsOutstanding \
:&Fcb->PagingIoWritesOutstanding;\
InsertTailList(WhichList,&RxContext->RxContextSerializationQLinks); \
}
#define RxRemoveFromOutStandingPagingOperationsList(RxContext) { \
RemoveEntryList(&RxContext->RxContextSerializationQLinks); \
RxContext->RxContextSerializationQLinks.Flink = NULL; \
RxContext->RxContextSerializationQLinks.Blink = NULL; \
}
FAST_MUTEX RxLowIoPagingIoSyncMutex;
//
// here we hiding the IO access flags
//
INLINE
NTSTATUS
RxLockAndMapUserBufferForLowIo (
IN PRX_CONTEXT RxContext,
IN PIRP Irp,
IN PLOWIO_CONTEXT LowIoContext,
IN ULONG Operation
)
{
RxLockUserBuffer( RxContext,
Irp,
(Operation == LOWIO_OP_READ) ? IoWriteAccess : IoReadAccess,
LowIoContext->ParamsFor.ReadWrite.ByteCount );
if (RxMapUserBuffer( RxContext, Irp ) == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
} else {
LowIoContext->ParamsFor.ReadWrite.Buffer = Irp->MdlAddress;
return STATUS_SUCCESS;
}
}
//
// NT specific routines
//
VOID
RxLockUserBuffer (
IN PRX_CONTEXT RxContext,
IN PIRP Irp,
IN LOCK_OPERATION Operation,
IN ULONG BufferLength
)
/*++
Routine Description:
This routine locks the specified buffer for the specified type of
access. The file system requires this routine since it does not
ask the I/O system to lock its buffers for direct I/O. This routine
may only be called from the Fsd while still in the user context.
Arguments:
RxContext - Pointer to the pointer Irp for which the buffer is to be locked.
Operation - IoWriteAccess for read operations, or IoReadAccess for
write operations.
BufferLength - Length of user buffer.
Return Value:
None
--*/
{
PMDL Mdl = NULL;
PAGED_CODE();
if (Irp->MdlAddress == NULL) {
ASSERT( !FlagOn( Irp->Flags, IRP_INPUT_OPERATION ) );
//
// Allocate the Mdl, and Raise if we fail.
//
if (BufferLength > 0) {
Mdl = IoAllocateMdl( Irp->UserBuffer,
BufferLength,
FALSE,
FALSE,
Irp );
if (Mdl == NULL) {
RxRaiseStatus( RxContext, STATUS_INSUFFICIENT_RESOURCES );
} else {
//
// Now probe the buffer described by the Irp. If we get an exception,
// deallocate the Mdl and return the appropriate "expected" status.
//
try {
MmProbeAndLockPages( Mdl,
Irp->RequestorMode,
Operation );
} except(EXCEPTION_EXECUTE_HANDLER) {
NTSTATUS Status;
Status = GetExceptionCode();
IoFreeMdl( Mdl );
Irp->MdlAddress = NULL;
if (!FsRtlIsNtstatusExpected( Status )) {
Status = STATUS_INVALID_USER_BUFFER;
}
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT );
RxRaiseStatus( RxContext, Status );
}
}
}
} else {
Mdl = Irp->MdlAddress;
ASSERT( RxLowIoIsMdlLocked( Mdl ) );
}
}
PVOID
RxMapSystemBuffer (
IN PRX_CONTEXT RxContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine returns the system buffer address from the irp. the way that the code is written
it may also decide to get the buffer address from the mdl. that is wrong because the systembuffer is
always nonpaged so no locking/mapping is needed. thus, the mdl path now contains an assert.
Arguments:
RxContext - Pointer to the IrpC for the request.
Return Value:
Mapped address
--*/
{
PAGED_CODE();
if (Irp->MdlAddress == NULL) {
return Irp->AssociatedIrp.SystemBuffer;
} else {
ASSERT (!"there should not be an MDL in this irp!!!!!");
return MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
}
}
PVOID
RxMapUserBuffer (
IN PRX_CONTEXT RxContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine returns the address of the userbuffer. if an MDL exists then the assumption is that
the mdl describes the userbuffer and the system address for the mdl is returned. otherwise, the userbuffer
is returned directly.
Arguments:
RxContext - Pointer to the IrpC for the request.
Return Value:
Mapped address
--*/
{
PAGED_CODE();
if (Irp->MdlAddress == NULL) {
return Irp->UserBuffer;
} else {
return MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// from here down (except for fsctl buffer determination), everything is available for either wrapper. we may
// decide that the fsctl stuff should be moved as well
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID
RxInitializeLowIoContext (
PRX_CONTEXT RxContext,
ULONG Operation,
PLOWIO_CONTEXT LowIoContext
)
/*++
Routine Description:
This routine initializes the LowIO context in the RxContext.
Arguments:
RxContext - context of irp being processed.
Return Value:
none
--*/
{
PIRP Irp = RxContext->CurrentIrp;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PAGED_CODE();
ASSERT( LowIoContext == &RxContext->LowIoContext );
KeInitializeEvent( &RxContext->SyncEvent,
NotificationEvent,
FALSE );
//
// this ID is used to release the resource on behalf of another thread....
// e.g. it is used when an async routine completes to release the thread
// acquired by the first acquirer.
//
LowIoContext->ResourceThreadId = ExGetCurrentResourceThread();
LowIoContext->Operation = (USHORT)Operation;
switch (Operation) {
case LOWIO_OP_READ:
case LOWIO_OP_WRITE:
#if DBG
LowIoContext->ParamsFor.ReadWrite.ByteOffset = 0xffffffee; // no operation should start there!
LowIoContext->ParamsFor.ReadWrite.ByteCount = 0xeeeeeeee; // no operation should start there!
#endif
ASSERT( &IrpSp->Parameters.Read.Length == &IrpSp->Parameters.Write.Length );
ASSERT( &IrpSp->Parameters.Read.Key == &IrpSp->Parameters.Write.Key );
LowIoContext->ParamsFor.ReadWrite.Key = IrpSp->Parameters.Read.Key;
LowIoContext->ParamsFor.ReadWrite.Flags = (FlagOn( Irp->Flags, IRP_PAGING_IO ) ? LOWIO_READWRITEFLAG_PAGING_IO : 0);
break;
case LOWIO_OP_FSCTL:
case LOWIO_OP_IOCTL:
LowIoContext->ParamsFor.FsCtl.Flags = 0;
LowIoContext->ParamsFor.FsCtl.InputBufferLength = 0;
LowIoContext->ParamsFor.FsCtl.pInputBuffer = NULL;
LowIoContext->ParamsFor.FsCtl.OutputBufferLength = 0;
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = NULL;
LowIoContext->ParamsFor.FsCtl.MinorFunction = 0;
break;
case LOWIO_OP_SHAREDLOCK:
case LOWIO_OP_EXCLUSIVELOCK:
case LOWIO_OP_UNLOCK:
case LOWIO_OP_UNLOCK_MULTIPLE:
case LOWIO_OP_CLEAROUT:
case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
break;
default:
ASSERT( FALSE );
}
}
PVOID
RxLowIoGetBufferAddress (
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine gets the buffer corresponding to the Mdl in the LowIoContext.
Arguments:
RxContext - context for the request.
Return Value:
Mapped address
--*/
{
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PAGED_CODE();
if (LowIoContext->ParamsFor.ReadWrite.ByteCount > 0) {
ASSERT( LowIoContext->ParamsFor.ReadWrite.Buffer );
return MmGetSystemAddressForMdlSafe( LowIoContext->ParamsFor.ReadWrite.Buffer, NormalPagePriority );
} else {
return NULL;
}
}
NTSTATUS
RxLowIoSubmitRETRY (
IN PRX_CONTEXT RxContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine just calls LowIoSubmit; the completion routine was previously
stored so we just extract it and pass it in. This is called out of the Fsp
dispatcher for retrying at the low level.
Arguments:
RxContext - the usual
Return Value:
whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
--*/
{
PFCB Fcb = (PFCB)RxContext->pFcb;
PAGED_CODE();
return RxLowIoSubmit( RxContext, Irp, Fcb, RxContext->LowIoContext.CompletionRoutine );
}
NTSTATUS
RxLowIoCompletionTail (
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine is called by lowio routines at the very end...i.e. after the individual completion
routines are called.
Arguments:
RxContext - the RDBSS context
Return Value:
whatever value supplied by the caller.
--*/
{
NTSTATUS Status;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
ULONG Operation = LowIoContext->Operation;
BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
RxDbgTrace( +1, Dbg, ("RxLowIoCompletionTail, Operation=%08lx\n",LowIoContext->Operation) );
if ((KeGetCurrentIrql() < DISPATCH_LEVEL ) ||
(FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL ))) {
Status = RxContext->LowIoContext.CompletionRoutine( RxContext );
} else {
Status = STATUS_MORE_PROCESSING_REQUIRED;
}
if ((Status == STATUS_MORE_PROCESSING_REQUIRED) || (Status == STATUS_RETRY)) {
RxDbgTrace( -1, Dbg, ("RxLowIoCompletionTail wierdstatus, Status=%08lx\n", Status) );
return Status;
}
switch (Operation) {
case LOWIO_OP_READ:
case LOWIO_OP_WRITE:
if (FlagOn( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO )) {
RxDbgTrace( 0, Dbg, ("RxLowIoCompletionTail pagingio unblock\n") );
ExAcquireFastMutexUnsafe( &RxLowIoPagingIoSyncMutex );
RxRemoveFromOutStandingPagingOperationsList( RxContext );
ExReleaseFastMutexUnsafe( &RxLowIoPagingIoSyncMutex );
RxResumeBlockedOperations_ALL( RxContext );
}
break;
case LOWIO_OP_SHAREDLOCK:
case LOWIO_OP_EXCLUSIVELOCK:
case LOWIO_OP_UNLOCK:
case LOWIO_OP_UNLOCK_MULTIPLE:
case LOWIO_OP_CLEAROUT:
break;
case LOWIO_OP_FSCTL:
case LOWIO_OP_IOCTL:
case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
break;
default:
ASSERT( !"Valid Low Io Op Code" );
}
if (!FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL )) {
//
// if we're being called from lowiosubmit then just get out otherwise...do the completion
//
RxCompleteAsynchronousRequest( RxContext, Status );
}
RxDbgTrace(-1, Dbg, ("RxLowIoCompletionTail, Status=%08lx\n",Status));
return(Status);
}
NTSTATUS
RxLowIoCompletion (
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine must be called by the MiniRdr LowIo routines when they complete,
IF THEY HAVE INITIALLY RETURNED PENDING.
It behaves a bit differently depending on whether it's sync or async IO.
For sync, we just get back into the user's thread. For async, we first try
the completion routine directly. If we get MORE_PROCESSING, then we flip to
a thread and the routine will be recalled.
Arguments:
RxContext - the RDBSS context
Return Value:
Whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
The value M_P_R is very handy if this is being called for a Irp completion.
M_P_R causes the Irp completion guy to stop processing which is good since
the called completion routine may complete the packet.
--*/
{
NTSTATUS Status;
BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
if (SynchronousIo) {
RxSignalSynchronousWaiter( RxContext );
return STATUS_MORE_PROCESSING_REQUIRED;
}
RxDbgTrace( 0, Dbg, ("RxLowIoCompletion ASYNC\n") );
ASSERT( RxLowIoIsBufferLocked( &RxContext->LowIoContext ) );
Status = RxLowIoCompletionTail( RxContext );
//
// The called routine makes the decision as to whether it can continue. Many
// will ask for a post if we're at DPC level. Some will not.
//
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
RxPostToWorkerThread( RxFileSystemDeviceObject,
HyperCriticalWorkQueue,
&RxContext->WorkQueueItem,
RxLowIoCompletion,
RxContext );
} else if (Status == STATUS_RETRY) {
//
// I'm not too sure about this.
//
RxFsdPostRequestWithResume( RxContext, RxLowIoSubmitRETRY );
Status = STATUS_MORE_PROCESSING_REQUIRED;
}
return Status;
}
#if DBG
VOID
RxAssertFsctlIsLikeIoctl ()
{
ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.OutputBufferLength)
== FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.OutputBufferLength) );
ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.InputBufferLength)
== FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.InputBufferLength) );
ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.FsControlCode)
== FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.IoControlCode) );
ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.Type3InputBuffer)
== FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.Type3InputBuffer) );
}
#else
#define RxAssertFsctlIsLikeIoctl()
#endif //if DBG
NTSTATUS
NTAPI
RxLowIoPopulateFsctlInfo (
IN PRX_CONTEXT RxContext,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PAGED_CODE();
RxAssertFsctlIsLikeIoctl();
LowIoContext->ParamsFor.FsCtl.FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
LowIoContext->ParamsFor.FsCtl.InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
LowIoContext->ParamsFor.FsCtl.OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
LowIoContext->ParamsFor.FsCtl.MinorFunction = IrpSp->MinorFunction;
switch (LowIoContext->ParamsFor.FsCtl.FsControlCode & 3) {
case METHOD_BUFFERED:
LowIoContext->ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
break;
case METHOD_IN_DIRECT:
case METHOD_OUT_DIRECT:
LowIoContext->ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (Irp->MdlAddress != NULL) {
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
if (LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = NULL;
}
break;
case METHOD_NEITHER:
LowIoContext->ParamsFor.FsCtl.pInputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
break;
default:
ASSERT(!"Valid Method for Fs Control");
break;
}
return Status;
}
NTSTATUS
RxLowIoSubmit (
IN PRX_CONTEXT RxContext,
IN PIRP Irp,
IN PFCB Fcb,
PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
/*++
Routine Description:
This routine passes the request to the minirdr after setting up for completion. it then waits
or pends as appropriate.
Arguments:
RxContext - the usual
Return Value:
whatever value is returned by a callout....or by LowIoCompletion.
--*/
{
IN PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
IN PFILE_OBJECT FileObject = IrpSp->FileObject;
NTSTATUS Status = STATUS_SUCCESS;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
ULONG Operation = LowIoContext->Operation;
BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
PAGED_CODE();
LowIoContext->CompletionRoutine = CompletionRoutine;
RxDbgTrace(+1, Dbg, ("RxLowIoSubmit, Operation=%08lx\n",LowIoContext->Operation));
//
// if fcb is shadowed and user buffer are not already locked then try fast path
//
if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED ) &&
!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED )) {
RxContext->InformationToReturn = 0;
Status = RxShadowFastLowIo( RxContext, Irp );
if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
return Status;
}
Status = STATUS_SUCCESS;
}
switch (Operation) {
case LOWIO_OP_READ:
case LOWIO_OP_WRITE:
ASSERT( LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xffffffee );
ASSERT (LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xeeeeeeee );
Status = RxLockAndMapUserBufferForLowIo( RxContext, Irp, LowIoContext, Operation);
//
// NT paging IO is different from WIN9X so this may be different
//
if (FlagOn( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO )) {
ExAcquireFastMutexUnsafe( &RxLowIoPagingIoSyncMutex );
RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
RxInsertIntoOutStandingPagingOperationsList( RxContext, Operation );
ExReleaseFastMutexUnsafe( &RxLowIoPagingIoSyncMutex );
}
break;
case LOWIO_OP_FSCTL:
case LOWIO_OP_IOCTL:
Status = RxLowIoPopulateFsctlInfo( RxContext, Irp );
if (Status == STATUS_SUCCESS) {
if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0) &&
(LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL)) {
Status = STATUS_INVALID_PARAMETER;
}
if ((LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0) &&
(LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL)) {
Status = STATUS_INVALID_PARAMETER;
}
}
break;
case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
case LOWIO_OP_SHAREDLOCK:
case LOWIO_OP_EXCLUSIVELOCK:
case LOWIO_OP_UNLOCK:
case LOWIO_OP_UNLOCK_MULTIPLE:
case LOWIO_OP_CLEAROUT:
break;
default:
ASSERTMSG( "Invalid Low Io Op Code", FALSE );
Status = STATUS_INVALID_PARAMETER;
}
SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED );
if (Status == STATUS_SUCCESS) {
PMINIRDR_DISPATCH MiniRdrDispatch;
if (!SynchronousIo) {
//
// get ready for any arbitrary finish order...assume return of pending
//
InterlockedIncrement( &RxContext->ReferenceCount );
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP )) {
IoMarkIrpPending( Irp );
}
RxDbgTrace( 0, Dbg, ("RxLowIoSubmit, Operation is ASYNC!\n"));
}
MiniRdrDispatch = RxContext->RxDeviceObject->Dispatch;
if (MiniRdrDispatch != NULL) {
//
// Use private dispatch if lwio is enabled on this file
//
if (FlagOn( Fcb->FcbState, FCB_STATE_LWIO_ENABLED ) &&
(Fcb->MRxDispatch != NULL)) {
MiniRdrDispatch = Fcb->MRxDispatch;
}
do {
RxContext->InformationToReturn = 0;
Status = STATUS_MORE_PROCESSING_REQUIRED;
//
// handle shadowed fcb
//
if (FlagOn( Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED )) {
Status = RxShadowLowIo( RxContext, Irp, Fcb );
}
//
// call underlying mini-rdr if more processing is needed
//
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
MINIRDR_CALL( Status,
RxContext,
MiniRdrDispatch,
MRxLowIOSubmit[LowIoContext->Operation],
(RxContext) );
}
if (Status == STATUS_PENDING){
if (!SynchronousIo) {
goto FINALLY;
}
RxWaitSync( RxContext );
Status = RxContext->StoredStatus;
} else {
if (!SynchronousIo && (Status != STATUS_RETRY)) {
//
// we were wrong about pending..so clear the bit and deref
//
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP )) {
ClearFlag( IrpSp->Control, SL_PENDING_RETURNED );
}
InterlockedDecrement( &RxContext->ReferenceCount );
}
}
} while (Status == STATUS_RETRY);
} else {
Status = STATUS_INVALID_PARAMETER;
}
}
//
// you do not come here for pended,async IO
//
RxContext->StoredStatus = Status;
SetFlag( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL );
Status = RxLowIoCompletionTail( RxContext );
FINALLY:
RxDbgTrace( -1, Dbg, ("RxLowIoSubmit, Status=%08lx\n",Status) );
return Status;
}
VOID
RxInitializeLowIoPerFcbInfo(
PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
/*++
Routine Description:
This routine is called in FcbInitialization to initialize the LowIo part of the structure.
Arguments:
LowIoPerFcbInfo - the struct to be initialized
Return Value:
--*/
{
PAGED_CODE();
InitializeListHead( &LowIoPerFcbInfo->PagingIoReadsOutstanding );
InitializeListHead( &LowIoPerFcbInfo->PagingIoWritesOutstanding );
}