/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    RxStruc.h

Abstract:

    This module defines the data structures that make up the major internal
    part of the Rx file system.

Author:

    Gary Kimura     [GaryKi]    28-Dec-1989

Revision History:

    Joe Linn        [joelinn]   aug-1994 moved over to rdbss

--*/

#ifndef _RDBSSSTRUC_
#define _RDBSSSTRUC_

#include "prefix.h"
#include "lowio.h"
#include "scavengr.h"      // scavenger related definitions.
#include "RxContx.h"
#include "mrx.h"
#include "Fcb.h"

//define our byte offsets to be the full 64 bits
typedef LONGLONG RXVBO;

#if 0
//
//  Define who many freed structures we are willing to keep around
//

#define FREE_FOBX_SIZE                   (8)
#define FREE_FCB_SIZE                    (8)
#define FREE_NON_PAGED_FCB_SIZE          (8)

#define FREE_128_BYTE_SIZE               (16)
#define FREE_256_BYTE_SIZE               (16)
#define FREE_512_BYTE_SIZE               (16)
#endif //0


//
//  We will use both a common and private dispatch tables on a per FCB basis to (a) get
//  some encapsulation and (b) [less important] go a little faster. The driver table then gets
//  optimized for the most common case. Right now we just use the common dispatch...later and
//  Eventually, all the FCBs will have pointers to optimized dispatch tables.
//

//  used to synchronize access to  rxcontxs and structures

extern RX_SPIN_LOCK RxStrucSupSpinLock;


typedef struct _RDBSS_EXPORTS {
    RX_SPIN_LOCK             *pRxStrucSupSpinLock;
    PLONG                    pRxDebugTraceIndent;
} RDBSS_EXPORTS, *PRDBSS_EXPORTS;

extern RDBSS_EXPORTS RxExports;

// this type is used with table locks to track whether or not the lock
// should be released

typedef enum _LOCK_HOLDING_STATE {
    LHS_LockNotHeld,
    LHS_SharedLockHeld,
    LHS_ExclusiveLockHeld
} LOCK_HOLDING_STATE;

//
//  The RDBSS_DATA record is the top record in the Rx file system in-memory
//  data structure.  This structure must be allocated from non-paged pool.
//

typedef struct _RDBSS_DATA {

    //
    //  The type and size of this record (must be RDBSS_NTC_DATA_HEADER)
    //

    NODE_TYPE_CODE NodeTypeCode;
    NODE_BYTE_SIZE NodeByteSize;

    //  The Driver object we were initialized with

    PDRIVER_OBJECT DriverObject;

    //
    // Mini Rdr registration related fields
    //

    LONG      NumberOfMinirdrsStarted;

    FAST_MUTEX MinirdrRegistrationMutex;
    LIST_ENTRY RegisteredMiniRdrs;          //protected by the mutex
    LONG       NumberOfMinirdrsRegistered;  //protected by the mutex

    //
    //  A pointer to our EPROCESS struct, which is a required input to the
    //  Cache Management subsystem.
    //

    PEPROCESS OurProcess;

#if 0
    //
    //  This is the ExWorkerItem that does both kinds of deferred closes.
    //

    RX_WORK_QUEUE_ITEM RxCloseItem;
#endif //0

    //
    //  Cache manager call back structures, which must be passed on each call
    //  to CcInitializeCacheMap.
    //

    CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
    CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks;

    //  To control access to the global Rx data record

    ERESOURCE Resource;

} RDBSS_DATA;
typedef RDBSS_DATA *PRDBSS_DATA;

extern RDBSS_DATA RxData;

extern PEPROCESS
RxGetRDBSSProcess();

//
// Note: A Strategy needs to be in place to deal with requests for stopping the
// RDBSS when requests are active.
//

typedef enum _RX_RDBSS_STATE_ {
   RDBSS_STARTABLE = 0,  //RDBSS_START_IN_PROGRESS,
   RDBSS_STARTED,
   RDBSS_STOP_IN_PROGRESS
   //this state deleted with cause! RDBSS_STOPPED
} RX_RDBSS_STATE, *PRX_RDBSS_STATE;

typedef struct _RDBSS_STARTSTOP_CONTEXT_ {
   RX_RDBSS_STATE State;
   ULONG          Version;
   PRX_CONTEXT    pStopContext;
} RDBSS_STARTSTOP_CONTEXT, *PRDBSS_STARTSTOP_CONTEXT;

typedef struct _MRX_CALLDOWN_COMPLETION_CONTEXT_ {
   LONG     WaitCount;
   KEVENT   Event;
} MRX_CALLDOWN_COMPLETION_CONTEXT,
  *PMRX_CALLDOWN_COMPLETION_CONTEXT;

typedef
NTSTATUS
(NTAPI *PMRX_CALLDOWN_ROUTINE) (
    IN OUT PVOID pCalldownParameter);


typedef struct _MRX_CALLDOWN_CONTEXT_ {
   RX_WORK_QUEUE_ITEM               WorkQueueItem;
   PRDBSS_DEVICE_OBJECT             pMRxDeviceObject;
   PMRX_CALLDOWN_COMPLETION_CONTEXT pCompletionContext;
   PMRX_CALLDOWN_ROUTINE            pRoutine;
   NTSTATUS                         CompletionStatus;
   PVOID                            pParameter;
} MRX_CALLDOWN_CONTEXT, *PMRX_CALLDOWN_CONTEXT;

typedef struct _RX_DISPATCHER_CONTEXT_ {
   LONG     NumberOfWorkerThreads;
   PKEVENT  pTearDownEvent;
} RX_DISPATCHER_CONTEXT, *PRX_DISPATCHER_CONTEXT;

#define RxSetRdbssState(RxDeviceObject,NewState)                \
        {                                                       \
           KIRQL SavedIrql;                                     \
           KeAcquireSpinLock(&RxStrucSupSpinLock,&SavedIrql);   \
           RxDeviceObject->StartStopContext.State = (NewState); \
           KeReleaseSpinLock(&RxStrucSupSpinLock,SavedIrql);    \
        }

#define RxGetRdbssState(RxDeviceObject)         \
        (RxDeviceObject)->StartStopContext.State

extern BOOLEAN
RxIsOperationCompatibleWithRdbssState(PIRP pIrp);

//
//  The RDBSS Device Object is an I/O system device object with additions for
//  the various structures needed by each minirdr: the dispatch, export-to-minirdr
//  structure, MUP call characteristics, list of active operations, etc.
//

typedef struct _RDBSS_DEVICE_OBJECT {

    union {
        DEVICE_OBJECT DeviceObject;
#ifndef __cplusplus
        DEVICE_OBJECT;
#endif // __cplusplus
    };

    ULONG RegistrationControls;
    PRDBSS_EXPORTS    RdbssExports;      //stuff that the minirdr needs to know
    PDEVICE_OBJECT    RDBSSDeviceObject; // set to NULL if monolithic
    PMINIRDR_DISPATCH Dispatch; // the mini rdr dispatch vector
    UNICODE_STRING    DeviceName;

    ULONG             NetworkProviderPriority;

    HANDLE            MupHandle;

    BOOLEAN           RegisterUncProvider;
    BOOLEAN           RegisterMailSlotProvider;
    BOOLEAN           RegisteredAsFileSystem;
    BOOLEAN           Unused;

    LIST_ENTRY        MiniRdrListLinks;

    ULONG             NumberOfActiveFcbs;
    ULONG             NumberOfActiveContexts;

    struct {
        LARGE_INTEGER   PagingReadBytesRequested;
        LARGE_INTEGER   NonPagingReadBytesRequested;
        LARGE_INTEGER   CacheReadBytesRequested;
        LARGE_INTEGER   FastReadBytesRequested;
        LARGE_INTEGER   NetworkReadBytesRequested;
        ULONG           ReadOperations;
        ULONG           FastReadOperations;
        ULONG           RandomReadOperations;

        LARGE_INTEGER   PagingWriteBytesRequested;
        LARGE_INTEGER   NonPagingWriteBytesRequested;
        LARGE_INTEGER   CacheWriteBytesRequested;
        LARGE_INTEGER   FastWriteBytesRequested;
        LARGE_INTEGER   NetworkWriteBytesRequested;
        ULONG           WriteOperations;
        ULONG           FastWriteOperations;
        ULONG           RandomWriteOperations;
    };

    //
    //  The following field tells how many requests for this volume have
    //  either been enqueued to ExWorker threads or are currently being
    //  serviced by ExWorker threads.  If the number goes above
    //  a certain threshold, put the request on the overflow queue to be
    //  executed later.
    //

    LONG PostedRequestCount[MaximumWorkQueue];

    //
    //  The following field indicates the number of IRP's waiting
    //  to be serviced in the overflow queue.
    //

    LONG OverflowQueueCount[MaximumWorkQueue];

    //
    //  The following field contains the queue header of the overflow queue.
    //  The Overflow queue is a list of IRP's linked via the IRP's ListEntry
    //  field.
    //

    LIST_ENTRY OverflowQueue[MaximumWorkQueue];

    //
    //  The following spinlock protects access to all the above fields.
    //

    RX_SPIN_LOCK OverflowQueueSpinLock;

    //
    // The following fields are required for synchronization with async.
    // requests issued by the RDBSS on behalf of this mini redirector on
    // on shutdown.
    //

    LONG    AsynchronousRequestsPending;

    PKEVENT pAsynchronousRequestsCompletionEvent;

    RDBSS_STARTSTOP_CONTEXT StartStopContext;

    RX_DISPATCHER_CONTEXT   DispatcherContext;

    struct _RX_PREFIX_TABLE  *pRxNetNameTable; //some guys may want to share
    struct _RX_PREFIX_TABLE  RxNetNameTableInDeviceObject;

    PRDBSS_SCAVENGER pRdbssScavenger; //for sharing
    RDBSS_SCAVENGER RdbssScavengerInDeviceObject;

} RDBSS_DEVICE_OBJECT;

typedef RDBSS_DEVICE_OBJECT *PRDBSS_DEVICE_OBJECT;

INLINE VOID
NTAPI
RxUnregisterMinirdr(
    IN PRDBSS_DEVICE_OBJECT RxDeviceObject
)
{
    PDEVICE_OBJECT RDBSSDeviceObject;

    RDBSSDeviceObject = RxDeviceObject->RDBSSDeviceObject;

    RxpUnregisterMinirdr(RxDeviceObject);

    if (RDBSSDeviceObject != NULL) {
        ObDereferenceObject(RDBSSDeviceObject);
    }
}

extern FAST_MUTEX RxMinirdrRegistrationMutex;
extern LIST_ENTRY RxRegisteredMiniRdrs;
extern ULONG RxNumberOfMinirdrs;

#endif // _RDBSSSTRUC_