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.
968 lines
25 KiB
968 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
shadow.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that implements local read/write operations for shadow
|
|
FCB
|
|
|
|
Author:
|
|
|
|
Ahmed Mohamed (ahmedm) 15-Dec-2001
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// define this so that rdbsstrace flag works, just use the lowio one since shadow is part of it
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_LOWIO)
|
|
|
|
#define RxGetShadowSrvOpenContext(SrvOpen) ((PMRXSHADOW_SRV_OPEN) (SrvOpen)->ShadowContext)
|
|
|
|
#define RxShadowLockKeyLock(LowIoContext, ShadowCtx) (LowIoContext->ParamsFor.Locks.Key)
|
|
#define RxShadowLockKey(LowIoContext, ShadowCtx) (LowIoContext->ParamsFor.ReadWrite.Key)
|
|
|
|
typedef struct {
|
|
PIRP Irp;
|
|
BOOLEAN Cancelable;
|
|
LONG Refcnt;
|
|
} RX_SHADOW_CONTEXT, *PRX_SHADOW_CONTEXT;
|
|
|
|
extern PETHREAD RxSpinUpRequestsThread;
|
|
|
|
NTSTATUS
|
|
RxShadowVerifyIoParameters(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PFILE_OBJECT FileObject,
|
|
PVOID Buffer,
|
|
ULONG Length,
|
|
PLARGE_INTEGER FileOffset
|
|
)
|
|
{
|
|
|
|
if (!FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING )) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// The file was opened without intermediate buffering enabled.
|
|
// Check that the Buffer is properly aligned, and that the
|
|
// length is an integral number of the block size.
|
|
//
|
|
|
|
if ((DeviceObject->SectorSize &&
|
|
(Length & (DeviceObject->SectorSize - 1))) ||
|
|
((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement)) {
|
|
|
|
//
|
|
// Check for sector sizes that are not a power of two.
|
|
//
|
|
|
|
if ((DeviceObject->SectorSize && (Length % DeviceObject->SectorSize)) ||
|
|
((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement)) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If a ByteOffset parameter was specified, ensure that it is
|
|
// is of the proper type.
|
|
//
|
|
|
|
if ((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
|
|
(FileOffset->HighPart == -1)) {
|
|
|
|
NOTHING;
|
|
|
|
} else if ((FileOffset->LowPart == FILE_USE_FILE_POINTER_POSITION) &&
|
|
(FileOffset->HighPart == -1) &&
|
|
FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO )) {
|
|
|
|
NOTHING;
|
|
|
|
} else if (DeviceObject->SectorSize &&
|
|
(FileOffset->LowPart & (DeviceObject->SectorSize - 1))) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxShadowBuildAsynchronousRequest (
|
|
IN PIRP OriginalIrp,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PFCB Fcb,
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PMRXSHADOW_SRV_OPEN LocalSrvOpen,
|
|
IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
|
IN PVOID Arg,
|
|
OUT PIRP *Irp
|
|
)
|
|
/*++
|
|
|
|
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:
|
|
|
|
RxContext - The RDBSS context.
|
|
|
|
CompletionRoutine - The Irp CompletionRoutine.
|
|
|
|
Return Value:
|
|
|
|
The return status of the operation.
|
|
|
|
--*/
|
|
{
|
|
PIRP NewIrp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
ULONG MajorFunction = RxContext->MajorFunction;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
LONG Length;
|
|
|
|
*Irp = NULL;
|
|
|
|
if ((MajorFunction != IRP_MJ_READ) &&
|
|
(MajorFunction != IRP_MJ_WRITE) &&
|
|
(MajorFunction != IRP_MJ_LOCK_CONTROL)) {
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
IF_DEBUG {
|
|
PFOBX Fobx = (PFOBX)RxContext->pFobx;
|
|
|
|
ASSERT( Fobx != NULL );
|
|
ASSERT( Fobx->pSrvOpen == RxContext->pRelevantSrvOpen );
|
|
}
|
|
|
|
NewIrp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
|
|
if (!NewIrp) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Set current thread for IoSetHardErrorOrVerifyDevice.
|
|
//
|
|
|
|
NewIrp->Tail.Overlay.Thread = RxSpinUpRequestsThread; //PsGetCurrentThread();
|
|
NewIrp->Tail.Overlay.OriginalFileObject = FileObject;
|
|
NewIrp->RequestorMode = KernelMode;
|
|
NewIrp->AssociatedIrp.SystemBuffer = (PVOID)NULL;
|
|
|
|
//
|
|
// 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( NewIrp );
|
|
IrpSp->MajorFunction = (UCHAR) MajorFunction;
|
|
IrpSp->MinorFunction = 0;
|
|
IrpSp->FileObject = FileObject;
|
|
IrpSp->DeviceObject = DeviceObject;
|
|
|
|
if (CompletionRoutine != NULL) {
|
|
|
|
IoSetCompletionRoutine( NewIrp,
|
|
CompletionRoutine,
|
|
Arg,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE );
|
|
}
|
|
|
|
NewIrp->Flags = 0;
|
|
SetFlag( NewIrp->Flags, FlagOn( OriginalIrp->Flags, IRP_SYNCHRONOUS_API | IRP_NOCACHE ) );
|
|
|
|
if (MajorFunction == IRP_MJ_LOCK_CONTROL) {
|
|
|
|
//
|
|
// We need to tag the lock flag
|
|
//
|
|
|
|
FileObject->LockOperation = TRUE;
|
|
|
|
IrpSp->MinorFunction = RxContext->MinorFunction;
|
|
IrpSp->Flags = (UCHAR)LowIoContext->ParamsFor.Locks.Flags;
|
|
IrpSp->Parameters.LockControl.Length = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length;
|
|
IrpSp->Parameters.LockControl.Key = RxShadowLockKeyLock( LowIoContext, LocalSrvOpen );
|
|
IrpSp->Parameters.LockControl.ByteOffset.QuadPart = LowIoContext->ParamsFor.Locks.ByteOffset;
|
|
NewIrp->Tail.Overlay.AuxiliaryBuffer = OriginalIrp->Tail.Overlay.AuxiliaryBuffer;
|
|
|
|
*Irp = NewIrp;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
//
|
|
// if file is opened with no intermediate bufffering then set no cache flag
|
|
//
|
|
|
|
if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING )) {
|
|
SetFlag( NewIrp->Flags, IRP_NOCACHE );
|
|
}
|
|
|
|
Length = LowIoContext->ParamsFor.ReadWrite.ByteCount;
|
|
|
|
if (MajorFunction == IRP_MJ_WRITE) {
|
|
|
|
if (FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) {
|
|
IrpSp->Flags = SL_WRITE_THROUGH;
|
|
}
|
|
|
|
IrpSp->Parameters.Write.ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
IrpSp->Parameters.Write.Length = Length;
|
|
IrpSp->Parameters.Write.Key = RxShadowLockKey( LowIoContext, LocalSrvOpen );
|
|
|
|
} else {
|
|
|
|
IrpSp->Parameters.Read.ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
IrpSp->Parameters.Read.Length = Length;
|
|
IrpSp->Parameters.Read.Key = RxShadowLockKey( LowIoContext, LocalSrvOpen );
|
|
}
|
|
|
|
NewIrp->UserBuffer = OriginalIrp->UserBuffer;
|
|
NewIrp->MdlAddress = RxContext->LowIoContext.ParamsFor.ReadWrite.Buffer;
|
|
if (NewIrp->MdlAddress != NULL) {
|
|
|
|
NewIrp->UserBuffer = MmGetMdlVirtualAddress( NewIrp->MdlAddress );
|
|
|
|
if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP )) {
|
|
|
|
//
|
|
// we must map the mdl into system address space and use the system address instead
|
|
//
|
|
|
|
NewIrp->UserBuffer = MmGetSystemAddressForMdlSafe( NewIrp->MdlAddress, NormalPagePriority );
|
|
|
|
//
|
|
// we need to zap out the mdl address, otherwise the filesystem complains that the
|
|
// userbuffer and the mdl startva are not the same
|
|
//
|
|
|
|
NewIrp->MdlAddress = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, return a pointer to the IRP.
|
|
//
|
|
|
|
*Irp = NewIrp;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxShadowCommonCompletion (
|
|
PRX_CONTEXT RxContext,
|
|
PIRP Irp,
|
|
NTSTATUS Status,
|
|
ULONG_PTR Information
|
|
)
|
|
{
|
|
PRX_SHADOW_CONTEXT Context;
|
|
BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
|
|
|
|
//
|
|
// Clear the MDL address from the IRP if it is a re-use of our own. Do this before completion
|
|
// so we can successfully read the Buffer MDL from the LOWIO_CONTEXT
|
|
//
|
|
if ( (Irp->MdlAddress == RxContext->LowIoContext.ParamsFor.ReadWrite.Buffer) &&
|
|
( (RxContext->MajorFunction == IRP_MJ_READ) ||
|
|
(RxContext->MajorFunction == IRP_MJ_WRITE) ) ) {
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
//
|
|
// we need to synch with cancel
|
|
//
|
|
|
|
Context = (PRX_SHADOW_CONTEXT)RxContext->MRxContext;
|
|
if (Context->Cancelable) {
|
|
KIRQL SavedIrql;
|
|
|
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|
|
|
Irp = Context->Irp;
|
|
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) {
|
|
|
|
RxContext->MRxCancelRoutine = NULL;
|
|
Context->Irp = NULL;
|
|
|
|
} else {
|
|
|
|
LONG x;
|
|
|
|
//
|
|
// cancel thread must have a reference on the Irp so we don't free it now but
|
|
// on the actual cancel call
|
|
//
|
|
|
|
x = InterlockedDecrement( &Context->Refcnt );
|
|
if (x > 0) {
|
|
Irp = NULL;
|
|
} else {
|
|
|
|
//
|
|
// we could have already got cancelled and we need to let the others we are done
|
|
//
|
|
|
|
Context->Irp = NULL;
|
|
}
|
|
}
|
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|
}
|
|
|
|
RxContext->StoredStatus = Status;
|
|
RxContext->InformationToReturn += Information;
|
|
|
|
if (SynchronousIo) {
|
|
|
|
//
|
|
// Signal the thread that is waiting after queuing the workitem on the
|
|
// KQueue.
|
|
//
|
|
|
|
RxSignalSynchronousWaiter( RxContext );
|
|
|
|
} else {
|
|
|
|
RxLowIoCompletion( RxContext );
|
|
}
|
|
|
|
if (Irp != NULL) {
|
|
|
|
if (Irp->MdlAddress) {
|
|
PMDL mdl,nextMdl;
|
|
|
|
for (mdl = Irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
|
|
nextMdl = mdl->Next;
|
|
MmUnlockPages( mdl );
|
|
}
|
|
|
|
for (mdl = Irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
|
|
nextMdl = mdl->Next;
|
|
IoFreeMdl( mdl );
|
|
}
|
|
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
//
|
|
// We are done with this Irp, so free it.
|
|
//
|
|
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxShadowIrpCompletion (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP CalldownIrp OPTIONAL,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the calldownIrp is completed.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object in play.
|
|
|
|
CalldownIrp -
|
|
|
|
Context -
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - STATUS_MORE_PROCESSING_REQUIRED
|
|
|
|
--*/
|
|
{
|
|
PRX_CONTEXT RxContext = (PRX_CONTEXT)Context;
|
|
|
|
RxShadowCommonCompletion( RxContext,
|
|
CalldownIrp,
|
|
CalldownIrp->IoStatus.Status,
|
|
CalldownIrp->IoStatus.Information );
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxShadowCancelRoutine(
|
|
PRX_CONTEXT RxContext
|
|
)
|
|
{
|
|
|
|
KIRQL SavedIrql;
|
|
PIRP Irp;
|
|
LONG x;
|
|
PRX_SHADOW_CONTEXT Context;
|
|
|
|
Irp = NULL;
|
|
|
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|
|
|
Context = (RX_SHADOW_CONTEXT *) RxContext->MRxContext;
|
|
Irp = Context->Irp;
|
|
if (Irp != NULL) {
|
|
|
|
//
|
|
// io hasn't completed yet
|
|
//
|
|
|
|
InterlockedIncrement( &Context->Refcnt );
|
|
|
|
//
|
|
// need to clear the Irp field
|
|
//
|
|
|
|
Context->Irp = NULL;
|
|
}
|
|
|
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|
|
|
if (Irp != NULL) {
|
|
|
|
IoCancelIrp(Irp);
|
|
x = InterlockedDecrement( &Context->Refcnt );
|
|
if (x == 0) {
|
|
|
|
if (Irp->MdlAddress) {
|
|
PMDL mdl,nextMdl;
|
|
|
|
for (mdl = Irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
|
|
nextMdl = mdl->Next;
|
|
MmUnlockPages( mdl );
|
|
}
|
|
|
|
for (mdl = Irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
|
|
nextMdl = mdl->Next;
|
|
IoFreeMdl( mdl );
|
|
}
|
|
|
|
Irp->MdlAddress = NULL;
|
|
}
|
|
|
|
IoFreeIrp( Irp );
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxShadowIoHandler (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb,
|
|
IN BOOLEAN Cancelable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is common to guys who use the async context engine. It has the
|
|
responsibility for getting a context, initing, starting and finalizing it,
|
|
but the internal guts of the procesing is via the continuation routine
|
|
that is passed in.
|
|
|
|
Arguments:
|
|
|
|
RxContext - The RDBSS context.
|
|
|
|
Irp - The original irp
|
|
|
|
Fcb - The fcb io is being done on
|
|
|
|
Cancelable - Can the irp be cancelled
|
|
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PMRXSHADOW_SRV_OPEN LocalSrvOpen;
|
|
PLOWIO_CONTEXT LowIoContext = &(RxContext->LowIoContext);
|
|
PIRP TopIrp = NULL;
|
|
BOOLEAN SynchronousIo;
|
|
PIRP ShadowIrp = NULL;
|
|
|
|
LocalSrvOpen = RxGetShadowSrvOpenContext( RxContext->pRelevantSrvOpen );
|
|
|
|
//
|
|
// We are in, issue the I/O
|
|
//
|
|
|
|
SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
|
|
|
|
if (LocalSrvOpen->UnderlyingFileObject != NULL) {
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PFILE_OBJECT FileObject;
|
|
|
|
DeviceObject = LocalSrvOpen->UnderlyingDeviceObject;
|
|
FileObject = LocalSrvOpen->UnderlyingFileObject;
|
|
|
|
|
|
if (SynchronousIo) {
|
|
KeInitializeEvent( &RxContext->SyncEvent, NotificationEvent, FALSE );
|
|
}
|
|
|
|
Status = RxShadowBuildAsynchronousRequest( Irp,
|
|
DeviceObject,
|
|
FileObject,
|
|
Fcb,
|
|
RxContext,
|
|
LocalSrvOpen,
|
|
RxShadowIrpCompletion,
|
|
(PVOID) RxContext,
|
|
&ShadowIrp );
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
PRX_SHADOW_CONTEXT Context;
|
|
|
|
Context = (PRX_SHADOW_CONTEXT)RxContext->MRxContext;
|
|
|
|
ASSERT( sizeof( *Context ) <= sizeof( RxContext->MRxContext ));
|
|
|
|
//
|
|
// save new Irp if we want to resume later
|
|
//
|
|
|
|
Context->Irp = ShadowIrp;
|
|
Context->Cancelable = Cancelable;
|
|
Context->Refcnt = 1;
|
|
|
|
try {
|
|
|
|
//
|
|
// Save the TopLevel Irp.
|
|
//
|
|
|
|
TopIrp = IoGetTopLevelIrp();
|
|
|
|
//
|
|
// Tell the underlying guy he's all clear.
|
|
//
|
|
|
|
IoSetTopLevelIrp( NULL );
|
|
|
|
Status = IoCallDriver( DeviceObject, ShadowIrp );
|
|
|
|
} finally {
|
|
|
|
//
|
|
// Restore my context for unwind.
|
|
//
|
|
|
|
IoSetTopLevelIrp( TopIrp );
|
|
|
|
}
|
|
|
|
if (Cancelable == TRUE) {
|
|
|
|
KIRQL SavedIrql;
|
|
|
|
TopIrp = NULL;
|
|
|
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|
if ((Context->Irp != NULL) &&
|
|
!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) {
|
|
|
|
//
|
|
// io is still pending and hasn't been cancelled
|
|
//
|
|
|
|
RxContext->MRxCancelRoutine = RxShadowCancelRoutine;
|
|
|
|
} else if (Context->Irp != NULL) {
|
|
|
|
//
|
|
// io is already cancelled
|
|
//
|
|
|
|
TopIrp = Context->Irp;
|
|
|
|
//
|
|
// we need to clear the Irp field
|
|
//
|
|
Context->Irp = NULL;
|
|
|
|
//
|
|
// we need to take an extra reference
|
|
//
|
|
|
|
InterlockedIncrement( &Context->Refcnt );
|
|
}
|
|
|
|
|
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|
|
|
if (TopIrp != NULL) {
|
|
|
|
LONG x;
|
|
|
|
IoCancelIrp( TopIrp );
|
|
x = InterlockedDecrement( &Context->Refcnt );
|
|
if (x == 0) {
|
|
if (TopIrp->MdlAddress) {
|
|
TopIrp->MdlAddress = NULL;
|
|
}
|
|
IoFreeIrp( TopIrp );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SynchronousIo) {
|
|
RxWaitSync( RxContext );
|
|
Status = RxContext->StoredStatus;
|
|
} else {
|
|
Status = STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
Status = STATUS_VOLUME_DISMOUNTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxShadowFastLowIo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles network read requests.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
PMRXSHADOW_SRV_OPEN MrxShadowSrvOpen;
|
|
PLOWIO_CONTEXT LowIoContext = &(RxContext->LowIoContext);
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
LARGE_INTEGER Offset;
|
|
BOOLEAN Wait, PagingIo;
|
|
IO_STATUS_BLOCK Ios;
|
|
PVOID Buffer;
|
|
PIRP TopIrp;
|
|
|
|
//
|
|
// we only support read and write
|
|
//
|
|
|
|
if ((LowIoContext->Operation != LOWIO_OP_READ) && (LowIoContext->Operation != LOWIO_OP_WRITE)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// don't deal with name pipes
|
|
//
|
|
|
|
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION )) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// check for locks and take default path
|
|
//
|
|
|
|
if (IrpSp->FileObject && IrpSp->FileObject->LockOperation) {
|
|
return Status;
|
|
}
|
|
|
|
PagingIo = BooleanFlagOn( LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO );
|
|
|
|
MrxShadowSrvOpen = RxGetShadowSrvOpenContext( RxContext->pRelevantSrvOpen );
|
|
|
|
//
|
|
// The only time we can get PagingIo write on a loopback file is if the
|
|
// file has been memory mapped.
|
|
//
|
|
|
|
//
|
|
// We don't handle PagingIo read and no-buffering handles through fast
|
|
// path. PagingIo write is tried through the fast path and if it does
|
|
// not succeed then we return STATUS_MORE_PROCESSING_REQUIRED.
|
|
//
|
|
|
|
if ((PagingIo && LowIoContext->Operation == LOWIO_OP_READ) ||
|
|
(MrxShadowSrvOpen == NULL) ||
|
|
(MrxShadowSrvOpen->UnderlyingFileObject == NULL ) ||
|
|
(IrpSp->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)) {
|
|
|
|
return Status;
|
|
}
|
|
|
|
Offset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
|
|
//
|
|
// get user buffer
|
|
//
|
|
|
|
if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP )) {
|
|
Buffer = Irp->UserBuffer;
|
|
} else {
|
|
ASSERT( LowIoContext->ParamsFor.ReadWrite.Buffer != NULL );
|
|
Buffer = RxLowIoGetBufferAddress( RxContext );
|
|
}
|
|
|
|
//
|
|
// Check shadow state and io params.
|
|
//
|
|
|
|
if (RxShadowVerifyIoParameters( MrxShadowSrvOpen->UnderlyingDeviceObject,
|
|
IrpSp->FileObject,
|
|
Buffer,
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
|
&Offset) != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
Wait = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
|
|
|
|
if (PagingIo) {
|
|
ASSERT(LowIoContext->Operation == LOWIO_OP_WRITE);
|
|
Wait = FALSE;
|
|
}
|
|
|
|
//
|
|
// Save the TopLevel Irp.
|
|
//
|
|
|
|
TopIrp = IoGetTopLevelIrp();
|
|
|
|
//
|
|
// Tell the underlying guy he's all clear.
|
|
//
|
|
|
|
IoSetTopLevelIrp( NULL );
|
|
|
|
try {
|
|
if ((LowIoContext->Operation == LOWIO_OP_READ) &&
|
|
(MrxShadowSrvOpen->FastIoRead != NULL) &&
|
|
MrxShadowSrvOpen->FastIoRead(MrxShadowSrvOpen->UnderlyingFileObject,
|
|
&Offset,
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
|
Wait,
|
|
RxShadowLockKey( LowIoContext, MrxShadowSrvOpen ),
|
|
Buffer,
|
|
&Ios,
|
|
MrxShadowSrvOpen->UnderlyingDeviceObject )) {
|
|
|
|
//
|
|
// the fast io path worked
|
|
//
|
|
|
|
Irp->IoStatus = Ios;
|
|
RxContext->StoredStatus = Ios.Status;
|
|
RxContext->InformationToReturn += Ios.Information;
|
|
Status = Ios.Status;
|
|
|
|
} else if ((LowIoContext->Operation == LOWIO_OP_WRITE) &&
|
|
(MrxShadowSrvOpen->FastIoWrite != NULL) &&
|
|
MrxShadowSrvOpen->FastIoWrite(MrxShadowSrvOpen->UnderlyingFileObject,
|
|
&Offset,
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
|
Wait,
|
|
RxShadowLockKey(LowIoContext, MrxShadowSrvOpen),
|
|
Buffer,
|
|
&Ios,
|
|
MrxShadowSrvOpen->UnderlyingDeviceObject )) {
|
|
|
|
//
|
|
// The fast io path worked.
|
|
//
|
|
|
|
Irp->IoStatus = Ios;
|
|
RxContext->StoredStatus = Ios.Status;
|
|
RxContext->InformationToReturn += Ios.Information;
|
|
Status = Ios.Status;
|
|
}
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
//
|
|
// TODO: Should we fall through to the slow path on an exception?
|
|
//
|
|
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS && PagingIo) {
|
|
ASSERT(LowIoContext->Operation == LOWIO_OP_WRITE);
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
//
|
|
// Restore my context for unwind.
|
|
//
|
|
IoSetTopLevelIrp( TopIrp );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxShadowLowIo (
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PIRP Irp,
|
|
IN PFCB Fcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles network read requests.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
PMRXSHADOW_SRV_OPEN MrxShadowSrvOpen;
|
|
PLOWIO_CONTEXT LowIoContext = &(RxContext->LowIoContext);
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
LARGE_INTEGER Offset;
|
|
PVOID Buffer;
|
|
|
|
//
|
|
// we only support read and write and lock
|
|
//
|
|
|
|
if ((LowIoContext->Operation != LOWIO_OP_READ) &&
|
|
(LowIoContext->Operation != LOWIO_OP_WRITE) &&
|
|
(RxContext->MajorFunction != IRP_MJ_LOCK_CONTROL)) {
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// don't deal with name pipes
|
|
//
|
|
|
|
if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION )) {
|
|
return Status;
|
|
}
|
|
|
|
MrxShadowSrvOpen = RxGetShadowSrvOpenContext( RxContext->pRelevantSrvOpen );
|
|
|
|
if ((MrxShadowSrvOpen == NULL) ||
|
|
(MrxShadowSrvOpen->UnderlyingFileObject == NULL)) {
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// if min-rdr wants to handle shadow io then pass call down
|
|
//
|
|
|
|
if (MrxShadowSrvOpen->DispatchRoutine) {
|
|
return MrxShadowSrvOpen->DispatchRoutine( RxContext );
|
|
}
|
|
|
|
if ((LowIoContext->Operation == LOWIO_OP_READ) ||
|
|
(LowIoContext->Operation == LOWIO_OP_WRITE)) {
|
|
|
|
Offset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
|
|
|
//
|
|
// if we have no mdl then use the user buffer directly
|
|
//
|
|
|
|
if (!LowIoContext->ParamsFor.ReadWrite.Buffer) {
|
|
Buffer = Irp->UserBuffer;
|
|
} else {
|
|
Buffer = RxLowIoGetBufferAddress( RxContext );
|
|
}
|
|
|
|
//
|
|
// check shadow state and io params
|
|
//
|
|
|
|
Status = RxShadowVerifyIoParameters( MrxShadowSrvOpen->UnderlyingDeviceObject,
|
|
IrpSp->FileObject,
|
|
Buffer,
|
|
LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
|
&Offset );
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
//
|
|
// don't return status more processing required here in order to enforce proper
|
|
// alignment. Note, if the user has the file locked the server can't help it anyway.
|
|
//
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = RxShadowIoHandler( RxContext, Irp, Fcb, RxContext->MajorFunction == IRP_MJ_LOCK_CONTROL ? TRUE : FALSE );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|