windows-nt/Source/XPSP1/NT/base/fs/mup/forward.c
2020-09-26 16:20:57 +08:00

708 lines
17 KiB
C
Raw 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
);
VOID
DeferredForwardedIoCompletionRoutine(
PVOID Context);
NTSTATUS
CommonForwardedIoCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, BuildAndSubmitIrp )
#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;
PVOID fscontext2;
PLIST_ENTRY listEntry;
PCCB ccb;
PMASTER_FORWARDED_IO_CONTEXT masterContext;
BOOLEAN ownLock = FALSE;
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,
&fscontext2
);
if ( fcb == NULL || 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();
if (masterContext == NULL) {
//
// We ran out of resources. Clean up and return the error.
//
DebugTrace(0, Dbg, "Couldn't allc masterContect\n", 0);
FsRtlExitFileSystem();
MupCompleteRequest( Irp, STATUS_INSUFFICIENT_RESOURCES );
status = STATUS_INSUFFICIENT_RESOURCES;
DebugTrace(-1, Dbg, "MupForwardRequest -> %08lx\n", status );
return status;
}
DebugTrace( 0, Dbg, "Allocated MasterContext 0x%08lx\n", masterContext );
IoMarkIrpPending(Irp);
//
// At this point, we're committed to returning STATUS_PENDING
//
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;
masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
//
// Copy the referenced pointer to the FCB.
//
masterContext->Fcb = fcb;
try {
//
// Submit the forwarded IRPs. Note that we can not hold the lock
// across calls to BuildAndSubmitIrp as it calls IoCallDriver().
//
ACQUIRE_LOCK( &MupCcbListLock );
ownLock = TRUE;
listEntry = fcb->CcbList.Flink;
while ( listEntry != &fcb->CcbList ) {
RELEASE_LOCK( &MupCcbListLock );
ownLock = FALSE;
ccb = CONTAINING_RECORD( listEntry, CCB, ListEntry );
MupAcquireGlobalLock();
MupReferenceBlock( ccb );
MupReleaseGlobalLock();
BuildAndSubmitIrp( Irp, ccb, masterContext );
ACQUIRE_LOCK( &MupCcbListLock );
ownLock = TRUE;
listEntry = listEntry->Flink;
}
RELEASE_LOCK( &MupCcbListLock );
ownLock = FALSE;
} except ( EXCEPTION_EXECUTE_HANDLER ) {
masterContext->ErrorStatus = GetExceptionCode();
}
//
// If BuildAndSubmitIrp threw an exception, the lock might still be
// held. Drop it if so.
//
if (ownLock == TRUE) {
RELEASE_LOCK( &MupCcbListLock );
}
//
// Release our reference to the master IO context block.
//
MupDereferenceMasterIoContext( masterContext, NULL );
//
// Return to the caller.
//
FsRtlExitFileSystem();
DebugTrace(-1, Dbg, "MupForwardIrp -> %08lx\n", status);
return STATUS_PENDING;
}
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 = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
ULONG bufferLength;
KPROCESSOR_MODE requestorMode;
PMDL mdl = NULL;
PAGED_CODE();
DebugTrace(+1, Dbg, "BuildAndSubmitIrp\n", 0);
try {
// make this NonPagedPool, since we could free this up in the
// io completion routine.
forwardedIoContext = ExAllocatePoolWithTag(
NonPagedPool,
sizeof( FORWARDED_IO_CONTEXT ),
' puM');
if (forwardedIoContext == NULL) {
try_return(status = STATUS_INSUFFICIENT_RESOURCES);
}
forwardedIoContext->pIrp = NULL;
forwardedIoContext->DeviceObject = NULL;
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 = 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 ) {
//
// 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');
if (irp->AssociatedIrp.SystemBuffer == NULL) {
try_return(status = STATUS_INSUFFICIENT_RESOURCES);
}
RtlMoveMemory(
irp->AssociatedIrp.SystemBuffer,
OriginalIrp->UserBuffer,
bufferLength);
//
// 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.
// Note that no MDL is allocated, nor is any memory probed or
// locked if the length of the request was zero.
//
if ( bufferLength != 0 ) {
//
// 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) {
try_return(status = STATUS_INSUFFICIENT_RESOURCES);
}
MmProbeAndLockPages( mdl, requestorMode, IoReadAccess );
}
} 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 );
//
// At this point it is up to the completion routine to free things
//
irp = NULL;
forwardedIoContext = NULL;
mdl = NULL;
try_exit:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
//
// Clean up everything if we are returning an error
//
if (!NT_SUCCESS(status)) {
if ( forwardedIoContext != NULL )
ExFreePool( forwardedIoContext );
if ( irp != NULL ) {
if (irp->AssociatedIrp.SystemBuffer != NULL)
ExFreePool(irp->AssociatedIrp.SystemBuffer);
IoFreeIrp( irp );
}
if ( mdl != NULL )
IoFreeMdl( mdl );
}
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;
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 );
//
// Give this to a worker thread if we are at too high an Irq level
//
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
ioContext->DeviceObject = DeviceObject;
ioContext->pIrp = Irp;
ExInitializeWorkItem(
&ioContext->WorkQueueItem,
DeferredForwardedIoCompletionRoutine,
Context);
ExQueueWorkItem(&ioContext->WorkQueueItem, CriticalWorkQueue);
} else {
CommonForwardedIoCompletionRoutine(
DeviceObject,
Irp,
Context);
}
//
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
// will stop working on the IRP.
//
DebugTrace( -1, Dbg, "ForwardedIoCompletionRoutine exit\n", 0 );
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
DeferredForwardedIoCompletionRoutine(
PVOID Context)
{
PFORWARDED_IO_CONTEXT ioContext = Context;
CommonForwardedIoCompletionRoutine(
ioContext->DeviceObject,
ioContext->pIrp,
Context);
}
NTSTATUS
CommonForwardedIoCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PFORWARDED_IO_CONTEXT ioContext = Context;
NTSTATUS status = Irp->IoStatus.Status;
DeviceObject;
//
// 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
//
ExFreePool( ioContext );
return STATUS_MORE_PROCESSING_REQUIRED;
}