384 lines
10 KiB
C
384 lines
10 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
umrx.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This header defines the UMRxEngine object and associated functions.
|
||
|
The UMRxEngine provides a set of services for dispatch function
|
||
|
writers so they can reflect requests to user-mode components.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Code / Ideas have been adopted from Joe Linn's user-mode reflector
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Rohan Phillips [Rohanp] 18-Jan-2001
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifndef _UMRX_H_
|
||
|
#define _UMRX_H_
|
||
|
|
||
|
//
|
||
|
// defines and tags
|
||
|
//
|
||
|
#define UMRX_ENGINE_TAG (ULONG) 'xrmU'
|
||
|
#define UMRX_CONTEXT_TAG (ULONG) 'xtcU'
|
||
|
|
||
|
#define REASSIGN_MID 1
|
||
|
#define DONT_REASSIGN_MID 0
|
||
|
|
||
|
#define TICKS_PER_SECOND (10 * 1000 * 1000)
|
||
|
|
||
|
typedef USHORT NODE_TYPE_CODE;
|
||
|
typedef CSHORT NODE_BYTE_SIZE;
|
||
|
|
||
|
typedef struct _MRX_NORMAL_NODE_HEADER {
|
||
|
NODE_TYPE_CODE NodeTypeCode;
|
||
|
NODE_BYTE_SIZE NodeByteSize;
|
||
|
ULONG NodeReferenceCount;
|
||
|
} MRX_NORMAL_NODE_HEADER;
|
||
|
|
||
|
|
||
|
enum {
|
||
|
UMRX_ENGINE_STATE_STOPPED = 0,
|
||
|
UMRX_ENGINE_STATE_STARTING,
|
||
|
UMRX_ENGINE_STATE_STARTED,
|
||
|
UMRX_ENGINE_STATE_STOPPING
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Define the UMRxEngine object. There is one such object for
|
||
|
// every NET_ROOT. This object contains all the data str needed
|
||
|
// for routing kernel-mode requests to user-mode.
|
||
|
//
|
||
|
typedef struct _UMRX_ENGINE {
|
||
|
// MID to UMRxContext mapping table
|
||
|
struct {
|
||
|
PRX_MID_ATLAS MidAtlas;
|
||
|
FAST_MUTEX MidManagementMutex;
|
||
|
LIST_ENTRY WaitingForMidListhead;
|
||
|
};
|
||
|
struct {
|
||
|
KQUEUE Queue;
|
||
|
LARGE_INTEGER TimeOut;
|
||
|
LIST_ENTRY PoisonEntry;
|
||
|
ULONG NumberOfWorkerThreads;
|
||
|
ULONG NumberOfWorkItems;
|
||
|
ERESOURCE Lock;
|
||
|
ULONG State;
|
||
|
ULONG ThreadAborted;
|
||
|
} Q;
|
||
|
ULONG NextSerialNumber;
|
||
|
ULONG cUserModeReflectionsInProgress;
|
||
|
LIST_ENTRY ActiveLinkHead;
|
||
|
} UMRX_ENGINE, *PUMRX_ENGINE;
|
||
|
|
||
|
|
||
|
void
|
||
|
UMRxAbortPendingRequests(IN PUMRX_ENGINE pUMRxEngine);
|
||
|
|
||
|
//
|
||
|
// Forwards
|
||
|
//
|
||
|
struct _UMRX_CONTEXT;
|
||
|
typedef struct _UMRX_CONTEXT *PUMRX_CONTEXT;
|
||
|
|
||
|
//
|
||
|
// Signatures for function pointers
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Continue routine is called by InitiateRequest -
|
||
|
// This turns around and submits the request to the
|
||
|
// UMR engine with callbacks for FORMAT and COMPLETION.
|
||
|
//
|
||
|
typedef
|
||
|
NTSTATUS
|
||
|
(*PUMRX_CONTINUE_ROUTINE) (
|
||
|
PUMRX_CONTEXT pUMRxContext,
|
||
|
PRX_CONTEXT pRxContext
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Format routine - called before user-mode worker thread completes.
|
||
|
// Each dispatch routine will interpret the WORK_ITEM union based on opcode.
|
||
|
// eg: for Create, WorkItem is a CREATE_REQUEST.
|
||
|
//
|
||
|
typedef
|
||
|
NTSTATUS
|
||
|
(*PUMRX_USERMODE_FORMAT_ROUTINE) (
|
||
|
PUMRX_CONTEXT pUMRxContext,
|
||
|
PRX_CONTEXT pRxContext,
|
||
|
PUMRX_USERMODE_WORKITEM WorkItem,
|
||
|
ULONG WorkItemLength,
|
||
|
PULONG ReturnedLength
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Completion routine - called when user-mode response is received.
|
||
|
// Each dispatch routine will interpret the WORK_ITEM union based on opcode.
|
||
|
// eg: for Create, WorkItem is a CREATE_RESPONSE.
|
||
|
//
|
||
|
typedef
|
||
|
VOID
|
||
|
(*PUMRX_USERMODE_COMPLETION_ROUTINE) (
|
||
|
PUMRX_CONTEXT pUMRxContext,
|
||
|
PRX_CONTEXT pRxContext,
|
||
|
PUMRX_USERMODE_WORKITEM WorkItem,
|
||
|
ULONG WorkItemLength
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Type of operation reflected to user-mode
|
||
|
//
|
||
|
typedef enum _UMRX_CONTEXT_TYPE {
|
||
|
UMRX_CTXTYPE_IFSDFSLINK = 0,
|
||
|
UMRX_CTXTYPE_GETDFSREPLICAS,
|
||
|
UMRX_CTXTYPE_MAXIMUM
|
||
|
} UMRX_CONTEXT_TYPE;
|
||
|
|
||
|
//
|
||
|
// Define the UMRxContext. This context is sent as part of
|
||
|
// the REQUEST to user-mode. The user-mode handler will
|
||
|
// send the context back in a RESPONSE. The context will be
|
||
|
// used to do the rendezvous with blocked requests.
|
||
|
//
|
||
|
|
||
|
#define UMRX_NTC_CONTEXT ((USHORT)0xedd0)
|
||
|
|
||
|
typedef struct _UMRX_CONTEXT{
|
||
|
MRX_NORMAL_NODE_HEADER;
|
||
|
PUMRX_ENGINE pUMRxEngine; // owning engine object
|
||
|
PRX_CONTEXT RxContext;
|
||
|
PVOID SavedMinirdrContextPtr;
|
||
|
union {
|
||
|
IO_STATUS_BLOCK;
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
};
|
||
|
UMRX_CONTEXT_TYPE CTXType;
|
||
|
PUMRX_CONTINUE_ROUTINE Continuation;
|
||
|
struct {
|
||
|
LIST_ENTRY WorkQueueLinks;
|
||
|
PUMRX_USERMODE_FORMAT_ROUTINE FormatRoutine;
|
||
|
PUMRX_USERMODE_COMPLETION_ROUTINE CompletionRoutine;
|
||
|
KEVENT WaitForMidEvent;
|
||
|
ULONG CallUpSerialNumber;
|
||
|
USHORT CallUpMid;
|
||
|
} UserMode;
|
||
|
LIST_ENTRY ActiveLink;
|
||
|
} UMRX_CONTEXT, *PUMRX_CONTEXT;
|
||
|
|
||
|
#define UMRxReferenceContext(pUMRxContext) {\
|
||
|
ULONG result = InterlockedIncrement(&(pUMRxContext)->NodeReferenceCount); \
|
||
|
RxDbgTrace(0, (DEBUG_TRACE_UMRX), \
|
||
|
("ReferenceContext result=%08lx\n", result )); \
|
||
|
}
|
||
|
|
||
|
typedef struct _UMRX_WORKITEM_HEADER_PRIVATE {
|
||
|
PUMRX_CONTEXT pUMRxContext;
|
||
|
ULONG SerialNumber;
|
||
|
USHORT Mid;
|
||
|
} UMRX_WORKITEM_HEADER_PRIVATE, *PUMRX_WORKITEM_HEADER_PRIVATE;
|
||
|
|
||
|
//
|
||
|
// Create a UMRX_ENGINE object
|
||
|
//
|
||
|
PUMRX_ENGINE
|
||
|
CreateUMRxEngine();
|
||
|
|
||
|
//
|
||
|
// Close a UMRX_ENGINE object -
|
||
|
// Owner of object ensures that all usage of this object
|
||
|
// is within the Create/Finalize span.
|
||
|
//
|
||
|
VOID
|
||
|
FinalizeUMRxEngine(
|
||
|
IN PUMRX_ENGINE pUMRxEngine
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Complete queued requests and optional cleanup when the store has exited
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxEngineCompleteQueuedRequests(
|
||
|
IN PUMRX_ENGINE pUMRxEngine,
|
||
|
IN NTSTATUS CompletionStatus,
|
||
|
IN BOOLEAN fCleanup
|
||
|
);
|
||
|
//
|
||
|
// Used to allow an engine to be used again after it's been shutdown.
|
||
|
//
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxEngineRestart(
|
||
|
IN PUMRX_ENGINE pUMRxEngine
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Initiate a request to the UMR engine -
|
||
|
// This creates a UMRxContext that is used for response rendezvous.
|
||
|
// All IFS dispatch routines will start a user-mode reflection by
|
||
|
// calling this routine. Steps in routine:
|
||
|
//
|
||
|
// 1. Allocate a UMRxContext and set RxContext
|
||
|
// (NOTE: need to have ASSERTs that validate this linkage)
|
||
|
// 2. Set Continue routine ptr and call Continue routine
|
||
|
// 3. If Continue routine is done ie not PENDING, Finalize UMRxContext
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxEngineInitiateRequest (
|
||
|
IN PUMRX_ENGINE pUMRxEngine,
|
||
|
IN PRX_CONTEXT RxContext,
|
||
|
IN UMRX_CONTEXT_TYPE RequestType,
|
||
|
IN PUMRX_CONTINUE_ROUTINE Continuation
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Create/Finalize UMRX_CONTEXTs
|
||
|
// These are pool allocs/frees
|
||
|
//
|
||
|
PUMRX_CONTEXT
|
||
|
UMRxCreateAndReferenceContext (
|
||
|
IN PRX_CONTEXT RxContext,
|
||
|
IN UMRX_CONTEXT_TYPE RequestType
|
||
|
);
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
UMRxDereferenceAndFinalizeContext (
|
||
|
IN OUT PUMRX_CONTEXT pUMRxContext
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Submit a request to the UMR engine -
|
||
|
// This adds the request to the engine KQUEUE for processing by
|
||
|
// a user-mode thread. Steps:
|
||
|
//
|
||
|
// 1. set the FORMAT and COMPLETION callbacks in the UMRxContext
|
||
|
// 2. initialize the RxContext sync event
|
||
|
// 3. insert the UMRxContext into the engine KQUEUE
|
||
|
// 4. block on RxContext sync event (for SYNC operations)
|
||
|
// 5. after unblock (ie umode response is back), call Resume routine
|
||
|
//
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
UMRxEngineSubmitRequest(
|
||
|
IN PUMRX_CONTEXT pUMRxContext,
|
||
|
IN PRX_CONTEXT pRxContext,
|
||
|
IN UMRX_CONTEXT_TYPE RequestType,
|
||
|
IN PUMRX_USERMODE_FORMAT_ROUTINE FormatRoutine,
|
||
|
IN PUMRX_USERMODE_COMPLETION_ROUTINE CompletionRoutine
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Resume is called after I/O thread is unblocked by umode RESPONSE.
|
||
|
// This routine calls any Finish callbacks and then Finalizes the
|
||
|
// UMRxContext.
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxResumeEngineContext(
|
||
|
IN OUT PRX_CONTEXT RxContext
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// The following functions run in the context of user-mode
|
||
|
// worker threads that issue WORK IOCTLs. The IOCTL calls the
|
||
|
// following functions in order:
|
||
|
// 1. UMRxCompleteUserModeRequest() - process a response if needed
|
||
|
// 2. UMRxEngineProcessRequest() - process a request if one is
|
||
|
// available on the UMRxEngine KQUEUE. Since these IOCTLs are
|
||
|
// made on a NET_ROOT, the corresponding UMRxEngine is readily
|
||
|
// available in the NET_ROOT extension.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Every IOCTL pended is potentially a Response. If so, process it.
|
||
|
// The first IOCTL pended is usually a NULL Response or 'listen'.
|
||
|
// Steps:
|
||
|
// 1. Get MID from response buffer. Map MID to UMRxContext.
|
||
|
// 2. Call UMRxContext COMPLETION routine.
|
||
|
// 3. Unblock the I/O thread waiting in UMRxEngineSubmitRequest()
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxCompleteUserModeRequest(
|
||
|
IN PUMRX_ENGINE pUMRxEngine,
|
||
|
IN OUT PUMRX_USERMODE_WORKITEM WorkItem,
|
||
|
IN ULONG WorkItemLength,
|
||
|
IN BOOLEAN fReleaseUmrRef,
|
||
|
OUT PIO_STATUS_BLOCK IoStatus,
|
||
|
OUT BOOLEAN * pfReturnImmediately
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// NOTE: if no requests are available, the user-mode thread will
|
||
|
// block till a request is available (It is trivial to make this
|
||
|
// a more async model).
|
||
|
//
|
||
|
// If a request is available, get the corresponding UMRxContext and
|
||
|
// call ProcessRequest.
|
||
|
// Steps:
|
||
|
// 1. Call KeRemoveQueue() to remove a request from the UMRxEngine KQUEUE.
|
||
|
// 2. Get a MID for this UMRxContext and fill it in the WORK_ITEM header.
|
||
|
// 3. Call the UMRxContext FORMAT routine - this fills in the Request params.
|
||
|
// 4. return STATUS_SUCCESS - this causes the IOCTL to complete which
|
||
|
// triggers the user-mode completion and processing of the REQUEST.
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxEngineProcessRequest(
|
||
|
IN PUMRX_ENGINE pUMRxEngine,
|
||
|
OUT PUMRX_USERMODE_WORKITEM WorkItem,
|
||
|
IN ULONG WorkItemLength,
|
||
|
OUT PULONG FormattedWorkItemLength
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// This is called in response to a WORK_CLEANUP IOCTL.
|
||
|
// This routine will insert a dummy item in the engine KQUEUE.
|
||
|
// Each such dummy item inserted will release one thread.
|
||
|
//
|
||
|
NTSTATUS
|
||
|
UMRxEngineReleaseThreads(
|
||
|
IN PUMRX_ENGINE pUMRxEngine
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Cancel I/O infrastructure
|
||
|
//
|
||
|
typedef
|
||
|
NTSTATUS
|
||
|
(NTAPI *PUMRX_CANCEL_ROUTINE) (
|
||
|
PRX_CONTEXT pRxContext);
|
||
|
|
||
|
// The RX_CONTEXT instance has four fields ( ULONG's ) provided by the wrapper
|
||
|
// which can be used by the mini rdr to store its context. This is used by
|
||
|
// the reflector to identify the parameters for request cancellation
|
||
|
|
||
|
typedef struct _UMRX_RX_CONTEXT {
|
||
|
PUMRX_CANCEL_ROUTINE pCancelRoutine;
|
||
|
PVOID pCancelContext;
|
||
|
union {
|
||
|
struct {
|
||
|
PUMRX_CONTEXT pUMRxContext;
|
||
|
ULONG RxSyncTimeout;
|
||
|
};
|
||
|
IO_STATUS_BLOCK SyncCallDownIoStatus;
|
||
|
};
|
||
|
} UMRX_RX_CONTEXT, *PUMRX_RX_CONTEXT;
|
||
|
|
||
|
#define UMRxGetMinirdrContext(pRxContext) \
|
||
|
((PUMRX_RX_CONTEXT)(&(pRxContext)->UMRScratchSpace[0]))
|
||
|
|
||
|
#endif // _UMRX_H_
|
||
|
|
||
|
|
||
|
|