|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
InnerIo.c
Abstract:
This module implements the read, write, and lockctrl routines for the proxy minirdr Author:
Joe Linn [JoeLinn] 11-Oct-1994
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_READ)
#ifdef ALLOC_PRAGMA
#endif
NTSTATUS MRxProxyBuildAsynchronousRequest( IN PRX_CONTEXT RxContext, IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL )
/*++
Routine Description:
This routine builds an I/O Request Packet (IRP) suitable for a File System Driver (FSD) to use in requesting an I/O operation from a device driver. The request (RxContext->MajorFunction) must be one of the following request codes:
IRP_MJ_READ IRP_MJ_WRITE IRP_MJ_DIRECTORY_CONTROL IRP_MJ_FLUSH_BUFFERS //IRP_MJ_SHUTDOWN (not yet implemented)
Arguments:
CompletionRoutine - the IrpCompletionRoutine
Return Value:
The function value is a pointer to the IRP representing the specified request.
--*/
{ PIRP irp; PIO_STACK_LOCATION irpSp; ULONG MajorFunction = RxContext->MajorFunction; RxCaptureFcb; RxCaptureFobx; PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);
PMRXPROXY_ASYNCENGINE_CONTEXT AsyncEngineContext = (PMRXPROXY_ASYNCENGINE_CONTEXT)(pMRxProxyContext->AsyncEngineContext);
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(capFobx->pSrvOpen); //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb);
PDEVICE_OBJECT DeviceObject = proxySrvOpen->UnderlyingDeviceObject; PFILE_OBJECT FileObject = proxySrvOpen->UnderlyingFileObject;
LARGE_INTEGER ZeroAsLI; ULONG MdlLength = 0;
PAGED_CODE();
ASSERT (proxySrvOpen->UnderlyingFileObject);
if (DeviceObject->Flags & DO_BUFFERED_IO) { //i cannot handled buffered_io devices....sigh
return STATUS_INVALID_DEVICE_REQUEST; }
RxDbgTrace(0, Dbg, ("MRxProxyBuildAsynchronousRequest %08lx %08lx len/off=%08lx %08lx\n", RxContext,SrvOpen, LowIoContext->ParamsFor.ReadWrite.ByteCount, (ULONG)LowIoContext->ParamsFor.ReadWrite.ByteOffset));
RxLog(("BuildAsyncIrp %lx %lx %lx %lx", RxContext,SrvOpen, LowIoContext->ParamsFor.ReadWrite.ByteCount, (ULONG)LowIoContext->ParamsFor.ReadWrite.ByteOffset));
ZeroAsLI.QuadPart = 0;
// irp = IoBuildAsynchronousFsdRequest(
// MajorFunction,
// DeviceObject,
// NULL,
// 0,
// &ZeroAsLI,
// NULL
// );
//
// if (!irp) {
// return STATUS_INSUFFICIENT_RESOURCES;
// }
irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); //why not charge???
if (!irp) { return STATUS_INSUFFICIENT_RESOURCES; }
//
// Set current thread for IoSetHardErrorOrVerifyDevice.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Get a pointer to the stack location of the first driver which will be
// invoked. This is where the function codes and the parameters are set.
//
irpSp = IoGetNextIrpStackLocation( irp ); //ok4ioget
irpSp->MajorFunction = (UCHAR) MajorFunction; irpSp->FileObject = FileObject; //ok4->FileObj
RxLog(("BuildAsyncIrpFo %lx %lx",RxContext,FileObject));
{ BOOLEAN EnableCalls = CompletionRoutine!=NULL;
IoSetCompletionRoutine(irp, CompletionRoutine, RxContext, EnableCalls,EnableCalls,EnableCalls); }
if ( (MajorFunction == IRP_MJ_READ) || (MajorFunction == IRP_MJ_WRITE) ) {
// never paging io
BOOLEAN PagingIo = FALSE; //BOOLEAN PagingIo =
// BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO);
irp->Flags |= IRP_NOCACHE;
//
// Set the parameters according to whether this is a read or a write
// operation. Notice that these parameters must be set even if the
// driver has not specified buffered or direct I/O.
//
ASSERT (&irpSp->Parameters.Write.Key == &irpSp->Parameters.Read.Key); ASSERT (&irpSp->Parameters.Write.Length == &irpSp->Parameters.Read.Length); ASSERT (&irpSp->Parameters.Write.ByteOffset == &irpSp->Parameters.Read.ByteOffset); irpSp->Parameters.Read.Key = LowIoContext->ParamsFor.ReadWrite.Key; irpSp->Parameters.Read.ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset; irp->RequestorMode = KernelMode;
irp->UserBuffer = RxLowIoGetBufferAddress(RxContext);
MdlLength = RxContext->CurrentIrp->MdlAddress->ByteCount;
if (PagingIo) { irpSp->Parameters.Read.Length = MdlLength; } else { irpSp->Parameters.Read.Length = LowIoContext->ParamsFor.ReadWrite.ByteCount; }
} else if (MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
MdlLength = 0; //nothing else to do!!!
} else {
FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass; PVOID Buffer = RxContext->Info.Buffer; PULONG pLengthRemaining = &RxContext->Info.LengthRemaining; BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
ASSERT( MajorFunction == IRP_MJ_DIRECTORY_CONTROL ); irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY; //CODE.IMPROVEMENT it would be better to actually get the stuff out of the context.info
irpSp->Parameters.QueryDirectory = RxContext->CurrentIrpSp->Parameters.QueryDirectory; ASSERT ( (irpSp->Parameters.QueryDirectory.FileInformationClass == FileInformationClass) && (irpSp->Parameters.QueryDirectory.Length == *pLengthRemaining) ); irpSp->Flags = RxContext->CurrentIrpSp->Flags; irp->UserBuffer = Buffer; MdlLength = *pLengthRemaining;
if (Wait) { irp->Flags |= IRP_SYNCHRONOUS_API; } }
// Build an mdl if necessary....
if (MdlLength != 0) { irp->MdlAddress = IoAllocateMdl(irp->UserBuffer,MdlLength, FALSE,FALSE,NULL); if (!irp->MdlAddress) { //whoops.......sorry..........
IoFreeIrp(irp); return(STATUS_INSUFFICIENT_RESOURCES); }
MmBuildMdlForNonPagedPool(irp->MdlAddress); }
//
// Finally, return a pointer to the IRP.
//
AsyncEngineContext->CalldownIrp = irp; RxLog(("BAsyIrpX %lx %lx %lx %lx %lx %lx %lx", RxContext, irpSp->MajorFunction, irpSp->Flags, irpSp->Parameters.Others.Argument1, irpSp->Parameters.Others.Argument2, irpSp->Parameters.Others.Argument3, irpSp->Parameters.Others.Argument4)); return STATUS_SUCCESS; }
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//
// The local debug trace level
//
#undef Dbg
#define Dbg (DEBUG_TRACE_WRITE)
//everything else in here is ifdef'd out....also CODE.IMPROVEMENT we should change over
//to a common irp building routine in Rx. the code is already in the csc driver
#if 0
NTSTATUS MRxProxyBuildInnerIoAsyncWrite ( IN PRX_CONTEXT RxContext, IN PBYTE Buffer, IN ULONG WriteByteCount, IN PLARGE_INTEGER FileOffset, IN OUT PIRP *CalldownIrp )
/*++
Routine Description:
This routine fills in the calldown irp for a proxy read
Arguments:
RxContext, PBYTE Buffer - the write buffer ULONG Count - amount of data to written PLARGE_INTEGER FileOffset - fileoffset where the write begins PIRP *CallDownIrp - where the Irp is to be stored
Return Value:
NTSTATUS - Returns the status for the write
--*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; RxCaptureFobx; PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);
RxDbgTrace(+1, Dbg, ("MRxProxyInnerIoWrite.... ByteCount = %08lx, ByteOffset = %08lx %08lx\n", LowIoContext->ParamsFor.ReadWrite.ByteCount, FileOffset->LowPart, FileOffset->HighPart));
RxLog(("MRxProxyInnerIoWrite %lx %lx %lx", SrvOpen, LowIoContext->ParamsFor.ReadWrite.ByteCount, FileOffset->LowPart));
RxDbgTrace ( 0, Dbg, ( "MRxProxyInnerIoWrite.... ->Buffer = %8lx\n", Buffer));
*CalldownIrp = MRxProxyBuildAsynchronousReadWriteRequest( RxContext, // IN PVOID Context
MRxProxyAsyncEngineCalldownIrpCompletion // IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
);
if (!*CalldownIrp){ Status = (STATUS_INSUFFICIENT_RESOURCES); }
RxDbgTrace(-1, Dbg, ("MRxProxyInnerIoWrite.... exit\n"));
return(Status); }
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//
// The local debug trace level
//
#undef Dbg
#define Dbg (DEBUG_TRACE_LOCKCTRL)
PIRP MRxBuildLockRequest ( IN PIRP irp OPTIONAL, IN PFILE_OBJECT fileObject, IN PETHREAD UsersThread, IN UCHAR MinorCode, IN RXVBO ByteOffset, IN PLARGE_INTEGER Length, IN ULONG Key, IN UCHAR Flags, IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL, IN PVOID Context OPTIONAL )
/*++
Routine Description:
This function builds an I/O request packet for a lock request.
Arguments:
Irp - Supplies a pointer to an IRP; allocates one if one is not provided.
FileObject - Supplies a pointer the file object to which this request is directed. This pointer is copied into the IRP, so that the called driver can find its file-based context. NOTE THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure that the file object is not deleted while the I/O operation is in progress. The proxy minirdr accomplishes this by holding a pointer (a REFERENCED ptr) to the fileobject in its srvopen while the fileobject is open.
Context - Supplies a PVOID value that is passed to the completion routine.
StartingBlock - the block number of the beginning of the locked range.
ByteOffset - the offset within block of the beginning of the locked range.
Length - the length of the locked range.
Key - the key value to be associated with the lock.
Return Value:
None.
--*/
{ PDEVICE_OBJECT deviceObject; PIO_STACK_LOCATION irpSp;
PAGED_CODE( );
deviceObject = IoGetRelatedDeviceObject( fileObject );
//
// Allocate and initialize the I/O Request Packet (IRP) for this operation.
// The allocation is performed with an exception handler in case the
// caller does not have enough quota to allocate the packet.
if (irp) { ASSERT( irp->StackCount >= deviceObject->StackSize ); } else { irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); //joejoe should i charge quota??
}
if (!irp) {
//
// An IRP could not be allocated.
return NULL; }
// we have to make sure that the thread that takes the lock is the same as the one that reads
irp->Tail.Overlay.Thread = UsersThread; irp->RequestorMode = KernelMode;
//
// Get a pointer to the stack location for the first driver. This will be
// used to pass the original function codes and parameters.
//
irpSp = IoGetNextIrpStackLocation( irp );
{ BOOLEAN EnableCalls = CompletionRoutine!=NULL;
IoSetCompletionRoutine(irp, CompletionRoutine, Context, EnableCalls,EnableCalls,EnableCalls); }
irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL; irpSp->MinorFunction = MinorCode; irpSp->FileObject = fileObject; //ok4->FileObj
irpSp->DeviceObject = deviceObject;
irpSp->Flags = Flags;
irpSp->Parameters.LockControl.Length = Length; irpSp->Parameters.LockControl.Key = Key; irpSp->Parameters.LockControl.ByteOffset.QuadPart = ByteOffset;
return irp;
}
NTSTATUS MRxProxyCalldownLockCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP CalldownIrp, IN PVOID Context )
/*++
Routine Description:
This is the I/O completion routine for calldown lock requests. we just call the lowio completion and exit
Arguments:
DeviceObject - Pointer to target device object for the request.
CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem
Context - Irpcontext of the original request to the rdbss
Return Value:
NTSTATUS - (STATUS_MORE_PROCESSING_REQUIRED) is returned.
--*/
{ PRX_CONTEXT RxContext = Context;
RxDbgTrace ( 0, Dbg, ("MRxProxyCalldownLockCompletion = %08lx\n", 0)); //DbgBreakPoint();
if (CalldownIrp->PendingReturned){ RxContext->CurrentIrp->IoStatus = CalldownIrp->IoStatus; RxContext->StoredStatus = CalldownIrp->IoStatus.Status; } RxLowIoCompletion(RxContext);
IoFreeIrp(CalldownIrp); return((STATUS_MORE_PROCESSING_REQUIRED)); }
NTSTATUS MRxProxyLocks ( IN PRX_CONTEXT RxContext )
/*++
Routine Description:
This routine implements proxy read call. we fill in the info and stuff here BUT we do not complete the Irp.
Arguments:
Return Value:
NTSTATUS - Returns the status for the read
--*/
{ NTSTATUS Status; RxCaptureRequestPacket; PIRP CalldownIrp; RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock; PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PSRV_OPEN SrvOpen = capFobx->SrvOpen; PMRX_LOCAL_SRV_OPEN proxySrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
BOOLEAN Wait = FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)!=0; PLARGE_INTEGER LengthAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length; PLARGE_INTEGER OffsetAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.ByteOffset;
char *whichop;
switch (LowIoContext->Operation) { case LOWIO_OP_SHAREDLOCK: whichop = "SHAREDLOCK"; break; case LOWIO_OP_EXCLUSIVELOCK: whichop = "EXCLUSIVELOCK"; break; case LOWIO_OP_UNLOCK: whichop = "UNLOCK"; break; case LOWIO_OP_UNLOCKALL: whichop = "UNLOCKALL"; break; case LOWIO_OP_UNLOCKALLBYKEY: whichop = "UNLOCKALLBYKEY"; break; }
RxDbgTrace (+1, Dbg, ("MRxExclusiveLock...%s, Flags = %08lx, Key = %08lx\n", whichop, LowIoContext->ParamsFor.Locks.Flags, LowIoContext->ParamsFor.Locks.Key)); RxDbgTrace( 0, Dbg, (" ->Length = %08lx %08lx\n", LengthAsLI->LowPart, LengthAsLI->HighPart)); RxDbgTrace( 0, Dbg, (" ->ByteOffset = %08lx %08lx\n", OffsetAsLI->LowPart, OffsetAsLI->HighPart)); RxLog(('kLz',3,SrvOpen, LengthAsLI->LowPart, OffsetAsLI->LowPart));
ASSERT (proxySrvOpen->UnderlyingFileObject);
CalldownIrp = MRxBuildLockRequest ( NULL ,//IN PIRP irp OPTIONAL,
proxySrvOpen->UnderlyingFileObject ,//IN PFILE_OBJECT fileObject,
capReqPacket->Tail.Overlay.Thread ,//IN PTHREAD UsersThread,
capPARAMS->MinorFunction ,//IN UCHAR MinorCode,
LowIoContext->ParamsFor.Locks.ByteOffset,//IN RXVBO ByteOffset,
LengthAsLI ,//IN PLARGE_INTEGER Length,
LowIoContext->ParamsFor.Locks.Key ,//IN ULONG Key,
(UCHAR)LowIoContext->ParamsFor.Locks.Flags ,//IN UCHAR Flags,
MRxProxyCalldownLockCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
RxContext //IN PVOID Context OPTIONAL
);
if (!CalldownIrp){ Status = RxContext->StoredStatus = (STATUS_INSUFFICIENT_RESOURCES); return(Status); }
Status = RxContext->StoredStatus = IoCallDriver( proxySrvOpen->UnderlyingDeviceObject, CalldownIrp );
if (Status != (STATUS_PENDING)) { //copy up the status
capReqPacket->IoStatus = CalldownIrp->IoStatus; }
RxDbgTrace ( 0, Dbg, (" ---->Initial Status = %08lx\n", Status)); RxDbgTrace(-1, Dbg, (" ------> Initial Block status/Info = %08lx %08lx\n", capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information));
return(Status); }
NTSTATUS MRxProxyAssertLockCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP CalldownIrp, IN PVOID Context )
/*++
Routine Description:
This is the I/O completion routine for calldown ios like querydirectory. the rub is that we turned synchronous opens into async opens. what we do here is set an event (in the case of a pended packet for a sync that we turned async) OR copyup the status;complete;free in the case of a call that was always async.
Arguments:
DeviceObject - Pointer to target device object for the request.
CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem
Context - Irpcontext of the original request to the rdbss
Return Value:
NTSTATUS - If (STATUS_MORE_PROCESSING_REQUIRED) is returned.
--*/
{ PKEVENT Event = Context;
RxDbgTrace ( 0, Dbg, (" MRxProxyAssertLockCompletion = %08lx\n", 0));
if (CalldownIrp->PendingReturned){ KeSetEvent( Event, 0, FALSE ); }
return((STATUS_MORE_PROCESSING_REQUIRED)); }
NTSTATUS MRxProxyAssertBufferedFileLocks ( IN PSRV_OPEN SrvOpen )
/*++
Routine Description:
This routine is called to assert all buffered file locks on a srvopen.
Arguments:
SrvOpen - Supplies the file whose locks are to be asserted.
Return Value:
NTSTATUS - Status of operation.
--*/
{ NTSTATUS Status; PFILE_LOCK_INFO FileLock; PFCB Fcb = SrvOpen->Fcb;
PIRP CalldownIrp = NULL;
PMRX_LOCAL_SRV_OPEN proxySrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
UCHAR Flags; BOOLEAN Wait = TRUE;
PKEVENT Event;
PAGED_CODE();
RxDbgTrace (+1, Dbg, ("MRxProxyAssertBufferedFileLocks SrvOpen = %08lx", SrvOpen)); ASSERT (proxySrvOpen->UnderlyingFileObject);
Event = RxAllocatePoolWithTag( NonPagedPool, sizeof(KEVENT), 'LAxR' ); if (!CalldownIrp){ Status = (STATUS_INSUFFICIENT_RESOURCES); return(Status); }
try { for (FileLock = FsRtlGetNextFileLock(&Fcb->Specific.Fcb.FileLock, TRUE); FileLock != NULL; FileLock = FsRtlGetNextFileLock(&Fcb->Specific.Fcb.FileLock, FALSE)) {
RxDbgTrace (0, Dbg, ("MRxProxyAssertBufferedFileLocks Exclusive = %08lx, Key = %08lx\n", FileLock->ExclusiveLock, FileLock->Key)); RxDbgTrace( 0, Dbg, (" ->Length = %08lx %08lx\n", FileLock->Length.LowPart, FileLock->Length.HighPart)); RxDbgTrace( 0, Dbg, (" ->ByteOffset = %08lx %08lx\n", FileLock->StartingByte.LowPart, FileLock->StartingByte.HighPart));
if (FileLock->ExclusiveLock) { Flags = SL_EXCLUSIVE_LOCK | SL_FAIL_IMMEDIATELY; } else { Flags = SL_FAIL_IMMEDIATELY; }
//joejoe we should reuse the irp.........
CalldownIrp = MRxBuildLockRequest ( NULL ,//IN PIRP irp OPTIONAL,
proxySrvOpen->UnderlyingFileObject ,//IN PFILE_OBJECT fileObject,
proxySrvOpen->OriginalThread ,//IN PTHREAD UsersThread,
IRP_MN_LOCK ,//IN UCHAR MinorCode,
FileLock->StartingByte.QuadPart ,//IN RXVBO ByteOffset,
&FileLock->Length ,//IN PLARGE_INTEGER Length,
FileLock->Key ,//IN ULONG Key,
Flags ,//IN UCHAR Flags,
MRxProxyAssertLockCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
&Event //IN PVOID Context OPTIONAL
);
if (!CalldownIrp){ Status = (STATUS_INSUFFICIENT_RESOURCES); try_return(Status); }
CalldownIrp->Flags |= IRP_SYNCHRONOUS_API;
KeInitializeEvent( Event, SynchronizationEvent, FALSE );
Status = IoCallDriver( proxySrvOpen->UnderlyingDeviceObject, CalldownIrp );
if (Status == (STATUS_PENDING)) { KeWaitForSingleObject(Event, UserRequest, KernelMode, FALSE, NULL); Status = CalldownIrp->IoStatus.Status; }
RxDbgTrace ( 0, Dbg, (" ---->PerLock Status = %08lx\n", Status));
}
try_exit: NOTHING;
} finally {
ExFreePool(Event); if (CalldownIrp) { IoFreeIrp(CalldownIrp); } }
RxDbgTrace (-1, Dbg, ("--------->Final Status = %08lx\n", Status)); return Status;
}
#endif
|