Leaked source code of windows server 2003
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

/*++
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 );
}