windows-nt/Source/XPSP1/NT/base/fs/rdr2/rxce/lowio.c

944 lines
27 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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, RxNewMapUserBuffer)
#pragma alloc_text(PAGE, RxMapSystemBuffer)
#pragma alloc_text(PAGE, RxInitializeLowIoContext)
#pragma alloc_text(PAGE, RxLowIoGetBufferAddress)
#pragma alloc_text(PAGE, RxLowIoSubmitRETRY)
#pragma alloc_text(PAGE, RxLowIoCompletionTail)
#pragma alloc_text(PAGE, RxLowIoCompletion)
#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) \
?&capFcb->Specific.Fcb.PagingIoReadsOutstanding \
:&capFcb->Specific.Fcb.PagingIoWritesOutstanding;\
InsertTailList(WhichList,&RxContext->RxContextSerializationQLinks); \
}
#define RxRemoveFromOutStandingPagingOperationsList(RxContext) { \
RemoveEntryList(&RxContext->RxContextSerializationQLinks); \
RxContext->RxContextSerializationQLinks.Flink = NULL; \
RxContext->RxContextSerializationQLinks.Blink = NULL; \
}
#ifndef WIN9X
FAST_MUTEX RxLowIoPagingIoSyncMutex;
//here we hiding the IO access flags
#define RxLockAndMapUserBufferForLowIo(RXCONTEXT,LOWIOCONTEXT,OPERATION) {\
RxLockUserBuffer( RXCONTEXT, \
(OPERATION==LOWIO_OP_READ)?IoWriteAccess:IoReadAccess,\
LOWIOCONTEXT->ParamsFor.ReadWrite.ByteCount ); \
if (RxNewMapUserBuffer(RXCONTEXT) == NULL) Status = STATUS_INSUFFICIENT_RESOURCES; \
LOWIOCONTEXT->ParamsFor.ReadWrite.Buffer = RxUserBufferFromContext(RXCONTEXT); \
}
//these next macros are a bit strange. the macro parameter is the RxContext.....people who have
// not defined appropriate capture macros can access out from there. on NT, we will just use the
// captured entities but we hide the actual field designators
#define RxIsPagingIo(RXCONTEXT) (FlagOn(capReqPacket->Flags,IRP_PAGING_IO))
#define RxUserBufferFromContext(RXCONTEXT) (capReqPacket->MdlAddress)
#if 0
//if capFcb->NetRoot is NULL, then this must be the device FCB!
#define RxGetMiniRdrDispatchForLowIo(RXCONTEXT) {\
if (capFcb->VNetRoot != NULL) { \
pMiniRdrDispatch = capFcb->MRxDispatch; \
} else { \
PV_NET_ROOT pVirtualNetRoot = (PV_NET_ROOT)capFileObject->FsContext2; \
pMiniRdrDispatch = pVirtualNetRoot->NetRoot->Dispatch; \
} \
}
#endif 0
#define RxGetMiniRdrDispatchForLowIo(RXCONTEXT) {\
pMiniRdrDispatch = RxContext->RxDeviceObject->Dispatch; \
}
#define RxMarkPendingForLowIo(RXCONTEXT) IoMarkIrpPending(capReqPacket)
#define RxUnmarkPendingForLowIo(RXCONTEXT) {\
capPARAMS->Control &= ~SL_PENDING_RETURNED; \
}
#define RxGetCurrentResourceThreadForLowIo(RXCONTEXT) \
(ExGetCurrentResourceThread())
//NT specific routines
VOID
RxLockUserBuffer (
IN PRX_CONTEXT RxContext,
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
--*/
{
RxCaptureRequestPacket;
PMDL Mdl = NULL;
PAGED_CODE();
if (capReqPacket->MdlAddress == NULL) {
ASSERT(!(capReqPacket->Flags & IRP_INPUT_OPERATION));
// Allocate the Mdl, and Raise if we fail.
if (BufferLength > 0) {
Mdl = IoAllocateMdl(
capReqPacket->UserBuffer,
BufferLength,
FALSE,
FALSE,
capReqPacket );
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,
capReqPacket->RequestorMode,
Operation );
} except(EXCEPTION_EXECUTE_HANDLER) {
NTSTATUS Status;
Status = GetExceptionCode();
IoFreeMdl( Mdl );
capReqPacket->MdlAddress = NULL;
SetFlag(
RxContext->Flags,
RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
RxRaiseStatus(
RxContext,
(FsRtlIsNtstatusExpected(Status) ?
Status :
STATUS_INVALID_USER_BUFFER));
}
}
}
} else {
Mdl = capReqPacket->MdlAddress;
ASSERT(RxLowIoIsMdlLocked(Mdl));
}
}
NTSTATUS
RxLockBuffer (
IN PRX_CONTEXT RxContext,
IN PVOID pBuffer,
IN ULONG BufferLength,
IN LOCK_OPERATION Operation,
OUT PMDL *pBufferMdlPtr
)
/*++
Routine Description:
This routine locks the input 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.
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.
pBufferMdl - a placeholder for a pointer to the locked down MDL
Return Value:
RxStatus(SUCCESS) - if the operation was successful
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
RxCaptureRequestPacket;
*pBufferMdlPtr = NULL;
// Allocate the Mdl, and Raise if we fail.
*pBufferMdlPtr = IoAllocateMdl(
pBuffer,
BufferLength,
FALSE,
FALSE,
capReqPacket);
if (*pBufferMdlPtr == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
// probe and lock down the buffer
try {
MmProbeAndLockPages(
*pBufferMdlPtr,
capReqPacket->RequestorMode,
Operation );
RxProtectMdlFromFree(*pBufferMdlPtr);
} except(EXCEPTION_EXECUTE_HANDLER) {
NTSTATUS Status;
Status = GetExceptionCode();
IoFreeMdl(*pBufferMdlPtr);
Status = FsRtlIsNtstatusExpected(Status) ?
Status :
STATUS_INVALID_USER_BUFFER;
}
}
return Status;
}
PVOID
RxMapSystemBuffer (
IN PRX_CONTEXT RxContext
)
/*++
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
--*/
{
RxCaptureRequestPacket;
PAGED_CODE();
if (capReqPacket->MdlAddress == NULL) {
return capReqPacket->AssociatedIrp.SystemBuffer;
} else {
ASSERT (!"there should not be an MDL in this irp!!!!!");
return MmGetSystemAddressForMdlSafe(
capReqPacket->MdlAddress, NormalPagePriority );
}
}
PVOID
RxNewMapUserBuffer (
IN PRX_CONTEXT RxContext
)
/*++
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
--*/
{
RxCaptureRequestPacket;
PAGED_CODE();
if (capReqPacket->MdlAddress == NULL) {
return capReqPacket->UserBuffer;
} else {
return MmGetSystemAddressForMdlSafe(
capReqPacket->MdlAddress,
NormalPagePriority );
}
}
#else
#define RxMarkPendingForLowIo(RXCONTEXT)
#define RxUnmarkPendingForLowIo(RXCONTEXT)
//CIA figure out how paging io works on win9x
#define RxIsPagingIo(RXCONTEXT) FALSE
#define RxGetCurrentResourceThreadForLowIo(RXCONTEXT) 11
#define RxLockAndMapUserBufferForLowIo(RXCONTEXT,LOWIOCONTEXT,OPERATION) {\
if(((LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer = \
RxAllocateMdl(capReqPacket->ir_data, capReqPacket->ir_length)) \
!= NULL) {\
NTSTATUS __Status = _RxProbeAndLockPages((LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer, \
KernelMode,\
(OPERATION==LOWIO_OP_READ)?IoWriteAccess:IoReadAccess\
); \
if (__Status != STATUS_SUCCESS) { \
IoFreeMdl((LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer); \
(LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer = NULL; \
} \
}\
}
#define RxGetMiniRdrDispatchForLowIo(RXCONTEXT) {\
PV_NET_ROOT pVirtualNetRoot = (PV_NET_ROOT)capReqPacket->ir_rh; \
pMiniRdrDispatch = pVirtualNetRoot->NetRoot->Dispatch; \
}
#endif //#ifndef WIN9X
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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(
PLOWIO_CONTEXT LowIoContext,
ULONG Operation
)
/*++
Routine Description:
This routine initializes the LowIO context in the RxContext.
Arguments:
RxContext - context of irp being processed.
Return Value:
none
--*/
{
PRX_CONTEXT RxContext = CONTAINING_RECORD(LowIoContext,RX_CONTEXT,LowIoContext);
RxCaptureRequestPacket; RxCaptureParamBlock;
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 = RxGetCurrentResourceThreadForLowIo(RxContext);
LowIoContext->Operation = (USHORT)Operation;
switch (Operation) {
case LOWIO_OP_READ:
case LOWIO_OP_WRITE:
IF_DEBUG {
LowIoContext->ParamsFor.ReadWrite.ByteOffset = 0xffffffee; //no operation should start there!
LowIoContext->ParamsFor.ReadWrite.ByteCount = 0xeeeeeeee; //no operation should start there!
}
ASSERT (&capPARAMS->Parameters.Read.Length == &capPARAMS->Parameters.Write.Length);
ASSERT (&capPARAMS->Parameters.Read.Key == &capPARAMS->Parameters.Write.Key);
LowIoContext->ParamsFor.ReadWrite.Key = capPARAMS->Parameters.Read.Key;
LowIoContext->ParamsFor.ReadWrite.Flags = 0
| (RxIsPagingIo(RxContext)?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
)
/*++
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).
--*/
{
PAGED_CODE();
return(RxLowIoSubmit(RxContext,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);
PAGED_CODE();
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!
--*/
{
RxCaptureParamBlock;
#ifndef WIN9X
NTSTATUS Status;
#endif
BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
PAGED_CODE();
if (SynchronousIo) {
RxSignalSynchronousWaiter(RxContext);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
#ifdef WIN9X
RxDbgTrace(0, Dbg, ("We SHOULD NEVER GET HERE\n"));
ASSERT(FALSE);
#else
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) {
RxFsdPostRequestWithResume(RxContext,RxLowIoCompletion);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
//i'm not too sure about this
if (Status == STATUS_RETRY) {
RxFsdPostRequestWithResume(RxContext,RxLowIoSubmitRETRY);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
return(Status);
#endif
}
#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
)
{
NTSTATUS Status = STATUS_SUCCESS;
RxCaptureRequestPacket;
RxCaptureParamBlock;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PAGED_CODE();
RxAssertFsctlIsLikeIoctl();
LowIoContext->ParamsFor.FsCtl.FsControlCode =
capPARAMS->Parameters.FileSystemControl.FsControlCode;
LowIoContext->ParamsFor.FsCtl.InputBufferLength =
capPARAMS->Parameters.FileSystemControl.InputBufferLength;
LowIoContext->ParamsFor.FsCtl.OutputBufferLength =
capPARAMS->Parameters.FileSystemControl.OutputBufferLength;
LowIoContext->ParamsFor.FsCtl.MinorFunction = capPARAMS->MinorFunction;
switch (LowIoContext->ParamsFor.FsCtl.FsControlCode & 3) {
case METHOD_BUFFERED:
{
LowIoContext->ParamsFor.FsCtl.pInputBuffer = capReqPacket->AssociatedIrp.SystemBuffer;
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = capReqPacket->AssociatedIrp.SystemBuffer;
}
break;
case METHOD_IN_DIRECT:
case METHOD_OUT_DIRECT:
{
LowIoContext->ParamsFor.FsCtl.pInputBuffer = capReqPacket->AssociatedIrp.SystemBuffer;
if (capReqPacket->MdlAddress!=NULL) {
LowIoContext->ParamsFor.FsCtl.pOutputBuffer =
MmGetSystemAddressForMdlSafe(
capReqPacket->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 = capPARAMS->Parameters.FileSystemControl.Type3InputBuffer;
LowIoContext->ParamsFor.FsCtl.pOutputBuffer = capReqPacket->UserBuffer;
}
break;
default:
ASSERT(!"Valid Method for Fs Control");
break;
}
return Status;
}
NTSTATUS
RxLowIoSubmit (
IN PRX_CONTEXT RxContext,
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.
--*/
{
RxCaptureRequestPacket;
RxCaptureFcb;
RxCaptureFobx;
RxCaptureParamBlock;
RxCaptureFileObject;
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));
switch (Operation) {
case LOWIO_OP_READ:
case LOWIO_OP_WRITE:
ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xffffffee);
ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xeeeeeeee);
RxLockAndMapUserBufferForLowIo(RxContext,LowIoContext,Operation);
#ifndef WIN9X
// 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);
}
#else
if (!LowIoContext->ParamsFor.ReadWrite.Buffer) {
//
// Couldn't get mdl for data!
//
return(STATUS_INSUFFICIENT_RESOURCES);
}
#endif //ifndef WIN9X
break;
//can't do much to make this OS independent
case LOWIO_OP_FSCTL:
case LOWIO_OP_IOCTL:
Status = RxLowIoPopulateFsctlInfo(RxContext);
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:
ASSERT(!"Valid Low Io Op Code");
Status = STATUS_INVALID_PARAMETER;
}
SetFlag(RxContext->Flags,RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
if (Status==STATUS_SUCCESS) {
PMINIRDR_DISPATCH pMiniRdrDispatch;
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)) {
RxMarkPendingForLowIo(RxContext);
}
RxDbgTrace( 0, Dbg, ("RxLowIoSubmit, Operation is ASYNC!\n"));
}
pMiniRdrDispatch = NULL;
RxGetMiniRdrDispatchForLowIo(RxContext);
if (pMiniRdrDispatch != NULL) {
do {
RxContext->InformationToReturn = 0;
MINIRDR_CALL(
Status,
RxContext,
pMiniRdrDispatch,
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)) {
RxUnmarkPendingForLowIo(RxContext);
}
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);
}