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.
359 lines
9.4 KiB
359 lines
9.4 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rmnotify.c
|
|
|
|
Abstract:
|
|
|
|
Interfaces with the resource monitor to detect notification
|
|
of resource state changes.
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 12-Jan-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "fmp.h"
|
|
|
|
#define LOG_MODULE RMNOTIFY
|
|
|
|
//
|
|
// Local Data
|
|
//
|
|
|
|
CL_QUEUE NotifyQueue;
|
|
|
|
HANDLE RmNotifyThread;
|
|
|
|
|
|
|
|
//
|
|
// Local Functions
|
|
//
|
|
DWORD
|
|
FmpRmWorkerThread(
|
|
IN LPVOID lpThreadParameter
|
|
);
|
|
|
|
VOID
|
|
FmpRmWorkItemHandler(
|
|
IN PCLRTL_WORK_ITEM WorkItem,
|
|
IN DWORD Ignored1,
|
|
IN DWORD Ignored2,
|
|
IN ULONG_PTR Ignored3
|
|
);
|
|
|
|
DWORD
|
|
FmpInitializeNotify(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialization routine for notification engine
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD ThreadId;
|
|
DWORD Status;
|
|
|
|
Status = ClRtlInitializeQueue(&NotifyQueue);
|
|
if (Status != ERROR_SUCCESS) {
|
|
CL_LOGFAILURE(Status);
|
|
return(Status);
|
|
}
|
|
|
|
RmNotifyThread = CreateThread(NULL,
|
|
0,
|
|
FmpRmWorkerThread,
|
|
NULL,
|
|
0,
|
|
&ThreadId);
|
|
if (RmNotifyThread == NULL) {
|
|
CsInconsistencyHalt(GetLastError());
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
DWORD
|
|
FmpRmWorkerThread(
|
|
IN LPVOID lpThreadParameter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This thread processes deferred Resource Monitor events.
|
|
|
|
Arguments:
|
|
|
|
lpThreadParameter - not used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
PRM_EVENT event;
|
|
PLIST_ENTRY entry;
|
|
|
|
while (TRUE)
|
|
{
|
|
entry = ClRtlRemoveHeadQueue(&NotifyQueue);
|
|
if ( entry == NULL ) {
|
|
break;
|
|
}
|
|
|
|
event = CONTAINING_RECORD(entry,
|
|
RM_EVENT,
|
|
Linkage);
|
|
|
|
if (event->EventType == RmWorkerTerminate)
|
|
{
|
|
LocalFree(event);
|
|
break;
|
|
}
|
|
|
|
status = FmpRmDoHandleCriticalResourceStateChange( event,
|
|
NULL,
|
|
event->Parameters.ResourceTransition.NewState);
|
|
|
|
LocalFree(event);
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
BOOL
|
|
FmpPostNotification(
|
|
IN RM_NOTIFY_KEY NotifyKey,
|
|
IN DWORD NotifyEvent,
|
|
IN CLUSTER_RESOURCE_STATE CurrentState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine used by resource monitor for resource state
|
|
change notification. This routine queues the notification to
|
|
a worker thread for deferred processing.
|
|
|
|
Arguments:
|
|
|
|
NotifyKey - Supplies the notification key for the resource
|
|
that changed
|
|
|
|
NotifyEvent - The event type.
|
|
|
|
CurrentState - Supplies the (new) current state of the resource
|
|
|
|
Return Value:
|
|
|
|
TRUE - continue receiving notifications
|
|
|
|
FALSE - abort notifications
|
|
|
|
--*/
|
|
|
|
{
|
|
PRM_EVENT event;
|
|
|
|
|
|
event = LocalAlloc(LMEM_FIXED, sizeof(RM_EVENT));
|
|
|
|
if (event != NULL) {
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[FM] NotifyCallBackRoutine: enqueuing event\n");
|
|
|
|
event->EventType = NotifyEvent;
|
|
event->Parameters.ResourceTransition.NotifyKey = NotifyKey;
|
|
event->Parameters.ResourceTransition.NewState = CurrentState;
|
|
|
|
//
|
|
// Enqueue the event for the worker thread.
|
|
//
|
|
ClRtlInsertTailQueue(&NotifyQueue, &event->Linkage);
|
|
} else {
|
|
ClRtlLogPrint(LOG_UNUSUAL, "[FM] NotifyCallBackRoutine: Unable to post item, memory alloc failure %1!u!\n",
|
|
GetLastError());
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
DWORD
|
|
FmpRmDoHandleCriticalResourceStateChange(
|
|
IN PRM_EVENT pEvent,
|
|
IN OPTIONAL PFM_RESOURCE pTransitionedResource,
|
|
IN CLUSTER_RESOURCE_STATE NewState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does an interlocked decrement of the gdwQuoBlockingResources variable.
|
|
Handle the transition of the quorum resource state via a separate
|
|
thread.
|
|
|
|
Arguments:
|
|
|
|
pEvent - The Resource Monitor Event
|
|
|
|
pTransitionedResource - The resource whose state has changed.
|
|
|
|
NewState - New state of the resource.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS on success, a Win32 error code otherwise.
|
|
|
|
Comments:
|
|
|
|
DO NOT hold any locks (such as group lock, gQuoChangeLock, etc.)
|
|
in this function. You could deadlock the system quite easily.
|
|
|
|
--*/
|
|
|
|
{
|
|
RM_NOTIFY_KEY NotifyKey;
|
|
DWORD dwOldBlockingFlag;
|
|
PFM_RESOURCE pResource = pTransitionedResource;
|
|
DWORD status = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 4/19/99
|
|
//
|
|
// This function decrements the blocking resources count when the
|
|
// resource state has stabilized. It is important to do this
|
|
// decrement in a non-blocking mode so that the quorum resource
|
|
// does not get caught forever waiting for this count to go down to
|
|
// zero in the offline call, FmpRmOfflineResource. This code was
|
|
// originally located in FmpHandleResourceTransition and was moved
|
|
// here since you could run out of FmpRmWorkItemHandler threads
|
|
// (which service the CsDelayedWorkQueue) since all of them could
|
|
// get blocked on the local resource lock in
|
|
// FmpHandleResourceTransition and consequently any new notifications
|
|
// from resmon which could potentially decrement this count will
|
|
// not get serviced.
|
|
//
|
|
if ( !ARGUMENT_PRESENT ( pTransitionedResource ) )
|
|
{
|
|
//SS: have no idea what this was for, but only do this check if pEvent is passed in
|
|
if (pEvent)
|
|
{
|
|
NotifyKey = pEvent->Parameters.ResourceResuscitate.NotifyKey;
|
|
|
|
pResource = FmpFindResourceByNotifyKey(
|
|
NotifyKey
|
|
);
|
|
|
|
if ( pResource == NULL ) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[FM] FmpRmDoHandleCriticalResourceStateChange, bad resource NotifyKey %1!u!\n",
|
|
NotifyKey);
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( pEvent->EventType != ResourceTransition )
|
|
{
|
|
goto FnExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pResource->QuorumResource )
|
|
{
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 6/25/99
|
|
//
|
|
// If this resource is the quorum resource, then let
|
|
// FmpHandleResourceTransition take care of the sync notifications.
|
|
// Note that this function only does the notifications for the
|
|
// non-quorum resources as well as does the decrement on the
|
|
// blocking resources count. The decrement MUST be done
|
|
// without holding any locks to avoid potential deadlocks with
|
|
// the quorum resource offline getting stuck in FmpRmOfflineResource
|
|
// waiting for the blocking resources count to go to 0.
|
|
// As far as the quorum resource goes, the sync notifications
|
|
// must be done with gQuoChangeLock held since we want to
|
|
// synchronize with other threads such as the FmCheckQuorumState
|
|
// called by the DM node down handler. FmpHandleResourceTransition
|
|
// does hold the gQuoChangeLock.
|
|
//
|
|
// Note also that for the quorum resource a separate thread
|
|
// handles the resource transition since if we depend on the
|
|
// worker threads servicing the CsDelayedWorkQueue to do this,
|
|
// this notification could be starved from being processed since
|
|
// some thread could hold the group lock and be stuck in the
|
|
// resource onlining waiting for the quorum resource to go
|
|
// online and all the worker threads servicing the CsDelayedWorkQueue
|
|
// could be blocked on the group lock preventing the propagation
|
|
// of the quorum resource state.
|
|
//
|
|
FmpCreateResStateChangeHandler( pResource, NewState, pResource->State );
|
|
|
|
|
|
goto FnExit;
|
|
}
|
|
|
|
|
|
//
|
|
// Comments from sunitas: Call the synchronous notifications.
|
|
// This is done before the count is decremented as the synchronous
|
|
// callbacks like the registry replication must get a chance to
|
|
// finish before the quorum resource state is allowed to change.
|
|
//
|
|
// Note, there is no synchronization here with the resmon's
|
|
// online/offline code. They are using the LocalResourceLocks.
|
|
//
|
|
FmpCallResourceNotifyCb( pResource, NewState );
|
|
|
|
dwOldBlockingFlag = InterlockedExchange( &pResource->BlockingQuorum, 0 );
|
|
|
|
if ( dwOldBlockingFlag ) {
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[FM] FmpRmDoHandleCriticalResourceStateChange: call InterlockedDecrement on gdwQuoBlockingResources, Resource %1!ws!\n",
|
|
OmObjectId(pResource));
|
|
InterlockedDecrement( &gdwQuoBlockingResources );
|
|
}
|
|
|
|
//post a work item to the fm worker thread to handle the rest
|
|
OmReferenceObject(pResource);
|
|
FmpPostWorkItem(FM_EVENT_RES_RESOURCE_TRANSITION,
|
|
pResource,
|
|
NewState);
|
|
|
|
|
|
FnExit:
|
|
return( status );
|
|
}
|