NT4/private/ntos/mup/forward.c
2020-09-30 17:12:29 +02:00

687 lines
17 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
fscontrl.c
Abstract:
This module implements the forwarding of all broadcast requests
to UNC providers.
Author:
Manny Weiser (mannyw) 6-Jan-1992
Revision History:
--*/
#include "mup.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_FORWARD)
//
// local procedure prototypes
//
NTSTATUS
BuildAndSubmitIrp (
IN PIRP OriginalIrp,
IN PCCB Ccb,
IN PMASTER_FORWARDED_IO_CONTEXT MasterContext
);
NTSTATUS
ForwardedIoCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, BuildAndSubmitIrp )
#pragma alloc_text( PAGE, ForwardedIoCompletionRoutine )
#pragma alloc_text( PAGE, MupForwardIoRequest )
#endif
NTSTATUS
MupForwardIoRequest (
IN PMUP_DEVICE_OBJECT MupDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine forwards an I/O Request Packet to all redirectors for
a broadcast request.
Arguments:
MupDeviceObject - Supplies the device object to use.
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The status for the IRP
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
PFCB fcb;
ULONG fscontext2;
PLIST_ENTRY listEntry;
PCCB ccb;
PMASTER_FORWARDED_IO_CONTEXT masterContext;
MupDeviceObject;
PAGED_CODE();
DebugTrace(+1, Dbg, "MupForwardIrp\n", 0);
if (MupEnableDfs &&
MupDeviceObject->DeviceObject.DeviceType == FILE_DEVICE_DFS) {
status = DfsVolumePassThrough((PDEVICE_OBJECT)MupDeviceObject, Irp);
return( status );
}
irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Find the FCB for this file object
//
FsRtlEnterFileSystem();
MupDecodeFileObject(
irpSp->FileObject,
(PVOID *)&fcb,
(PVOID *)&fscontext2
);
try {
if ( BlockType( fcb ) != BlockTypeFcb ) {
//
// This is not an FCB.
//
DebugTrace(0, Dbg, "The fail is closing\n", 0);
FsRtlExitFileSystem();
MupCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST );
status = STATUS_INVALID_DEVICE_REQUEST;
DebugTrace(-1, Dbg, "MupForwardRequest -> %08lx\n", status );
return status;
}
//
// Allocate a context structure
//
masterContext = MupAllocateMasterIoContext();
DebugTrace( 0, Dbg, "Allocated MasterContext 0x%08lx\n", masterContext );
masterContext->OriginalIrp = Irp;
//
// set status for MupDereferenceMasterIoContext. If this is still
// an error when the context is freed then masterContext->ErrorStatus
// will be used to complete the request.
//
masterContext->SuccessStatus = STATUS_UNSUCCESSFUL;
//
// Copy the referenced pointer to the FCB.
//
masterContext->Fcb = fcb;
//
// Submit the forwarded IRPs. Note that we can not hold the lock
// across calls to BuildAndSubmitIrp as it calls IoCallDriver().
//
ACQUIRE_LOCK( &MupCcbListLock );
listEntry = fcb->CcbList.Flink;
while ( listEntry != &fcb->CcbList ) {
RELEASE_LOCK( &MupCcbListLock );
ccb = CONTAINING_RECORD( listEntry, CCB, ListEntry );
MupAcquireGlobalLock();
MupReferenceBlock( ccb );
MupReleaseGlobalLock();
BuildAndSubmitIrp( Irp, ccb, masterContext );
ACQUIRE_LOCK( &MupCcbListLock );
listEntry = listEntry->Flink;
}
RELEASE_LOCK( &MupCcbListLock );
//
// Release our reference to the master IO context block.
//
status = MupDereferenceMasterIoContext( masterContext, NULL );
} except ( EXCEPTION_EXECUTE_HANDLER ) {
status = GetExceptionCode();
}
//
// Return to the caller.
//
FsRtlExitFileSystem();
DebugTrace(-1, Dbg, "MupForwardIrp -> %08lx\n", status);
return status;
}
NTSTATUS
BuildAndSubmitIrp (
IN PIRP OriginalIrp,
IN PCCB Ccb,
IN PMASTER_FORWARDED_IO_CONTEXT MasterContext
)
/*++
Routine Description:
This routine takes the original IRP and forwards it to the
the UNC provider described by the CCB.
Arguments:
OriginalIrp - Supplies the Irp being processed
Ccb - A pointer the the ccb.
MasterContext - A pointer to the master context block for this
forwarded request.
Return Value:
NTSTATUS - The status for the Irp
--*/
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp;
PFORWARDED_IO_CONTEXT forwardedIoContext = NULL;
NTSTATUS status;
PDEVICE_OBJECT deviceObject;
ULONG bufferLength;
KPROCESSOR_MODE requestorMode;
PMDL mdl;
PAGED_CODE();
DebugTrace(+1, Dbg, "BuildAndSubmitIrp\n", 0);
try {
forwardedIoContext = ALLOCATE_PAGED_POOL(
sizeof( FORWARDED_IO_CONTEXT ),
BlockTypeIoContext
);
DebugTrace( 0, Dbg, "Allocated work context 0x%08lx\n", forwardedIoContext );
//
// Get the address of the target device object. Note that this was
// already done for the no intermediate buffering case, but is done
// here again to speed up the turbo write path.
//
deviceObject = IoGetRelatedDeviceObject( Ccb->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.
//
irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
if (irp == NULL) {
//
// An IRP could not be allocated. Return an appropriate
// error status code.
//
try_return( STATUS_INSUFFICIENT_RESOURCES );
}
irp->Tail.Overlay.OriginalFileObject = Ccb->FileObject;
irp->Tail.Overlay.Thread = OriginalIrp->Tail.Overlay.Thread;
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 );
//
// Copy the parameters from the original request.
//
RtlMoveMemory(
irpSp,
IoGetCurrentIrpStackLocation( OriginalIrp ),
sizeof( *irpSp )
);
bufferLength = irpSp->Parameters.Write.Length;
irpSp->FileObject = Ccb->FileObject;
//
// Even though this is probably meaningless to a remote mailslot
// write, pass it though obediently.
//
if (Ccb->FileObject->Flags & FO_WRITE_THROUGH) {
irpSp->Flags = SL_WRITE_THROUGH;
}
requestorMode = OriginalIrp->RequestorMode;
//
// Now determine whether this device expects to have data buffered
// to it or whether it performs direct I/O. This is based on the
// DO_BUFFERED_IO flag in the device object. If the flag is set,
// then a system buffer is allocated and the caller's data is copied
// into it. Otherwise, a Memory Descriptor List (MDL) is allocated
// and the caller's buffer is locked down using it.
//
if (deviceObject->Flags & DO_BUFFERED_IO) {
//
// The device does not support direct I/O. Allocate a system
// buffer, and copy the caller's data into it. This is done
// using an exception handler that will perform cleanup if the
// operation fails. Note that this is only done if the operation
// has a non-zero length.
//
irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
if ( bufferLength != 0 ) {
try {
//
// If the request was made from a mode other than kernel,
// presumably user, probe the entire buffer to determine
// whether or not the caller has write access to it.
//
if (requestorMode != KernelMode) {
ProbeForRead(
OriginalIrp->UserBuffer,
bufferLength,
sizeof( UCHAR )
);
}
//
// Allocate the intermediary system buffer from paged
// pool and charge quota for it.
//
irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithQuotaTag(
PagedPoolCacheAligned,
bufferLength,
' puM'
);
RtlMoveMemory(
irp->AssociatedIrp.SystemBuffer,
OriginalIrp->UserBuffer,
bufferLength
);
} except(EXCEPTION_EXECUTE_HANDLER) {
if ( irp->AssociatedIrp.SystemBuffer != NULL ) {
ExFreePool( irp->AssociatedIrp.SystemBuffer );
}
try_return( GetExceptionCode() );
}
//
// Set the IRP_BUFFERED_IO flag in the IRP so that I/O
// completion will know that this is not a direct I/O
// operation. Also set the IRP_DEALLOCATE_BUFFER flag
// so it will deallocate the buffer.
//
irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
} else {
//
// This is a zero-length write. Simply indicate that this is
// buffered I/O, and pass along the request. The buffer will
// not be set to deallocate so the completion path does not
// have to special-case the length.
//
irp->Flags = IRP_BUFFERED_IO;
}
} else if (deviceObject->Flags & DO_DIRECT_IO) {
//
// This is a direct I/O operation. Allocate an MDL and invoke the
// memory management routine to lock the buffer into memory. This
// is done using an exception handler that will perform cleanup if
// the operation fails. Note that no MDL is allocated, nor is any
// memory probed or locked if the length of the request was zero.
//
mdl = (PMDL) NULL;
if ( bufferLength != 0 ) {
try {
//
// Allocate an MDL, charging quota for it, and hang it
// off of the IRP. Probe and lock the pages associated
// with the caller's buffer for read access and fill in
// the MDL with the PFNs of those pages.
//
mdl = IoAllocateMdl(
OriginalIrp->UserBuffer,
bufferLength,
FALSE,
TRUE,
irp
);
if (mdl == NULL) {
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
}
MmProbeAndLockPages( mdl, requestorMode, IoReadAccess );
} except(EXCEPTION_EXECUTE_HANDLER) {
if ( mdl != NULL ) {
IoFreeMdl( mdl );
}
try_return (GetExceptionCode());
}
}
} else {
//
// Pass the address of the caller's buffer to the device driver.
// It is now up to the driver to do everything.
//
irp->UserBuffer = OriginalIrp->UserBuffer;
}
//
// If this write operation is to be performed without any caching,
// set the appropriate flag in the IRP so no caching is performed.
//
if (Ccb->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
irp->Flags |= IRP_NOCACHE | IRP_WRITE_OPERATION;
} else {
irp->Flags |= IRP_WRITE_OPERATION;
}
//
// Setup the context block
//
forwardedIoContext->Ccb = Ccb;
forwardedIoContext->MasterContext = MasterContext;
MupAcquireGlobalLock();
MupReferenceBlock( MasterContext );
MupReleaseGlobalLock();
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
irp,
(PIO_COMPLETION_ROUTINE)ForwardedIoCompletionRoutine,
forwardedIoContext,
TRUE,
TRUE,
TRUE
);
//
// Pass the request to the provider.
//
IoCallDriver( Ccb->DeviceObject, irp );
status = STATUS_SUCCESS;
#if 0
irp = IoAllocateIrp( (CCHAR)(Ccb->DeviceObject->StackSize + 1), TRUE );
DebugTrace( 0, Dbg, "Allocated IRP 0x%08lx\n", irp );
if ( irp == NULL ) {
try_return( STATUS_INSUFFICIENT_RESOURCES );
}
IoSetNextIrpStackLocation( irp );
irp->Tail.Overlay.OriginalFileObject = Ccb->FileObject;
irp->Tail.Overlay.Thread = OriginalIrp->Tail.Overlay.Thread;
irp->RequestorMode = KernelMode;
irp->AssociatedIrp.SystemBuffer = OriginalIrp->AssociatedIrp.SystemBuffer;
irp->UserBuffer = OriginalIrp->UserBuffer;
//
// Get a pointer to the next stack location. This one is used to
// hold the parameters for the request. Fill in the
// service-dependent parameters for the request.
//
irpSp = IoGetNextIrpStackLocation( irp );
RtlMoveMemory(
irpSp,
IoGetCurrentIrpStackLocation( OriginalIrp ),
sizeof( *irpSp )
);
//
// Change the stack location that need to be changed.
//
irpSp->DeviceObject = Ccb->DeviceObject;
irpSp->FileObject = Ccb->FileObject;
//
// Setup the context block
//
forwardedIoContext->Ccb = Ccb;
forwardedIoContext->MasterContext = MasterContext;
MupAcquireGlobalLock();
MupReferenceBlock( MasterContext );
MupReleaseGlobalLock();
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
irp,
(PIO_COMPLETION_ROUTINE)ForwardedIoCompletionRoutine,
forwardedIoContext,
TRUE,
TRUE,
TRUE
);
//
// Return a pointer to the IRP.
//
IoCallDriver( Ccb->DeviceObject, irp );
status = STATUS_SUCCESS;
#endif
try_exit:
NOTHING;
} finally {
if ( AbnormalTermination() ) {
if ( forwardedIoContext != NULL ) {
FREE_POOL( forwardedIoContext );
}
if ( irp != NULL ) {
IoFreeIrp( irp );
}
}
}
DebugTrace(-1, Dbg, "BuildAndSubmitIrp -> 0x%08lx\n", status);
return status;
}
NTSTATUS
ForwardedIoCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routines cleans up after a forwarded IRP has completed.
Arguments:
DeviceObject - A pointer to the MUP device object.
IRP - A pointer to the IRP being processed.
Context - A pointer to a block containing the context of a forward IRP.
Return Value:
None.
--*/
{
PFORWARDED_IO_CONTEXT ioContext = Context;
NTSTATUS status = Irp->IoStatus.Status;
DeviceObject;
PAGED_CODE();
DebugTrace( +1, Dbg, "ForwardedIoCompletionRoutine\n", 0 );
DebugTrace( 0, Dbg, "Irp = 0x%08lx\n", Irp );
DebugTrace( 0, Dbg, "Context = 0x%08lx\n", Context );
DebugTrace( 0, Dbg, "status = 0x%08lx\n", status );
//
// Free the Irp, and any additional structures we may have allocated.
//
if ( Irp->MdlAddress ) {
MmUnlockPages( Irp->MdlAddress );
IoFreeMdl( Irp->MdlAddress );
}
if ( Irp->Flags & IRP_DEALLOCATE_BUFFER ) {
ExFreePool( Irp->AssociatedIrp.SystemBuffer );
}
IoFreeIrp( Irp );
//
// Release the our referenced blocks.
//
MupDereferenceCcb( ioContext->Ccb );
MupDereferenceMasterIoContext( ioContext->MasterContext, &status );
//
// Free the slave forwarded IO context block
//
FREE_POOL( ioContext );
//
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
// will stop working on the IRP.
//
DebugTrace( -1, Dbg, "ForwardedIoCompletionRoutine -> 0x%08lx\n", STATUS_MORE_PROCESSING_REQUIRED );
return STATUS_MORE_PROCESSING_REQUIRED;
}