windows-nt/Source/XPSP1/NT/base/cluster/clusnet/driver/clusnet.c

1388 lines
27 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
clusnet.c
Abstract:
Intialization and dispatch routines for the Cluster Network Driver.
Author:
Mike Massa (mikemas) July 29, 1996
Revision History:
Who When What
-------- -------- ----------------------------------------------
mikemas 07-29-96 created
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
#include "clusnet.tmh"
#include <sspi.h>
//
// Global Data
//
PDRIVER_OBJECT CnDriverObject = NULL;
PDEVICE_OBJECT CnDeviceObject = NULL;
KSPIN_LOCK CnDeviceObjectStackSizeLock = 0;
PDEVICE_OBJECT CdpDeviceObject = NULL;
PKPROCESS CnSystemProcess = NULL;
CN_STATE CnState = CnStateShutdown;
PERESOURCE CnResource = NULL;
CL_NODE_ID CnMinValidNodeId = ClusterInvalidNodeId;
CL_NODE_ID CnMaxValidNodeId = ClusterInvalidNodeId;
CL_NODE_ID CnLocalNodeId = ClusterInvalidNodeId;
KSPIN_LOCK CnShutdownLock = 0;
BOOLEAN CnShutdownScheduled = FALSE;
PKEVENT CnShutdownEvent = NULL;
WORK_QUEUE_ITEM CnShutdownWorkItem = {{NULL, NULL}, NULL, NULL};
HANDLE ClussvcProcessHandle = NULL;
//
// vars for managing Events. The lookaside list generates Event data structs
// that are used to carry the data back to user mode. EventLock is the only
// lock and synchronizes all access to any event structure (both here and in
// CN_FSCONTEXT). EventFileHandles is a list of CN_FSCONTEXT structs that
// are interested in receiving event notifications. To avoid synchronization
// problems between clusnet and mm in clussvc, events have an epoch associated
// with them. MM increments the epoch at the beginning of regroup event and
// updates clusnet at the end of regroup. Any events still pending in the
// event queue with a stale epoch are ignored by MM.
//
// EventDeliveryInProgress is a count of threads that are currently
// iterating through the EventFileHandles list and delivering events.
// The EventFileHandles list cannot be modified while EventDeliveryInProgress
// is greater than zero. EventDeliveryComplete is a notification event
// that is signalled when the EventDeliveryInProgress count reaches zero.
// EventRevisitRequired indicates whether a new event IRP arrived during
// event delivery. To avoid delivering events out of order, the IRP cannot
// be completed immediately.
//
PNPAGED_LOOKASIDE_LIST EventLookasideList = NULL;
LIST_ENTRY EventFileHandles = {0,0};
#if DBG
CN_LOCK EventLock = {0,0};
#else
CN_LOCK EventLock = 0;
#endif
ULONG EventEpoch;
LONG EventDeliveryInProgress = 0;
KEVENT EventDeliveryComplete;
BOOLEAN EventRevisitRequired = FALSE;
#if DBG
ULONG CnDebug = 0;
#endif // DBG
//
// Private Types
//
//
// Private Data
//
SECURITY_STATUS
SEC_ENTRY
SecSetPagingMode(
BOOLEAN Pageable
);
BOOLEAN SecurityPagingModeSet = FALSE;
//
// Local Prototypes
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
CnCreateDeviceObjects(
IN PDRIVER_OBJECT DriverObject
);
VOID
CnDeleteDeviceObjects(
VOID
);
VOID
CnAdjustDeviceObjectStackSize(
PDEVICE_OBJECT ClusnetDeviceObject,
PDEVICE_OBJECT TargetDeviceObject
);
//
// Mark init code as discardable.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(INIT, CnCreateDeviceObjects)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(PAGE, CnDeleteDeviceObjects)
#endif // ALLOC_PRAGMA
//
// Function definitions
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Initialization routine for the driver.
Arguments:
DriverObject - Pointer to the driver object created by the system.
RegistryPath - The driver's registry key.
Return Value:
An NT status code.
--*/
{
NTSTATUS status;
USHORT i;
#if DBG
volatile BOOLEAN DontLoad = FALSE;
if ( DontLoad )
return STATUS_UNSUCCESSFUL;
#endif
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[ClusNet] Loading...\n"));
}
WPP_INIT_TRACING(DriverObject, RegistryPath);
//
// Save a pointer to the system process so that we can open
// handles in the context of this process later.
//
CnSystemProcess = (PKPROCESS) IoGetCurrentProcess();
//
// Allocate a synchronization resource.
//
CnResource = CnAllocatePool(sizeof(ERESOURCE));
if (CnResource == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
status = ExInitializeResourceLite(CnResource);
if (!NT_SUCCESS(status)) {
goto error_exit;
}
//
// initialize the mechanisms used to deliver event callbacks
// to user mode
//
EventLookasideList = CnAllocatePool(sizeof(NPAGED_LOOKASIDE_LIST));
if (EventLookasideList == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
}
ExInitializeNPagedLookasideList(EventLookasideList,
NULL,
NULL,
0,
sizeof( CLUSNET_EVENT_ENTRY ),
CN_EVENT_SIGNATURE,
0);
CnInitializeLock( &EventLock, CNP_EVENT_LOCK );
InitializeListHead( &EventFileHandles );
KeInitializeEvent( &EventDeliveryComplete, NotificationEvent, TRUE );
//
// Initialize miscellaneous other items.
//
KeInitializeSpinLock(&CnShutdownLock);
KeInitializeSpinLock(&CnDeviceObjectStackSizeLock);
//
// Initialize the driver object
//
CnDriverObject = DriverObject;
DriverObject->DriverUnload = DriverUnload;
DriverObject->FastIoDispatch = NULL;
for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = CnDispatch;
}
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
CnDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
CnDispatchInternalDeviceControl;
//
// Create all the devices exported by this driver.
//
status = CnCreateDeviceObjects(DriverObject);
if (!NT_SUCCESS(status)) {
goto error_exit;
}
#ifdef MEMLOGGING
//
// initialize the in-memory log
//
CnInitializeMemoryLog();
#endif // MEMLOGGING
//
// Load the IP Address and NetBT support.
// This must be done before the transport registers for PnP events.
//
status = IpaLoad();
if (!NT_SUCCESS(status)) {
goto error_exit;
}
status = NbtIfLoad();
if (!NT_SUCCESS(status)) {
goto error_exit;
}
//
// Load the transport component
//
status = CxLoad(RegistryPath);
if (!NT_SUCCESS(status)) {
goto error_exit;
}
#ifdef MM_IN_CLUSNET
//
// Load the membership component
//
status = CmmLoad(RegistryPath);
if (!NT_SUCCESS(status)) {
goto error_exit;
}
#endif // MM_IN_CLUSNET
//
// make ksecdd non-pagable so we can sign and verify
// signatures at raised IRQL
//
SecSetPagingMode( FALSE );
SecurityPagingModeSet = TRUE;
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[ClusNet] Loaded.\n"));
}
return(STATUS_SUCCESS);
error_exit:
DriverUnload(CnDriverObject);
return(status);
}
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Unloads the driver.
Arguments:
DriverObject - Pointer to the driver object created by the system.
Return Value:
None
--*/
{
PAGED_CODE();
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[ClusNet] Unloading...\n"));
}
CnTrace(HBEAT_ERROR,0, "[ClusNet] Unloading...\n");
//
// First, force a shutdown.
//
CnShutdown();
//
// Now unload the components.
//
#ifdef MM_IN_CLUSNET
CmmUnload();
#endif // MM_IN_CLUSNET
CxUnload();
#ifdef MEMLOGGING
//
// initialize the in-memory log
//
CnFreeMemoryLog();
#endif // MEMLOGGING
CnDeleteDeviceObjects();
if (CnResource != NULL) {
ExDeleteResourceLite(CnResource);
CnFreePool(CnResource); CnResource = NULL;
}
CnDriverObject = NULL;
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[ClusNet] Unloaded.\n"));
}
if (EventLookasideList != NULL) {
ExDeleteNPagedLookasideList( EventLookasideList );
CnFreePool( EventLookasideList ); EventLookasideList = NULL;
}
//
// finally, allow the security driver to return to nonpaged mode
//
if ( SecurityPagingModeSet ) {
SecSetPagingMode( TRUE );
}
WPP_CLEANUP(DriverObject);
return;
} // DriverUnload
NTSTATUS
CnCreateDeviceObjects(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Creates the device objects exported by the driver.
Arguments:
DriverObject - Pointer to the driver object created by the system.
Return Value:
An NT status code.
--*/
{
NTSTATUS status;
UNICODE_STRING deviceName;
//
// Create the driver control device
//
RtlInitUnicodeString(&deviceName, DD_CLUSNET_DEVICE_NAME);
status = IoCreateDevice(
DriverObject,
0,
&deviceName,
FILE_DEVICE_NETWORK,
0,
FALSE,
&CnDeviceObject
);
if (!NT_SUCCESS(status)) {
CNPRINT((
"[ClusNet] Failed to create %ws device object, status %lx\n",
deviceName.Buffer,
status
));
return(status);
}
CnDeviceObject->Flags |= DO_DIRECT_IO;
CnDeviceObject->StackSize = CN_DEFAULT_IRP_STACK_SIZE;
status = IoRegisterShutdownNotification(CnDeviceObject);
if (!NT_SUCCESS(status)) {
CNPRINT((
"[ClusNet] Failed to register for shutdown notification, status %lx\n",
status
));
}
#if defined(WMI_TRACING)
status = IoWMIRegistrationControl (CnDeviceObject, WMIREG_ACTION_REGISTER);
if (!NT_SUCCESS(status)) {
CNPRINT(("[ClusNet] Failed to register for WMI Support, %lx\n", status) );
}
#endif
//
// Create the datagram transport device
//
RtlInitUnicodeString(&deviceName, DD_CDP_DEVICE_NAME);
status = IoCreateDevice(
DriverObject,
0,
&deviceName,
FILE_DEVICE_NETWORK,
0,
FALSE,
&CdpDeviceObject
);
if (!NT_SUCCESS(status)) {
CNPRINT((
"[ClusNet] Failed to create %ws device object, status %lx\n",
deviceName.Buffer,
status
));
return(status);
}
CdpDeviceObject->Flags |= DO_DIRECT_IO;
CdpDeviceObject->StackSize = CDP_DEFAULT_IRP_STACK_SIZE;
return(STATUS_SUCCESS);
}
VOID
CnDeleteDeviceObjects(
VOID
)
/*++
Routine Description:
Deletes the device objects exported by the driver.
Arguments:
None.
Return Value:
None.
--*/
{
PAGED_CODE();
if (CnDeviceObject != NULL) {
#if defined(WMI_TRACING)
IoWMIRegistrationControl(CnDeviceObject, WMIREG_ACTION_DEREGISTER);
#endif
IoDeleteDevice(CnDeviceObject);
CnDeviceObject = NULL;
}
if (CdpDeviceObject != NULL) {
IoDeleteDevice(CdpDeviceObject);
CdpDeviceObject = NULL;
}
return;
}
NTSTATUS
CnInitialize(
IN CL_NODE_ID LocalNodeId,
IN ULONG MaxNodes
)
/*++
Routine Description:
Initialization routine for the Cluster Network Driver.
Called when an initialize request is received.
Arguments:
LocalNodeId - The ID of the local node.
MaxNodes - The maximum number of valid cluster nodes.
Return Value:
An NT status code.
--*/
{
NTSTATUS status;
KIRQL irql;
if ( (MaxNodes == 0) ||
(LocalNodeId < ClusterMinNodeId) ||
(LocalNodeId > (ClusterMinNodeId + MaxNodes - 1))
)
{
return(STATUS_INVALID_PARAMETER);
}
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Initializing...\n"));
}
CnState = CnStateInitializePending;
//
// Reset global values
//
CnAssert(CnLocalNodeId == ClusterInvalidNodeId);
CnAssert(CnMinValidNodeId == ClusterInvalidNodeId);
CnAssert(CnMaxValidNodeId == ClusterInvalidNodeId);
CnMinValidNodeId = ClusterMinNodeId;
CnMaxValidNodeId = ClusterMinNodeId + MaxNodes - 1;
CnLocalNodeId = LocalNodeId;
//
// Reenable the halt processing mechanism.
//
KeAcquireSpinLock(&CnShutdownLock, &irql);
CnShutdownScheduled = FALSE;
CnShutdownEvent = NULL;
KeReleaseSpinLock(&CnShutdownLock, irql);
//
// Initialize the IP Address support
//
status = IpaInitialize();
if (status != STATUS_SUCCESS) {
goto error_exit;
}
#ifdef MM_IN_CLUSNET
//
// Call the Membership Manager's init routine. This will in turn call
// the Transport's init routine.
//
status = CmmInitialize();
#else // MM_IN_CLUSNET
status = CxInitialize();
#endif // MM_IN_CLUSNET
if (status == STATUS_SUCCESS) {
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Initialized.\n"));
}
CnState = CnStateInitialized;
}
else {
goto error_exit;
}
return(STATUS_SUCCESS);
error_exit:
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Initialization failed, Shutting down. Status = %08X\n",
status));
}
CnShutdown();
return(status);
} // CnInitialize
NTSTATUS
CnShutdown(
VOID
)
/*++
Routine Description:
Terminates operation of the Cluster Membership Manager.
Called when the Cluster Service is shutting down.
Arguments:
None.
Return Value:
None.
--*/
{
NTSTATUS status;
if ( (CnState == CnStateInitialized) ||
(CnState == CnStateInitializePending)
)
{
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Shutting down...\n"));
}
CnState = CnStateShutdownPending;
//
// Shutdown the NetBT and IP Address support.
//
NbtIfShutdown();
IpaShutdown();
#ifdef MM_IN_CLUSNET
//
// Shutdown the Membership Manager. This will shutdown the
// Transport as a side-effect.
//
CmmShutdown();
#else // MM_IN_CLUSNET
CxShutdown();
#endif // MM_IN_CLUSNET
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Shutdown complete.\n"));
}
CnAssert(CnLocalNodeId != ClusterInvalidNodeId);
CnMinValidNodeId = ClusterInvalidNodeId;
CnMaxValidNodeId = ClusterInvalidNodeId;
CnLocalNodeId = ClusterInvalidNodeId;
CnState = CnStateShutdown;
status = STATUS_SUCCESS;
}
else {
status = STATUS_DEVICE_NOT_READY;
}
//
// always test if we have a handle to this process
// and remove it
//
if ( ClussvcProcessHandle ) {
CnCloseProcessHandle( ClussvcProcessHandle );
ClussvcProcessHandle = NULL;
}
return(status);
} // CnShutdown
VOID
CnShutdownWorkRoutine(
IN PVOID WorkItem
)
{
BOOLEAN acquired;
NTSTATUS Status;
acquired = CnAcquireResourceExclusive(CnResource, TRUE);
if (!acquired) {
KIRQL irql;
CNPRINT(("[Clusnet] Failed to acquire CnResource\n"));
KeAcquireSpinLock(&CnShutdownLock, &irql);
CnShutdownScheduled = FALSE;
if (CnShutdownEvent != NULL) {
KeSetEvent(CnShutdownEvent, IO_NO_INCREMENT, FALSE);
}
KeReleaseSpinLock(&CnShutdownLock, irql);
return;
}
(VOID) CnShutdown();
if (CnShutdownEvent != NULL) {
KeSetEvent(CnShutdownEvent, IO_NO_INCREMENT, FALSE);
}
if (acquired) {
CnReleaseResourceForThread(
CnResource,
(ERESOURCE_THREAD) PsGetCurrentThread()
);
}
//
// Leave CnShutdownScheduled = TRUE until we are reinitialized to
// prevent scheduling unnecessary work items.
//
return;
} // CnShutdownWorkRoutine
BOOLEAN
CnHaltOperation(
IN PKEVENT ShutdownEvent OPTIONAL
)
/*++
Routine Description:
Schedules a critical worker thread to perform clusnet shutdown,
if a thread is not already scheduled.
Arguments:
ShutdownEvent - if provided, event to be signalled after
shutdown is complete
Return value:
TRUE if shutdown was scheduled. FALSE if shutdown was already
scheduled (in which case ShutdownEvent will not be signalled).
--*/
{
KIRQL irql;
KeAcquireSpinLock(&CnShutdownLock, &irql);
if (CnShutdownScheduled) {
KeReleaseSpinLock(&CnShutdownLock, irql);
return(FALSE);
}
CnShutdownScheduled = TRUE;
CnShutdownEvent = ShutdownEvent;
KeReleaseSpinLock(&CnShutdownLock, irql);
//
// Schedule a critical worker thread to do the shutdown work.
//
ExInitializeWorkItem(
&CnShutdownWorkItem,
CnShutdownWorkRoutine,
&CnShutdownWorkItem
);
ExQueueWorkItem(&CnShutdownWorkItem, CriticalWorkQueue);
return(TRUE);
} // CnHaltOperation
//
// ExResource wrappers that disable APCs.
//
BOOLEAN
CnAcquireResourceExclusive(
IN PERESOURCE Resource,
IN BOOLEAN Wait
)
{
BOOLEAN acquired;
KeEnterCriticalRegion();
acquired = ExAcquireResourceExclusiveLite(Resource, Wait);
if (!acquired) {
KeLeaveCriticalRegion();
}
return(acquired);
} // CnAcquireResourceExclusive
BOOLEAN
CnAcquireResourceShared(
IN PERESOURCE Resource,
IN BOOLEAN Wait
)
{
BOOLEAN acquired;
KeEnterCriticalRegion();
acquired = ExAcquireResourceSharedLite(Resource, Wait);
if (!acquired) {
KeLeaveCriticalRegion();
}
return(acquired);
} // CnAcquireResourceShared
VOID
CnReleaseResourceForThread(
IN PERESOURCE Resource,
IN ERESOURCE_THREAD ResourceThreadId
)
{
ExReleaseResourceForThreadLite(Resource, ResourceThreadId);
KeLeaveCriticalRegion();
return;
} // CnReleaseResourceForThread
NTSTATUS
CnCloseProcessHandle(
HANDLE Handle
)
/*++
Routine Description:
Close the cluster service process handle
Arguments:
None
Return Value:
None
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
CnAssert( Handle != NULL );
KeAttachProcess( CnSystemProcess );
Status = ZwClose( Handle );
KeDetachProcess();
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] Process handle released. status = %08X\n", Status));
}
return Status;
}
VOID
CnAdjustDeviceObjectStackSize(
PDEVICE_OBJECT ClusnetDeviceObject,
PDEVICE_OBJECT TargetDeviceObject
)
/*++
Routine Description
Adjust the StackSize of ClusnetDeviceObject so that we
can pass client IRPs down to TargetDeviceObject.
The StackSize of clusnet device objects is initialized to
a default that allows for some leeway for attached drivers.
Arguments
ClusnetDeviceObject - clusnet device object whose StackSize
should be adjusted
TargetDeviceObject - device object clusnet IRPs, originally
issued to clusnet, will be forwarded to
Return value
None
--*/
{
CCHAR defaultStackSize, newStackSize = 0;
KIRQL irql;
if (ClusnetDeviceObject == CnDeviceObject) {
defaultStackSize = CN_DEFAULT_IRP_STACK_SIZE;
}
else if (ClusnetDeviceObject == CdpDeviceObject) {
defaultStackSize = CDP_DEFAULT_IRP_STACK_SIZE;
}
else {
IF_CNDBG(CN_DEBUG_INIT) {
CNPRINT(("[Clusnet] CnAdjustDeviceObjectStackSize: "
"unknown clusnet device object %p.\n",
ClusnetDeviceObject
));
}
return;
}
KeAcquireSpinLock(&CnDeviceObjectStackSizeLock, &irql);
if (ClusnetDeviceObject->StackSize <
TargetDeviceObject->StackSize + defaultStackSize) {
ClusnetDeviceObject->StackSize =
TargetDeviceObject->StackSize + defaultStackSize;
IF_CNDBG(CN_DEBUG_INIT) {
newStackSize = ClusnetDeviceObject->StackSize;
}
}
KeReleaseSpinLock(&CnDeviceObjectStackSizeLock, irql);
IF_CNDBG(CN_DEBUG_INIT) {
if (newStackSize != 0) {
CNPRINT(("[Clusnet] Set StackSize of clusnet device "
"object %p to %d "
"based on target device object %p.\n",
ClusnetDeviceObject,
newStackSize,
TargetDeviceObject
));
}
}
return;
} // CnAdjustDeviceObjectStackSize
#if DBG
//
// Debug code.
//
ULONG CnCpuLockMask[MAXIMUM_PROCESSORS];
VOID
CnAssertBreak(
PCHAR FailedStatement,
PCHAR FileName,
ULONG LineNumber
)
{
DbgPrint(
"[Clusnet] Assertion \"%s\" failed in %s line %u\n",
FailedStatement,
FileName,
LineNumber
);
DbgBreakPoint();
return;
} // CnAssertBreak
ULONG
CnGetCpuLockMask(
VOID
)
{
ULONG mask;
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
CnAssert(CnCpuLockMask[KeGetCurrentProcessorNumber()] == 0);
mask = 0;
}
else {
mask = CnCpuLockMask[KeGetCurrentProcessorNumber()];
}
return(mask);
}
VOID
CnVerifyCpuLockMask(
IN ULONG RequiredLockMask,
IN ULONG ForbiddenLockMask,
IN ULONG MaximumLockMask
)
{
ULONG mask;
if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
mask = 0;
}
else {
mask = CnCpuLockMask[KeGetCurrentProcessorNumber()];
}
if ((mask & RequiredLockMask) != RequiredLockMask) {
CNPRINT((
"[Clusnet] Locking bug: Req'd lock mask %lx, actual mask %lx\n",
RequiredLockMask,
mask
));
DbgBreakPoint();
}
if (mask & ForbiddenLockMask) {
CNPRINT((
"[Clusnet] Locking bug: Forbidden mask %lx, actual mask %lx\n",
ForbiddenLockMask,
mask
));
DbgBreakPoint();
}
if (mask > MaximumLockMask) {
CNPRINT((
"[Clusnet] Locking bug: Max lock mask %lx, actual mask %lx\n",
MaximumLockMask,
mask
));
DbgBreakPoint();
}
return;
}
VOID
CnInitializeLock(
PCN_LOCK Lock,
ULONG Rank
)
{
KeInitializeSpinLock(&(Lock->SpinLock));
Lock->Rank = Rank;
return;
}
VOID
CnAcquireLock(
IN PCN_LOCK Lock,
OUT PCN_IRQL Irql
)
{
KIRQL irql;
ULONG currentCpu;
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
KeRaiseIrql(DISPATCH_LEVEL, &irql);
}
else {
irql = DISPATCH_LEVEL;
}
currentCpu = KeGetCurrentProcessorNumber();
if (CnCpuLockMask[currentCpu] >= Lock->Rank) {
CNPRINT((
"[Clusnet] CPU %u trying to acquire lock %lx out of order, mask %lx\n",
currentCpu,
Lock->Rank,
CnCpuLockMask[currentCpu]
));
DbgBreakPoint();
}
KeAcquireSpinLockAtDpcLevel(&(Lock->SpinLock));
*Irql = irql;
CnCpuLockMask[currentCpu] |= Lock->Rank;
return;
}
VOID
CnAcquireLockAtDpc(
IN PCN_LOCK Lock
)
{
ULONG currentCpu = KeGetCurrentProcessorNumber();
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
CNPRINT((
"[Clusnet] CPU %u trying to acquire DPC lock at passive level.\n",
currentCpu
));
DbgBreakPoint();
}
if (CnCpuLockMask[currentCpu] >= Lock->Rank) {
CNPRINT((
"[Clusnet] CPU %u trying to acquire lock %lx out of order, mask %lx\n",
currentCpu,
Lock->Rank,
CnCpuLockMask[currentCpu]
));
DbgBreakPoint();
}
KeAcquireSpinLockAtDpcLevel(&(Lock->SpinLock));
CnCpuLockMask[currentCpu] |= Lock->Rank;
return;
}
VOID
CnReleaseLock(
IN PCN_LOCK Lock,
IN CN_IRQL Irql
)
{
ULONG currentCpu = KeGetCurrentProcessorNumber();
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
CNPRINT((
"[Clusnet] CPU %u trying to release lock from passive level.\n",
currentCpu
));
DbgBreakPoint();
}
if ( !(CnCpuLockMask[currentCpu] & Lock->Rank) ) {
CNPRINT((
"[Clusnet] CPU %u trying to release lock %lx, which it doesn't hold, mask %lx\n",
currentCpu,
Lock->Rank,
CnCpuLockMask[currentCpu]
));
DbgBreakPoint();
}
CnCpuLockMask[currentCpu] &= ~(Lock->Rank);
KeReleaseSpinLock(&(Lock->SpinLock), Irql);
return;
}
VOID
CnReleaseLockFromDpc(
IN PCN_LOCK Lock
)
{
ULONG currentCpu = KeGetCurrentProcessorNumber();
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
CNPRINT((
"[Clusnet] CPU %u trying to release lock from passive level.\n",
currentCpu
));
DbgBreakPoint();
}
if ( !(CnCpuLockMask[currentCpu] & Lock->Rank) ) {
CNPRINT((
"[Clusnet] CPU %u trying to release lock %lx, which it doesn't hold, mask %lx\n",
currentCpu,
Lock->Rank,
CnCpuLockMask[currentCpu]
));
DbgBreakPoint();
}
CnCpuLockMask[currentCpu] &= ~(Lock->Rank);
KeReleaseSpinLockFromDpcLevel(&(Lock->SpinLock));
return;
}
VOID
CnMarkIoCancelLockAcquired(
VOID
)
{
ULONG currentCpu = KeGetCurrentProcessorNumber();
CnAssert(KeGetCurrentIrql() == DISPATCH_LEVEL);
CnAssert(!(CnCpuLockMask[currentCpu] & CN_IOCANCEL_LOCK));
CnAssert(CnCpuLockMask[currentCpu] < CN_IOCANCEL_LOCK_MAX);
CnCpuLockMask[currentCpu] |= CN_IOCANCEL_LOCK;
return;
}
VOID
CnAcquireCancelSpinLock(
OUT PCN_IRQL Irql
)
{
KIRQL irql;
KIRQL tempIrql;
ULONG currentCpu;
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
KeRaiseIrql(DISPATCH_LEVEL, &irql);
}
else {
irql = DISPATCH_LEVEL;
}
currentCpu = KeGetCurrentProcessorNumber();
if (CnCpuLockMask[currentCpu] >= CN_IOCANCEL_LOCK) {
CNPRINT((
"[Clusnet] CPU %u trying to acquire IoCancel lock out of order, mask %lx\n",
currentCpu,
CnCpuLockMask[currentCpu]
));
DbgBreakPoint();
}
IoAcquireCancelSpinLock(&tempIrql);
CnAssert(tempIrql == DISPATCH_LEVEL);
*Irql = irql;
CnCpuLockMask[currentCpu] |= CN_IOCANCEL_LOCK;
return;
}
VOID
CnReleaseCancelSpinLock(
IN CN_IRQL Irql
)
{
ULONG currentCpu = KeGetCurrentProcessorNumber();
if (KeGetCurrentIrql() != DISPATCH_LEVEL) {
CNPRINT((
"[Clusnet] CPU %u trying to release lock from passive level.\n",
currentCpu
));
DbgBreakPoint();
}
if ( !(CnCpuLockMask[currentCpu] & CN_IOCANCEL_LOCK) ) {
CNPRINT((
"[Clusnet] CPU %u trying to release IoCancel lock, which it doesn't hold, mask %lx\n",
currentCpu,
CnCpuLockMask[currentCpu]
));
DbgBreakPoint();
}
CnCpuLockMask[currentCpu] &= ~(CN_IOCANCEL_LOCK);
IoReleaseCancelSpinLock(Irql);
return;
}
#endif // DEBUG