944 lines
27 KiB
C
944 lines
27 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
|
||
|