mirror of https://github.com/lianthony/NT4.0
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.
523 lines
14 KiB
523 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fspdisp.c
|
|
|
|
Abstract:
|
|
|
|
This file provides the main FSP dispatch routine for the NT redirector.
|
|
|
|
It mostly provides a switch statement that calls the appropriate RdrFsp
|
|
routine and returns that status to the caller.
|
|
|
|
Notes:
|
|
There are two classes of redirector FSP worker threads. The first
|
|
are what are called FSP worker threads. These threads are responsible
|
|
for processing NT Irp's passed onto the redirector's main work thread.
|
|
|
|
In addition to this pool of threads, there is a small pool of "generic"
|
|
worker threads whose sole purpose is to process generic request
|
|
operations. These are used for processing such operations as close
|
|
behind, etc.
|
|
|
|
|
|
Author:
|
|
|
|
Larry Osterman (LarryO) 31-May-1990
|
|
|
|
Revision History:
|
|
|
|
31-May-1990 LarryO
|
|
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
VOID
|
|
RdrWorkerDispatch (
|
|
PVOID Context
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RdrFsdPostToFsp)
|
|
#pragma alloc_text(PAGE, RdrFspDispatch)
|
|
#pragma alloc_text(PAGE, RdrWorkerDispatch)
|
|
#pragma alloc_text(INIT, RdrpInitializeFsp)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
RdrFsdPostToFsp(
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine passes the IRP specified onto the FSP work queue, and kicks
|
|
an FSP thread. This routine accepts an I/O Request Packet (IRP) and a
|
|
work queue and passes the request to the appropriate request queue.
|
|
|
|
If the IRP cannot be queued because of an inability to
|
|
allocate an IRP context block, this routine completes the request
|
|
with an error status. If the IRP has already been cancelled, this
|
|
routine does nothing, allowing the cancel routine to complete the
|
|
request.
|
|
|
|
Arguments:
|
|
|
|
RdrDeviceObject - Pointer to the device object for this driver.
|
|
|
|
Irp - Pointer to the request packet representing the I/O request.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP_CONTEXT IrpContext;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Mark this I/O request as being pending. Even if we don't actually
|
|
// queue the IRP to the FSP, we still return STATUS_PENDING on the
|
|
// call to the I/O dispatch routine.
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
//
|
|
// Allocate an IRP context block. If this fails, complete the IRP
|
|
// with an error.
|
|
//
|
|
|
|
IrpContext = RdrAllocateIrpContext();
|
|
if ( IrpContext == NULL ) {
|
|
RdrCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Initialize the IRP context block.
|
|
//
|
|
|
|
IrpContext->Irp = Irp;
|
|
IrpContext->DeviceObject = DeviceObject;
|
|
IrpContext->WorkHeader.WorkerFunction = RdrFspDispatch;
|
|
IrpContext->WorkHeader.WorkItem.Irp = Irp;
|
|
|
|
//
|
|
// Store a back pointer to the IRP context in the IRP so we can free it
|
|
// if the IRP gets canceled. Leave 3 low order bits untouched for
|
|
// possible flags.
|
|
//
|
|
|
|
Irp->IoStatus.Information = (Irp->IoStatus.Information & 7) | (ULONG)IrpContext;
|
|
|
|
//
|
|
// Queue the request to a worker thread. If this fails, it is
|
|
// because the IRP has already been cancelled (and completed).
|
|
// In this case, simply free the IRP context block.
|
|
//
|
|
|
|
Status = RdrQueueToWorkerThread(&RdrDeviceObject->IrpWorkQueue,
|
|
&IrpContext->WorkHeader.WorkItem,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RdrFreeIrpContext(IrpContext);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
RdrFspDispatch (
|
|
IN PWORK_HEADER WorkHeader
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RdrFspDispatch is the main dispatch routine for the NT redirector's
|
|
FSP. It will process worker requests as queued.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - A pointer to the redirector DeviceObject
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP_CONTEXT IrpContext = CONTAINING_RECORD(WorkHeader, IRP_CONTEXT, WorkHeader);
|
|
PIRP Irp = IrpContext->Irp;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS Status;
|
|
PFS_DEVICE_OBJECT DeviceObject = IrpContext->DeviceObject;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// We no longer need the IRP context, free it as soon as possible.
|
|
//
|
|
|
|
RdrFreeIrpContext(IrpContext);
|
|
|
|
try {
|
|
dprintf(DPRT_FSPDISP, ("RdrFspDispatch: Got request, Irp = %08lx, "
|
|
"Function = %d\nAux buffer = %08lx\n", Irp, IrpSp->MajorFunction,
|
|
Irp->Tail.Overlay.AuxiliaryBuffer));
|
|
|
|
switch (IrpSp->MajorFunction) {
|
|
|
|
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
|
Status = RdrFspFsControlFile(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
Status = RdrFspDeviceIoControlFile(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_READ:
|
|
Status = RdrFspRead (DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_WRITE:
|
|
Status = RdrFspWrite (DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_DIRECTORY_CONTROL:
|
|
Status = RdrFspDirectoryControl (DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_QUERY_INFORMATION:
|
|
Status = RdrFspQueryInformationFile (DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_SET_INFORMATION:
|
|
Status = RdrFspSetInformationFile (DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
|
Status = RdrFspQueryVolumeInformationFile (DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_LOCK_CONTROL:
|
|
Status = RdrFspLockOperation(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_FLUSH_BUFFERS:
|
|
Status = RdrFspFlushBuffersFile(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_QUERY_EA:
|
|
Status = RdrFspQueryEa(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_SET_EA:
|
|
Status = RdrFspSetEa(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_QUERY_SECURITY:
|
|
Status = RdrFspQuerySecurity(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_SET_SECURITY:
|
|
Status = RdrFspSetSecurity(DeviceObject, Irp);
|
|
break;
|
|
|
|
|
|
#if RDRDBG
|
|
case IRP_MJ_CLEANUP:
|
|
InternalError(("Cleanup IRP request passed to FSP\n"));
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
RdrCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case IRP_MJ_CREATE:
|
|
InternalError(("NtCreateFile request passed to FSP\n"));
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
RdrCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
InternalError(("NtClose request passed to FSP\n"));
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
RdrCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
#endif
|
|
default:
|
|
InternalError(("Unexpected function %x passed to FSP\n", IrpSp->MajorFunction));
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
RdrCompleteRequest(Irp, Status);
|
|
break;
|
|
}
|
|
} except (RdrExceptionFilter(GetExceptionInformation(), &Status)) {
|
|
|
|
Status = RdrProcessException( Irp, Status );
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
RdrWorkerDispatch (
|
|
PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the generic worker dispatching routine. It pulls requests
|
|
from the redirector's "generic" worker function queue and processes them.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWORK_QUEUE WorkQueue = Context;
|
|
BOOLEAN FirstCall = TRUE;
|
|
|
|
PAGED_CODE();
|
|
|
|
dprintf(DPRT_FSPDISP, ("RdrWorkerDispatch: New Thread created\n"));
|
|
|
|
while (TRUE) {
|
|
//
|
|
// Simply pull a request from the queue and call it's associated
|
|
// function.
|
|
//
|
|
PWORK_ITEM Entry;
|
|
PWORK_HEADER WorkHeader;
|
|
|
|
Entry = RdrDequeueInWorkerThread(WorkQueue, &FirstCall);
|
|
WorkHeader = CONTAINING_RECORD( Entry, WORK_HEADER, WorkItem );
|
|
|
|
dprintf(DPRT_FSPDISP, ("Process work item %08lx\n", WorkHeader));
|
|
#if DBG
|
|
|
|
try {
|
|
|
|
PVOID WorkerRoutine;
|
|
|
|
WorkerRoutine = WorkHeader->WorkerFunction;
|
|
(WorkHeader->WorkerFunction)(WorkHeader);
|
|
if (KeGetCurrentIrql() != 0) {
|
|
KdPrint(("RDRWORKER: worker exit raised IRQL, worker routine %lx\n",
|
|
WorkerRoutine));
|
|
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
} except( KdPrint(("RDRWORKER: routine faulted - exinfo == %lX\n",
|
|
GetExceptionInformation())),
|
|
DbgBreakPoint(),
|
|
EXCEPTION_EXECUTE_HANDLER ) {
|
|
}
|
|
|
|
#else
|
|
|
|
(WorkHeader->WorkerFunction)(WorkHeader);
|
|
|
|
#endif
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrNotSupported (
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This catch all routine returns STATUS_NOT_SUPPORTED for the requested operation
|
|
--*/
|
|
{
|
|
RdrCompleteRequest(Irp, STATUS_NOT_SUPPORTED );
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RdrpInitializeFsp (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the FSP specific components and dispatch
|
|
routines.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
USHORT i;
|
|
|
|
//
|
|
// Allocate a spin lock to cover the redirector time counter.
|
|
//
|
|
|
|
KeInitializeSpinLock( &RdrTimeInterLock );
|
|
|
|
//
|
|
// Initialize the driver object with this driver's entry points.
|
|
//
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_CREATE] =
|
|
(PDRIVER_DISPATCH )RdrFsdCreate;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_CLOSE] =
|
|
(PDRIVER_DISPATCH )RdrFsdClose;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_READ] =
|
|
(PDRIVER_DISPATCH )RdrFsdRead;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_WRITE] =
|
|
(PDRIVER_DISPATCH )RdrFsdWrite;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
|
(PDRIVER_DISPATCH )RdrFsdQueryInformationFile;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
|
|
(PDRIVER_DISPATCH )RdrFsdSetInformationFile;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_QUERY_EA] =
|
|
(PDRIVER_DISPATCH )RdrFsdQueryEa;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_SET_EA] =
|
|
(PDRIVER_DISPATCH )RdrFsdSetEa;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
|
|
(PDRIVER_DISPATCH )RdrFsdFlushBuffersFile;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
|
|
(PDRIVER_DISPATCH )RdrFsdQueryVolumeInformationFile;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
|
|
(PDRIVER_DISPATCH)RdrNotSupported;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] =
|
|
(PDRIVER_DISPATCH )RdrFsdDirectoryControl;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
|
|
(PDRIVER_DISPATCH )RdrFsdFsControlFile;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
|
|
(PDRIVER_DISPATCH )RdrFsdDeviceIoControlFile;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] =
|
|
(PDRIVER_DISPATCH )RdrFsdLockOperation;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_CLEANUP] =
|
|
(PDRIVER_DISPATCH )RdrFsdCleanup;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] =
|
|
(PDRIVER_DISPATCH )RdrFsdQuerySecurity;
|
|
|
|
RdrDriverObject->MajorFunction[IRP_MJ_SET_SECURITY] =
|
|
(PDRIVER_DISPATCH )RdrFsdSetSecurity;
|
|
|
|
//
|
|
// Initialize the Fast I/O call backs used by the I/O system and the
|
|
// resource call backs.
|
|
//
|
|
|
|
RdrDriverObject->FastIoDispatch = &RdrFastIoDispatch;
|
|
|
|
RdrFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
|
|
RdrFastIoDispatch.FastIoCheckIfPossible = RdrFastIoCheckIfPossible; // CheckForFastIo
|
|
RdrFastIoDispatch.FastIoRead = FsRtlCopyRead; // Read
|
|
RdrFastIoDispatch.FastIoWrite = FsRtlCopyWrite; // Write
|
|
RdrFastIoDispatch.FastIoQueryBasicInfo = RdrFastQueryBasicInfo; // QueryBasicInfo
|
|
RdrFastIoDispatch.FastIoQueryStandardInfo = RdrFastQueryStdInfo; // QueryStandardInfo
|
|
RdrFastIoDispatch.FastIoLock = NULL; // Lock
|
|
RdrFastIoDispatch.FastIoUnlockSingle = NULL; // UnlockSingle
|
|
RdrFastIoDispatch.FastIoUnlockAll = NULL; // UnlockAll
|
|
RdrFastIoDispatch.FastIoUnlockAllByKey = NULL; // UnlockAllByKey
|
|
RdrFastIoDispatch.FastIoDeviceControl = NULL; // IoDeviceControl
|
|
|
|
RdrDeviceObject->CacheManagerCallbacks.AcquireForLazyWrite = RdrAcquireFcbForLazyWrite;
|
|
RdrDeviceObject->CacheManagerCallbacks.ReleaseFromLazyWrite = RdrReleaseFcbFromLazyWrite;
|
|
RdrDeviceObject->CacheManagerCallbacks.AcquireForReadAhead = RdrAcquireFcbForReadAhead;
|
|
RdrDeviceObject->CacheManagerCallbacks.ReleaseFromReadAhead = RdrReleaseFcbFromReadAhead;
|
|
|
|
|
|
Status = RdrInitializeWorkQueue(&RdrDeviceObject->IrpWorkQueue,
|
|
1, // Set one maximum thread at start
|
|
10*60, // 10 minute idle time limit
|
|
RdrWorkerDispatch,
|
|
&RdrDeviceObject->IrpWorkQueue);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
InternalError(("RdrInitialize cannot create system thread\n"));
|
|
RdrWriteErrorLogEntry(
|
|
NULL,
|
|
IO_ERR_INSUFFICIENT_RESOURCES,
|
|
EVENT_RDR_CANT_CREATE_THREAD,
|
|
Status,
|
|
NULL,
|
|
0
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
RdrInitializeIrpContext();
|
|
|
|
//
|
|
// Initialize the idle timer package.
|
|
//
|
|
|
|
RdrInitializeTimerPackage();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|