|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
fmgum.c
Abstract:
Cluster FM Global Update processing routines.
Author:
Rod Gamache (rodga) 24-Apr-1996
Revision History:
--*/
#include "fmp.h"
#include "ntrtl.h"
#if NO_SHARED_LOCKS
extern CRITICAL_SECTION gLockDmpRoot; #else
extern RTL_RESOURCE gLockDmpRoot; #endif
#define LOG_MODULE FMGUM
DWORD WINAPI FmpGumReceiveUpdates( IN DWORD Context, IN BOOL SourceNode, IN DWORD BufferLength, IN PVOID Buffer )
/*++
Routine Description:
Updates the specified resource (contained within Buffer) with a new state.
Arguments:
Context - The message update type. SourceNode - TRUE if this is the source node for this update. FALSE otherwise. BufferLength - Length of the received buffer. Buffer - The actual buffer
Returns:
ERROR_SUCCESS
--*/
{ PFM_RESOURCE resource;
//
// Chittur Subbaraman (chitturs) - 4/18/99
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
switch ( Context ) {
case FmUpdateFailureCount: { PGUM_FAILURE_COUNT failureCount; PFM_GROUP group;
//
// This update type is always sent.
// On the originating node, all of the work must be done by
// the sending thread.
// On the non-originating nodes, no locks can be acquired! This
// would cause hang situations with operations like move.
// ... this is okay, since the locking must be done on the sending
// node anyway, which owns the group.
//
if ( SourceNode == FALSE ) { if ( BufferLength <= sizeof(GUM_FAILURE_COUNT) ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] Gum FailureCount receive buffer too small!\n"); return(ERROR_SUCCESS); }
failureCount = (PGUM_FAILURE_COUNT)Buffer; group = OmReferenceObjectById( ObjectTypeGroup, (LPCWSTR)&failureCount->GroupId[0] );
if ( group == NULL ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] Gum FailureCount failed to find group %1!ws!\n", failureCount->GroupId); return(ERROR_SUCCESS); }
ClRtlLogPrint(LOG_NOISE, "[FM] GUM update failure count %1!ws!, count %2!u!\n", failureCount->GroupId, failureCount->Count);
//FmpAcquireLocalGroupLock( group );
if ( group->OwnerNode == NmLocalNode ) { ClRtlLogPrint(LOG_NOISE, "[FM] Gum FailureCount wrong owner for %1!ws!\n", failureCount->GroupId); } else { group->NumberOfFailures = failureCount->Count; if ( failureCount->NewTime ) { group->FailureTime = GetTickCount(); } }
//FmpReleaseLocalGroupLock( group );
OmDereferenceObject( group );
}
break; }
case FmUpdateCreateGroup: { PGUM_CREATE_GROUP GumGroup; DWORD Status = ERROR_SUCCESS;
GumGroup = (PGUM_CREATE_GROUP)Buffer;
Status = FmpUpdateCreateGroup( GumGroup, SourceNode ); return(Status); }
case FmUpdateCreateResource: { DWORD dwStatus = ERROR_SUCCESS; PGUM_CREATE_RESOURCE GumResource = (PGUM_CREATE_RESOURCE)Buffer;
dwStatus = FmpUpdateCreateResource( GumResource );
return( dwStatus ); }
case FmUpdateAddPossibleNode: case FmUpdateRemovePossibleNode: {
PGUM_CHANGE_POSSIBLE_NODE pGumChange; PFM_RESOURCE pResource; LPWSTR pszResourceId; LPWSTR pszNodeId; PNM_NODE pNode; DWORD dwStatus; DWORD dwControlCode; PFMP_POSSIBLE_NODE pPossibleNode;
pGumChange = (PGUM_CHANGE_POSSIBLE_NODE)Buffer; pszResourceId = pGumChange->ResourceId; pszNodeId = (LPWSTR)((PCHAR)pszResourceId + pGumChange->ResourceIdLen); pResource = OmReferenceObjectById(ObjectTypeResource,pszResourceId); pNode = OmReferenceObjectById(ObjectTypeNode, pszNodeId); CL_ASSERT(pResource != NULL); CL_ASSERT(pNode != NULL); pPossibleNode = LocalAlloc( LMEM_FIXED, sizeof(FMP_POSSIBLE_NODE) ); if ( pPossibleNode == NULL ) { return(ERROR_NOT_ENOUGH_MEMORY); } if (Context == FmUpdateAddPossibleNode) { dwControlCode = CLUSCTL_RESOURCE_ADD_OWNER; } else { dwControlCode = CLUSCTL_RESOURCE_REMOVE_OWNER; } dwStatus = FmpUpdateChangeResourceNode(SourceNode, pResource, pNode, dwControlCode); //if status is not successful then return, else notify
//resource dlls
if (dwStatus != ERROR_SUCCESS) { //dereference the objects
OmDereferenceObject(pResource); OmDereferenceObject(pNode); //free the memory
LocalFree(pPossibleNode); return(dwStatus); }
pPossibleNode->Resource = pResource; pPossibleNode->Node = pNode; pPossibleNode->ControlCode = dwControlCode;
//
// Tell the resource about the ADD/REMOVE in a worker thread.
//
FmpPostWorkItem( FM_EVENT_RESOURCE_CHANGE, pPossibleNode, 0 );
//
// Chittur Subbaraman (chitturs) - 6/7/99
//
// Don't reference pPossibleNode any more. It could have
// been freed by the worker thread by the time you get
// here.
//
ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, pResource );
// Let the worker thread perform the derefs/Frees
return(dwStatus); }
case FmUpdateJoin: break;
case FmUpdateCreateResourceType: { DWORD dwStatus;
dwStatus = FmpUpdateCreateResourceType( Buffer );
return( dwStatus ); } break; case FmUpdateDeleteResourceType: { BOOL ResourceExists = FALSE; PFM_RESTYPE Type;
Type = OmReferenceObjectById( ObjectTypeResType, (LPWSTR)Buffer); if (Type == NULL) { return(ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND); } //
// Make sure no resources exist of this type.
//
OmEnumObjects( ObjectTypeResource, FmpFindResourceType, Type, &ResourceExists); if (ResourceExists) { OmDereferenceObject(Type); return(ERROR_DIR_NOT_EMPTY); }
//
// We need to dereference the object twice to get
// rid of it. But then any notification handlers will
// not get a chance to see the object by the time
// the handler gets called. So we use the EP_DEREF_CONTEXT
// flag to get the event processor to do the second deref
// once everything has been dispatched.
//
FmpDeleteResType(Type); ClusterEventEx( CLUSTER_EVENT_RESTYPE_DELETED, EP_DEREF_CONTEXT, Type ); } break;
case FmUpdateChangeGroup: { PGUM_CHANGE_GROUP pGumChange; PFM_RESOURCE pResource; LPWSTR pszResourceId; LPWSTR pszGroupId; PFM_GROUP pNewGroup; DWORD dwStatus; DWORD dwClusterHighestVersion; pGumChange = (PGUM_CHANGE_GROUP)Buffer;
pszResourceId = pGumChange->ResourceId; pszGroupId = (LPWSTR)((PCHAR)pszResourceId + pGumChange->ResourceIdLen); //
// Find the specified resource and group.
//
pResource = OmReferenceObjectById(ObjectTypeResource, pszResourceId); if (pResource == NULL) { return(ERROR_RESOURCE_NOT_FOUND); } pNewGroup = OmReferenceObjectById(ObjectTypeGroup, pszGroupId); if (pNewGroup == NULL) { OmDereferenceObject(pResource); return(ERROR_SUCCESS); }
dwStatus = FmpUpdateChangeResourceGroup(SourceNode, pResource, pNewGroup);
OmDereferenceObject(pNewGroup); OmDereferenceObject(pResource);
return(dwStatus); } break;
default: {
} ClRtlLogPrint(LOG_UNUSUAL,"[FM] Gum received bad context, %1!u!\n", Context);
}
return(ERROR_SUCCESS);
} // FmpGumReceiveUpdates
DWORD FmpUpdateChangeQuorumResource( IN BOOL SourceNode, IN LPCWSTR NewQuorumResourceId, IN LPCWSTR szRootClusFilePath, IN LPDWORD pdwMaxQuorumLogSize )
/*++
Routine Description:
Perform updates related to changing of the quorum resource.
Arguments:
Return Value:
ERROR_SUCCESS if successful.
A Win32 error code otherwise.
--*/
{ PFM_RESOURCE pResource; PFM_RESOURCE pOldQuoResource=NULL; DWORD dwStatus; WCHAR lpszCheckPtFile[MAX_PATH]; DWORD dwChkPtSeq; HDMKEY ResKey; HLOCALXSACTION hXsaction = NULL; HLOG hNewQuoLog=NULL; WCHAR szQuorumLogPath[MAX_PATH];
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
lstrcpyW(szQuorumLogPath, szRootClusFilePath); //lstrcatW(szQuorumLogPath, cszClusLogFileRootDir);
pResource = OmReferenceObjectById( ObjectTypeResource, NewQuorumResourceId ); if (pResource == NULL) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateChangeQuorumResource: Resource <%1!ws!> could not be found....\n", NewQuorumResourceId); return(ERROR_SUCCESS); }
//since the resource->quorum is going to change, acquire the quocritsec
//always acquire the gQuoCritsec before gQuoLock
ACQUIRE_EXCLUSIVE_LOCK(gQuoChangeLock); //prevent any resources from going online at this time
ACQUIRE_EXCLUSIVE_LOCK(gQuoLock);
//pause any changes to the cluster database
//always acquire this lock after gQuoLock(refer to the ordering of locks
// in fminit.c)
ACQUIRE_EXCLUSIVE_LOCK(gLockDmpRoot);
DmPauseDiskManTimer();
//if this resource was already a quorum resource
if (!pResource->QuorumResource) {
//
// Now find the current quorum resource.
//
OmEnumObjects( ObjectTypeResource, FmpFindQuorumResource, &pOldQuoResource, NULL ); if ( pOldQuoResource != NULL ) { CL_ASSERT( pOldQuoResource->QuorumResource ); // Stop the quorum reservation thread!
pOldQuoResource->QuorumResource = FALSE; } //set the new resource to be the quorum resource
pResource->QuorumResource = TRUE;
}
//writes to the old log file
hXsaction = DmBeginLocalUpdate();
if (!hXsaction) { dwStatus = GetLastError(); goto FnExit; } dwStatus = DmLocalSetValue( hXsaction, DmQuorumKey, cszPath, REG_SZ, (LPBYTE)szQuorumLogPath, (lstrlenW(szQuorumLogPath)+1) * sizeof(WCHAR));
if (dwStatus != ERROR_SUCCESS) goto FnExit;
#ifdef CLUSTER_TESTPOINT
TESTPT(TpFailLocalXsaction) { LPWSTR pszStr = szQuorumLogPath; dwStatus = (MAX_PATH * sizeof(WCHAR)); dwStatus = DmQuerySz( DmQuorumKey, cszPath, &pszStr, &dwStatus, &dwStatus); ClRtlLogPrint(LOG_UNUSUAL, "[FM] Testing failing a local transaction midway- new quorum path %1!ws!\r\n", szQuorumLogPath); dwStatus = 999999; goto FnExit; } #endif
dwStatus = DmLocalSetValue( hXsaction, DmQuorumKey, cszMaxQuorumLogSize, REG_DWORD, (LPBYTE)pdwMaxQuorumLogSize, sizeof(DWORD));
if (dwStatus != ERROR_SUCCESS) goto FnExit;
//if the old quorum resource is different from the new quorum resource
if ((pOldQuoResource) && (pOldQuoResource != pResource)) { //get/set the new/old resource's flags
//set the core flag on the new quorum resource
ResKey = DmOpenKey( DmResourcesKey, NewQuorumResourceId, KEY_READ | KEY_SET_VALUE); if (!ResKey) { dwStatus = GetLastError(); goto FnExit; } pResource->ExFlags |= CLUS_FLAG_CORE; dwStatus = DmLocalSetValue( hXsaction, ResKey, CLUSREG_NAME_FLAGS, REG_DWORD, (LPBYTE)&(pResource->ExFlags), sizeof(DWORD));
DmCloseKey( ResKey );
if (dwStatus != ERROR_SUCCESS) goto FnExit;
//unset the core flag on the old quorum resource
ResKey = DmOpenKey( DmResourcesKey, OmObjectId(pOldQuoResource), KEY_READ | KEY_SET_VALUE); if (!ResKey) { dwStatus = GetLastError(); goto FnExit; } pOldQuoResource->ExFlags &= ~CLUS_FLAG_CORE;
//unset the core flag on the old quorum resource
dwStatus = DmLocalSetValue( hXsaction, ResKey, CLUSREG_NAME_FLAGS, REG_DWORD, (LPBYTE)&(pOldQuoResource->ExFlags), sizeof(DWORD));
DmCloseKey( ResKey );
if (dwStatus != ERROR_SUCCESS) goto FnExit;
} //
// Set the quorum resource value.
//
dwStatus = DmLocalSetValue( hXsaction, DmQuorumKey, CLUSREG_NAME_QUORUM_RESOURCE, REG_SZ, (CONST BYTE *)OmObjectId(pResource), (lstrlenW(OmObjectId(pResource))+1)*sizeof(WCHAR));
if (dwStatus != ERROR_SUCCESS) { goto FnExit; }
FnExit: if (dwStatus == ERROR_SUCCESS) { LPWSTR szClusterName=NULL; DWORD dwSize=0; //commit the update on the old log file,
//any nodes that were done, will get this change
//I cant delete this file
DmCommitLocalUpdate(hXsaction); //close the old log file, open the new one and take a checkpoint
DmSwitchToNewQuorumLog(szQuorumLogPath); // SS:the buffer should contain the current cluster name ?
DmQuerySz( DmClusterParametersKey, CLUSREG_NAME_CLUS_NAME, &szClusterName, &dwSize, &dwSize);
if (szClusterName) ClusterEventEx(CLUSTER_EVENT_PROPERTY_CHANGE, EP_FREE_CONTEXT, szClusterName); if ((pOldQuoResource) && (pOldQuoResource != pResource)) { //generate the resource property change events
ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, pResource ); ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, pOldQuoResource ); }
} else { if (hXsaction) DmAbortLocalUpdate(hXsaction); //reinstall the tombstone
DmReinstallTombStone(szQuorumLogPath); } if (pOldQuoResource) OmDereferenceObject(pOldQuoResource); OmDereferenceObject(pResource); DmRestartDiskManTimer(); //release locks
RELEASE_LOCK(gLockDmpRoot); RELEASE_LOCK(gQuoLock); RELEASE_LOCK(gQuoChangeLock); return(dwStatus); }
DWORD FmpUpdateResourceState( IN BOOL SourceNode, IN LPCWSTR ResourceId, IN PGUM_RESOURCE_STATE ResourceState ) /*++
Routine Description:
GUM update handler for resource state changes.
Arguments:
SourceNode - Supplies whether or not this node was the source of the update
ResourceId - Supplies the id of the resource whose state is changing
ResourceState - Supplies the new state of the resource.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PFM_RESOURCE resource;
if ( !FmpFMGroupsInited ) { return(ERROR_SUCCESS); }
//
// This update type is always sent.
// On the originating node, all of the work must be done by
// the sending thread.
// On the non-originating nodes, no locks can be acquired! This
// would cause some hang situations with operations like move.
// ... this is okay, since the locking must be done on the sending
// node anyway, which owns the group.
//
if ( SourceNode == FALSE ) { resource = OmReferenceObjectById( ObjectTypeResource, ResourceId );
if ( resource == NULL ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] Gum ResourceState failed to find resource %1!ws!\n", ResourceId); CL_LOGFAILURE( ERROR_RESOURCE_NOT_FOUND ); return(ERROR_SUCCESS); }
ClRtlLogPrint(LOG_NOISE, "[FM] Gum update resource %1!ws!, state %2!u!, current state %3!u!.\n", ResourceId, ResourceState->State, ResourceState->PersistentState);
//FmpAcquireLocalResourceLock( resource );
if ( resource->Group->OwnerNode == NmLocalNode ) { ClRtlLogPrint(LOG_NOISE, "[FM] Gum ResourceState wrong owner for %1!ws!\n", ResourceId); } else { resource->State = ResourceState->State; resource->PersistentState = ResourceState->PersistentState; resource->StateSequence = ResourceState->StateSequence;
switch ( ResourceState->State ) { case ClusterResourceOnline: ClusterEvent( CLUSTER_EVENT_RESOURCE_ONLINE, resource ); break; case ClusterResourceOffline: ClusterEvent( CLUSTER_EVENT_RESOURCE_OFFLINE, resource ); break; case ClusterResourceFailed: ClusterEvent( CLUSTER_EVENT_RESOURCE_FAILED, resource ); break; case ClusterResourceOnlinePending: case ClusterResourceOfflinePending: ClusterEvent( CLUSTER_EVENT_RESOURCE_CHANGE, resource ); break; default: ClRtlLogPrint(LOG_UNUSUAL, "[FM] Gum update resource state, bad state %1!u!\n", ResourceState->State); break; } }
OmDereferenceObject( resource ); } return(ERROR_SUCCESS); }
DWORD FmpUpdateGroupState( IN BOOL SourceNode, IN LPCWSTR GroupId, IN LPCWSTR NodeId, IN PGUM_GROUP_STATE GroupState ) /*++
Routine Description:
GUM update handler for group state changes.
Arguments:
SourceNode - Supplies whether or not this node was the source of the update
GroupId - Supplies the id of the resource whose state is changing
NodeId - Supplies the node id of the group owner.
GroupState - Supplies the new state of the group.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PFM_GROUP group; PWSTR nodeId; PNM_NODE node;
if ( !FmpFMGroupsInited ) { return(ERROR_SUCCESS); }
//
// This update type is always sent.
// On the originating node, all of the work must be done by
// the sending thread.
// On the non-originating nodes, no locks can be acquired! This
// would cause some hang situations with operations like move.
// ... this is okay, since the locking must be done on the sending
// node anyway, which owns the group.
//
if ( SourceNode == FALSE ) { group = OmReferenceObjectById( ObjectTypeGroup, GroupId );
if ( group == NULL ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] Gum GroupState failed to find group %1!ws!\n", GroupId); return(ERROR_SUCCESS); }
ClRtlLogPrint(LOG_NOISE, "[FM] GUM update group %1!ws!, state %2!u!\n", GroupId, GroupState->State);
if ( group->OwnerNode == NmLocalNode ) { ClRtlLogPrint(LOG_NOISE, "[FM] Gum GroupState wrong owner for %1!ws!\n", GroupId); } else { group->State = GroupState->State; group->PersistentState = GroupState->PersistentState; group->StateSequence = GroupState->StateSequence; node = OmReferenceObjectById( ObjectTypeNode, NodeId ); if ( node == NULL ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] Owner of Group %1!ws! cannot be found %2!ws!\n", GroupId, NodeId); } else { ClRtlLogPrint(LOG_NOISE, "[FM] New owner of Group %1!ws! is %2!ws!, state %3!u!, curstate %4!u!.\n", OmObjectId( group ), OmObjectId( node ), group->State, group->PersistentState); if ( !FmpInPreferredList( group, node, FALSE, NULL ) ) { ClRtlLogPrint( LOG_UNUSUAL, "[FM] New owner %1!ws! is not in preferred list for group %2!ws!.\n", OmObjectId( node ), OmObjectId( group )); } } group->OwnerNode = node;
switch ( GroupState->State ) { case ClusterGroupOnline: case ClusterGroupPartialOnline: ClusterEvent( CLUSTER_EVENT_GROUP_ONLINE, group ); break; case ClusterGroupOffline: ClusterEvent( CLUSTER_EVENT_GROUP_OFFLINE, group ); break; default: ClRtlLogPrint(LOG_UNUSUAL,"[FM] Gum update group state, bad state %1!u!\n", GroupState->State); break; } }
OmDereferenceObject( group );
}
return(ERROR_SUCCESS); }
DWORD FmpUpdateGroupNode( IN BOOL SourceNode, IN LPCWSTR GroupId, IN LPCWSTR NodeId ) /*++
Routine Description:
GUM update handler for group node changes. This is required for notification when a group moves between nodes but does not change state (i.e. it was already offline)
Arguments:
SourceNode - Supplies whether or not this node was the source of the update
GroupId - Supplies the id of the resource whose state is changing
NodeId - Supplies the node id of the group owner.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PFM_GROUP pGroup; DWORD dwStatus = ERROR_SUCCESS; PNM_NODE pNode = NULL; PNM_NODE pPrevNode = NULL; if ( !FmpFMGroupsInited ) { return(ERROR_SUCCESS); }
pGroup = OmReferenceObjectById( ObjectTypeGroup, GroupId );
if (pGroup == NULL) { ClRtlLogPrint(LOG_ERROR, "[FM] FmpUpdateGroupNode: GroupID = %1!ws! could not be found...\n", GroupId); //
// Chittur Subbaraman (chitturs) - 6/12/99
//
// Return ERROR_SUCCESS here since this is what NT4 side does.
// Compatibility pain !
//
goto FnExit; }
pNode = OmReferenceObjectById(ObjectTypeNode, NodeId);
if (pNode == NULL) { dwStatus = ERROR_CLUSTER_NODE_NOT_FOUND; goto FnExit; } //
// HACKHACK: Chittur Subbaraman (chitturs) - 5/20/99
// Comment out as a temporary solution to avoid deadlocks.
//
// FmpAcquireLocalGroupLock(pGroup);
pPrevNode = pGroup->OwnerNode;
//set the new owner node, incr ref count
OmReferenceObject(pNode); pGroup->OwnerNode = pNode;
//decr ref count on previous owner
OmDereferenceObject(pPrevNode); //
// HACKHACK: Chittur Subbaraman (chitturs) - 5/20/99
// Comment out as a temporary solution to avoid deadlocks.
//
// FmpReleaseLocalGroupLock(pGroup);
//generate an event to signify group owner node change
ClusterEvent(CLUSTER_EVENT_GROUP_CHANGE, pGroup); FnExit: if (pGroup) OmDereferenceObject(pGroup); if (pNode) OmDereferenceObject(pNode); return(dwStatus); }
DWORD FmpUpdateChangeClusterName( IN BOOL SourceNode, IN LPCWSTR szNewName ) /*++
Routine Description:
GUM update routine for changing the name of the cluster.
This changes the name property of the core network name resource as well. The resource is notified about it by a worker thread that the name has been changed.
Arguments:
SourceNode - Supplies whether or not this node originated the update.
NewName - Supplies the new name of the cluster.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ LPWSTR Buffer; DWORD Length; DWORD Status = ERROR_SUCCESS; LPWSTR ClusterNameId=NULL; DWORD idMaxSize = 0; DWORD idSize = 0; PFM_RESOURCE Resource=NULL; HDMKEY ResKey = NULL; HDMKEY ParamKey = NULL; HLOCALXSACTION hXsaction=NULL;
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
hXsaction = DmBeginLocalUpdate();
if (!hXsaction) { Status = ERROR_SUCCESS; goto FnExit;
} //find the core network name resource, set its private properties
Status = DmQuerySz( DmClusterParametersKey, CLUSREG_NAME_CLUS_CLUSTER_NAME_RES, (LPWSTR*)&ClusterNameId, &idMaxSize, &idSize); if (Status != ERROR_SUCCESS) { ClRtlLogPrint(LOG_ERROR, "[FM] FmpUpdateChangeClusterName failed to get cluster name resource, error %1!u!.\n", Status); goto FnExit; }
//
// Reference the specified resource ID.
//
Resource = OmReferenceObjectById( ObjectTypeResource, ClusterNameId ); if (Resource == NULL) { ClRtlLogPrint(LOG_ERROR, "[FM] FmpUpdateChangeClusterName failed to find the cluster name resource\n", Status); goto FnExit; }
ResKey = DmOpenKey(DmResourcesKey, ClusterNameId, KEY_READ | KEY_SET_VALUE); if (!ResKey) { Status = GetLastError(); goto FnExit; } ParamKey = DmOpenKey(ResKey, cszParameters, KEY_READ | KEY_SET_VALUE);
if (!ParamKey) { Status = GetLastError(); goto FnExit; }
Status = DmLocalSetValue(hXsaction, ParamKey, CLUSREG_NAME_RES_NAME, REG_SZ, (CONST BYTE *)szNewName, (lstrlenW(szNewName)+1)*sizeof(WCHAR));
if ( Status != ERROR_SUCCESS ) goto FnExit;
//update the default cluster name
Status = DmLocalSetValue(hXsaction, DmClusterParametersKey, CLUSREG_NAME_CLUS_NAME, REG_SZ, (CONST BYTE *)szNewName, (lstrlenW(szNewName)+1)*sizeof(WCHAR));
if (Status != ERROR_SUCCESS) goto FnExit;
//notify the resource dll that the name has been changed
//that will decrement the reference count on this object
//current fm only has pending work associated with
//this event on the name change case. If other cases require
//pending work, then CLUSTER_EVENT_PROPERTY_CONTEXT must
//be used
FmpPostWorkItem(FM_EVENT_CLUSTER_PROPERTY_CHANGE, Resource, 0); Resource = NULL; //
// Need to allocate a new buffer for posting the new name to the event
// processor
//
Length = (lstrlenW(szNewName)+1)*sizeof(WCHAR); Buffer = LocalAlloc(LMEM_FIXED,Length); if (Buffer == NULL) { Status = ERROR_NOT_ENOUGH_MEMORY; goto FnExit; } CopyMemory(Buffer, szNewName, Length); ClusterEventEx(CLUSTER_EVENT_PROPERTY_CHANGE, EP_FREE_CONTEXT, Buffer);
FnExit: if (ClusterNameId) LocalFree(ClusterNameId); if (ParamKey) DmCloseKey(ParamKey); if (ResKey) DmCloseKey(ResKey); if (Resource) OmDereferenceObject(Resource); if (hXsaction) { if (Status == ERROR_SUCCESS) DmCommitLocalUpdate(hXsaction); else DmAbortLocalUpdate(hXsaction); } return(Status); }
DWORD FmpUpdateChangeResourceName( IN BOOL bSourceNode, IN LPCWSTR lpszResourceId, IN LPCWSTR lpszNewName ) /*++
Routine Description:
GUM dispatch routine for changing the friendly name of a resource.
Arguments:
bSourceNode - Supplies whether or not this node initiated the GUM update. Not used.
lpszResourceId - Supplies the resource ID.
lpszNewName - Supplies the new friendly name.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise.
--*/
{ PFM_RESOURCE pResource = NULL; DWORD dwStatus; HDMKEY hKey = NULL; DWORD dwDisposition; HLOCALXSACTION hXsaction = NULL; PFM_RES_CHANGE_NAME pResChangeName = NULL;
if ( !FmpFMGroupsInited || FmpShutdown ) { return( ERROR_SUCCESS ); }
//
// Chittur Subbaraman (chitturs) - 6/28/99
//
// Restructure this GUM update as a local transaction.
//
//
pResource = OmReferenceObjectById( ObjectTypeResource, lpszResourceId );
if ( pResource == NULL ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateChangeResourceName: Resource <%1!ws!> could not be found....\n", lpszResourceId); return( ERROR_RESOURCE_NOT_FOUND ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateChangeResourceName: Entry for resource <%1!ws!>, New name = <%2!ws!>...\n", lpszResourceId, lpszNewName);
//
// Start a transaction
//
hXsaction = DmBeginLocalUpdate();
if ( !hXsaction ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateChangeResourceName: Failed in starting a transaction for resource %1!ws!, Status =%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; }
//
// Open the resources key.
//
hKey = DmLocalCreateKey( hXsaction, DmResourcesKey, lpszResourceId, 0, KEY_READ | KEY_WRITE, NULL, &dwDisposition ); if ( hKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateChangeResourceName: Failed in opening the resources key for resource %1!ws!, Status =%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; } CL_ASSERT( dwDisposition != REG_CREATED_NEW_KEY );
//
// Set the resource name in the registry
//
dwStatus = DmLocalSetValue( hXsaction, hKey, CLUSREG_NAME_RES_NAME, REG_SZ, ( CONST BYTE * ) lpszNewName, ( lstrlenW( lpszNewName ) + 1 ) * sizeof( WCHAR ) );
if( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateChangeResourceName: DmLocalSetValue for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
pResChangeName = LocalAlloc( LMEM_FIXED, lstrlenW( lpszNewName ) * sizeof ( WCHAR ) + sizeof( FM_RES_CHANGE_NAME ) );
if ( pResChangeName == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateChangeResourceName: Unable to allocate memory for ResChangeName structure for resource <%1!ws!>, Status =%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; }
dwStatus = OmSetObjectName( pResource, lpszNewName );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateChangeResourceName: Unable to set name <%3!ws!> for resource <%1!ws!>, Status =%2!d!....\n", lpszResourceId, dwStatus, lpszNewName ); LocalFree( pResChangeName ); goto FnExit; }
pResChangeName->pResource = pResource;
lstrcpyW( pResChangeName->szNewResourceName, lpszNewName );
//
// The FM worker thread will free the memory for the pResChangeName
// structure as well as dereference the pResource object.
//
FmpPostWorkItem( FM_EVENT_RESOURCE_NAME_CHANGE, pResChangeName, 0 );
pResource = NULL;
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateChangeResourceName: Successfully changed name of resource <%1!ws!> to <%2!ws!>...\n", lpszResourceId, lpszNewName);
FnExit: if ( pResource != NULL ) { OmDereferenceObject( pResource ); }
if ( hKey != NULL ) { DmCloseKey( hKey ); }
if ( ( dwStatus == ERROR_SUCCESS ) && ( hXsaction ) ) { DmCommitLocalUpdate( hXsaction ); } else { if ( hXsaction ) DmAbortLocalUpdate( hXsaction ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateChangeResourceName: Exit for resource %1!ws!, Status=%2!u!...\n", lpszResourceId, dwStatus);
return( dwStatus ); }
/****
@func DWORD | FmpUpdatePossibleNodesForResType| This update is called to update the possible nodes for a resource type.
@parm IN BOOL | SourceNode | set to TRUE, if the update originated at this node. @parm IN LPCWSTR | lpszResTypeName | The name of the resource type.
@parm IN DWORD | dwBufLength | The size of the multi-sz string pointed to by pBuf
@parm IN PVOID | pBuf | A pointer to the buffer containing the names of the nodes that support this resource type.
@comm The possible list of nodes that supports the given resource type is updated with the list provided.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f FmpDecisionPossibleDmSwitchToNewQuorumLog> ****/ DWORD FmpUpdatePossibleNodeForResType( IN BOOL SourceNode, IN LPCWSTR lpszResTypeName, IN LPDWORD pdwBufLength, IN PVOID pBuf ) { PFM_RESTYPE pResType; DWORD dwStatus; HDMKEY hResTypeKey = NULL; HLOCALXSACTION hXsaction = NULL; LIST_ENTRY NewPosNodeList; PLIST_ENTRY pListEntry; PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry = NULL;
//
// Chittur Subbaraman (chitturs) - 5/13/99
//
// Don't check for FmpFMGroupsInited condition since this GUM
// handler is called by the forming node before that variable
// is set to TRUE. This update always comes after the
// corresponding restypes have been created and is made
// internally by the clussvc following this order. Note that
// a joining node cannot receive this update until groups are
// inited since GUM receive updates are turned on only after
// the FmpFMGroupsInited variable is set to TRUE. Also, the
// intracluster RPC is fired up in a forming node only after
// the groups are inited. Hence, there is no major danger
// of this GUM handler being called if the corresponding
// restype is not created.
//
if ( FmpShutdown ) { return(ERROR_SUCCESS); }
InitializeListHead(&NewPosNodeList);
pResType = OmReferenceObjectById( ObjectTypeResType, lpszResTypeName);
if (!pResType) { dwStatus = ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND; goto FnExit; }
dwStatus = FmpAddPossibleNodeToList(pBuf, *pdwBufLength, &NewPosNodeList);
if (dwStatus != ERROR_SUCCESS) { goto FnExit; }
//writes to the old log file
hXsaction = DmBeginLocalUpdate();
if (!hXsaction) { dwStatus = GetLastError(); goto FnExit; }
hResTypeKey = DmOpenKey(DmResourceTypesKey, lpszResTypeName, KEY_READ | KEY_WRITE); if (hResTypeKey == NULL) { dwStatus = GetLastError(); goto FnExit; }
//if there are no possible owners, delete the value
if (pBuf && *pdwBufLength) { dwStatus = DmLocalSetValue( hXsaction, hResTypeKey, CLUSREG_NAME_RESTYPE_POSSIBLE_NODES, REG_MULTI_SZ, (LPBYTE)pBuf, *pdwBufLength); } else { dwStatus = DmLocalDeleteValue( hXsaction, hResTypeKey, CLUSREG_NAME_RESTYPE_POSSIBLE_NODES); if (dwStatus == ERROR_FILE_NOT_FOUND) { dwStatus = ERROR_SUCCESS; } }
FnExit: if (dwStatus == ERROR_SUCCESS) { //commit the update on the old log file,
//any nodes that were done, will get this change
//I cant delete this file
DmCommitLocalUpdate(hXsaction);
ACQUIRE_EXCLUSIVE_LOCK(gResTypeLock); //free the old list
while (!IsListEmpty(&pResType->PossibleNodeList)) { pListEntry = RemoveHeadList(&pResType->PossibleNodeList); pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY, PossibleLinkage); OmDereferenceObject(pResTypePosEntry->PossibleNode); LocalFree(pResTypePosEntry); } //now switch the possible owners list for the
//resource type
while (!IsListEmpty(&(NewPosNodeList))) { //remove from the new prepared list and hang
//it of the restype structure
pListEntry = RemoveHeadList(&NewPosNodeList); InsertTailList(&pResType->PossibleNodeList, pListEntry); pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY, PossibleLinkage); ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdatePossibleNodesForRestype:Adding node %1!ws! to %2!ws! resource type's possible node list...\n", OmObjectId(pResTypePosEntry->PossibleNode), lpszResTypeName);
}
RELEASE_LOCK(gResTypeLock); ClusterEvent( CLUSTER_EVENT_RESTYPE_PROPERTY_CHANGE, pResType );
} else { //free up the NewPostNodeList
if (hXsaction) DmAbortLocalUpdate(hXsaction); //if a new list was prepared, free it
while (!IsListEmpty(&(NewPosNodeList))) { pListEntry = RemoveHeadList(&NewPosNodeList); pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY, PossibleLinkage); OmDereferenceObject(pResTypePosEntry->PossibleNode); LocalFree(pResTypePosEntry); }
} if (hResTypeKey) DmCloseKey(hResTypeKey); if (pResType) OmDereferenceObject(pResType);
return(dwStatus); }
/****
@func DWORD | FmpDecidePossibleNodeForResType| When the quorum resource is changed, the FM invokes this api on the owner node of the new quorum resource to create a new quorum log file.
@parm IN PVOID | pResource | The new quorum resource. @parm IN LPCWSTR | lpszPath | The path for temporary cluster files. @parm IN DWORD | dwMaxQuoLogSize | The maximum size limit for the quorum log file.
@comm When a quorum resource is changed, the fm calls this funtion before it updates the quorum resource. If a new log file needs to be created, a checkpoint is taken.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f DmSwitchToNewQuorumLog> ****/ DWORD FmpDecidePossibleNodeForResType ( IN PGUM_VOTE_DECISION_CONTEXT pDecisionContext, IN DWORD dwVoteBufLength, IN PVOID pVoteBuf, IN DWORD dwNumVotes, IN BOOL bDidAllActiveNodesVote, OUT LPDWORD pdwOutputBufSize, OUT PVOID *ppOutputBuf ) { DWORD dwStatus = ERROR_SUCCESS; DWORD i; PFMP_VOTE_POSSIBLE_NODE_FOR_RESTYPE pFmpVote; LPWSTR lpmszPossibleNodes = NULL; DWORD dwlpmszLen = 0; PVOID pGumBuffer = NULL; DWORD dwNodeId; WCHAR szNodeId[6]; LPWSTR lpmszCurrentPossibleNodes=NULL; BOOL bChange = FALSE; HDMKEY hResTypeKey = NULL; DWORD dwSize; DWORD dwStringBufSize = 0; BOOL bAssumeSupported; LPWSTR TypeName = NULL;
//First get the type name from pDecisionContext
TypeName=(LPWSTR)LocalAlloc(LMEM_FIXED,pDecisionContext->dwInputBufLength);
if(TypeName==NULL) { ClRtlLogPrint(LOG_ERROR,"[FM] FmpDecidePossibleNodeForResType: Not Enough Memory, error= %1!d!\r\n", GetLastError()); goto FnExit; }
CopyMemory(TypeName,pDecisionContext->pInputBuf,pDecisionContext->dwInputBufLength);
//initialize the out params
*ppOutputBuf = NULL; *pdwOutputBufSize = 0;
bAssumeSupported= *((BOOL*)pDecisionContext->pContext);
if (bAssumeSupported) { hResTypeKey = DmOpenKey(DmResourceTypesKey, TypeName, KEY_READ | KEY_WRITE); if (hResTypeKey == NULL) { dwStatus = GetLastError(); CL_LOGFAILURE(dwStatus); goto FnExit; }
//pass the current possible node list to the decider
dwStatus = DmQueryString(hResTypeKey, CLUSREG_NAME_RESTYPE_POSSIBLE_NODES, REG_MULTI_SZ, &lpmszCurrentPossibleNodes, &dwStringBufSize, &dwSize); if (dwStatus != ERROR_SUCCESS) { //if the possible node list is not found this is ok
//ie. only if there is some other error we give up
if ( dwStatus != ERROR_FILE_NOT_FOUND ) { CL_LOGFAILURE(dwStatus); goto FnExit; } } DmCloseKey(hResTypeKey); hResTypeKey = NULL; } //if the current list is passed in, dont remove any possible
//nodes from the list if they dont vote, simply add the new ones
if (lpmszCurrentPossibleNodes) { DWORD dwStrLen; //make a copy of the multi-sz
dwlpmszLen = ClRtlMultiSzLength(lpmszCurrentPossibleNodes);
dwStrLen = dwlpmszLen * sizeof(WCHAR); lpmszPossibleNodes = LocalAlloc(LMEM_FIXED, dwStrLen); if (!lpmszPossibleNodes) { dwStatus = ERROR_NOT_ENOUGH_MEMORY; CL_LOGFAILURE(dwStatus); goto FnExit; } CopyMemory(lpmszPossibleNodes, lpmszCurrentPossibleNodes, dwStrLen); } for (i = 0; i< dwNumVotes; i++) { pFmpVote = (PFMP_VOTE_POSSIBLE_NODE_FOR_RESTYPE) GETVOTEFROMBUF(pVoteBuf, pDecisionContext->dwVoteLength, i+1 , &dwNodeId); //if not a valid vote, skip
if (!pFmpVote) continue; CL_ASSERT((PBYTE)pFmpVote <= ((PBYTE)pVoteBuf + dwVoteBufLength - sizeof(FMP_VOTE_POSSIBLE_NODE_FOR_RESTYPE))); wsprintfW(szNodeId, L"%d" , dwNodeId); if (pFmpVote->bPossibleNode) { if (lpmszCurrentPossibleNodes) { //if the string is already there, dont append it again
if (ClRtlMultiSzScan(lpmszCurrentPossibleNodes, szNodeId)) continue;
} dwStatus = ClRtlMultiSzAppend(&lpmszPossibleNodes, &dwlpmszLen, szNodeId); bChange = TRUE; if (dwStatus != ERROR_SUCCESS) goto FnExit; } else { //if a current list was specified
//this node is not a possible node anymore, remove it from the list
if (lpmszCurrentPossibleNodes) { ClRtlLogPrint(LOG_NOISE, "[FM] FmpDecidePossibleNodesForRestype: Removing node %1!ws! from %2!ws! restype possibleowner list \r\n", szNodeId,TypeName); dwStatus = ClRtlMultiSzRemove(lpmszPossibleNodes, &dwlpmszLen, szNodeId); if (dwStatus == ERROR_SUCCESS) { //if the node is successfully removed
bChange = TRUE; } else if (dwStatus != ERROR_FILE_NOT_FOUND) { //if the node exists but cannot be removed return with error
//if the node didnt exist, we dont do anything bChange remains
//set at FALSE
goto FnExit; } else { dwStatus = ERROR_SUCCESS; } } } }
//if nothing has changed dont issue a gum update
if (!bChange) { dwStatus = ERROR_ALREADY_EXISTS; goto FnExit; }
//dwlpmszLen contains the size of the multi-sz string in the
//number of characters, make it the number of bytes
dwlpmszLen *= sizeof(WCHAR); pGumBuffer = GumMarshallArgs(pdwOutputBufSize, 3, pDecisionContext->dwInputBufLength, pDecisionContext->pInputBuf, sizeof(DWORD), &dwlpmszLen, dwlpmszLen, lpmszPossibleNodes);
*ppOutputBuf = pGumBuffer; FnExit: if (lpmszPossibleNodes) LocalFree(lpmszPossibleNodes); if (hResTypeKey) DmCloseKey(hResTypeKey); if (lpmszCurrentPossibleNodes) LocalFree(lpmszCurrentPossibleNodes); if(TypeName) LocalFree(TypeName);
return(dwStatus); }
/****
@func DWORD | FmpUpdateChangeResourceNode| This update is called to update the possible nodes for a resource.
@parm IN BOOL | SourceNode | set to TRUE, if the update originated at this node. @parm IN PFM_RESOURCE | pResource | A pointer to the resource whose possible node list is being updated.
@parm IN PNM_NODE | pNode | A pointer to the node to be added/removed from the possible node lis.
@parm IN DWORD | dwControlCode | If CLUSCTL_RESOURCE_ADD_OWNER then the node is added to the possible node list, else it is removed.
@comm The possible list of nodes for a resource is updated.
@rdesc Returns a result code. ERROR_SUCCESS on success.
****/ DWORD FmpUpdateChangeResourceNode( IN BOOL SourceNode, IN PFM_RESOURCE pResource, IN PNM_NODE pNode, IN DWORD dwControlCode ) { DWORD dwStatus; HDMKEY hResKey = NULL; HLOCALXSACTION hXsaction = NULL;
//Dont acquire the local resource lock since acquiring that
//within gum updates causes deadlock
//use the global resource lock to synchronize this call
//with the enumeration of possible nodes
FmpAcquireResourceLock();
//start a transaction
hXsaction = DmBeginLocalUpdate();
if (!hXsaction) { dwStatus = GetLastError(); goto FnExit; }
if (dwControlCode == CLUSCTL_RESOURCE_ADD_OWNER) { dwStatus = FmpAddPossibleNode(pResource, pNode); } else { dwStatus = FmpRemovePossibleNode(pResource, pNode, FALSE); } if (dwStatus != ERROR_SUCCESS) { ClRtlLogPrint( LOG_NOISE, "[FM] FmpUpdateChangeResourceNode, failed possible node updatefor resource <%1!ws!>, error %2!u!\n", OmObjectName(pResource), dwStatus ); goto FnExit; } //fix the registry
//SS - do we need to fix the preferred node list
hResKey = DmOpenKey(DmResourcesKey, OmObjectId(pResource), KEY_READ | KEY_WRITE); if (hResKey == NULL) { dwStatus = GetLastError(); goto FnExit; }
if (dwControlCode == CLUSCTL_RESOURCE_ADD_OWNER) { dwStatus = DmLocalAppendToMultiSz( hXsaction, hResKey, CLUSREG_NAME_RES_POSSIBLE_OWNERS, OmObjectId(pNode)); } else { dwStatus = DmLocalRemoveFromMultiSz( hXsaction, hResKey, CLUSREG_NAME_RES_POSSIBLE_OWNERS, OmObjectId(pNode)); if (dwStatus == ERROR_FILE_NOT_FOUND) { DWORD i; DWORD Result; PNM_NODE pEnumNode;
//
// Possible nodes did not exist, so create a new entry
// with every possible node in it. FM will already have
// removed the passed in node from the possible node list.
//
i=0; do { Result = FmEnumResourceNode(pResource, i, &pEnumNode); if (Result == ERROR_SUCCESS) { dwStatus = DmLocalAppendToMultiSz( hXsaction, hResKey, CLUSREG_NAME_RES_POSSIBLE_OWNERS, OmObjectId(pEnumNode)); OmDereferenceObject(pEnumNode);
} else if ((Result == ERROR_NO_MORE_ITEMS) && (i == 0)) { //
// This is a funny corner case where there is a one
// node cluster and a resource with no possibleowners
// entry, and somebody removes the only node in the cluster
// from the possible owners list. Set PossibleOwners to
// the empty set.
//
dwStatus = DmLocalSetValue( hXsaction, hResKey, CLUSREG_NAME_RES_POSSIBLE_OWNERS, REG_MULTI_SZ, (CONST BYTE *)L"\0", 2);
} ++i; } while ( Result == ERROR_SUCCESS ); //map the error to success
dwStatus = ERROR_SUCCESS; } } DmCloseKey(hResKey);
FnExit: //release the lock
FmpReleaseResourceLock(); if (dwStatus == ERROR_SUCCESS) { //commit the update on the old log file,
//any nodes that were done, will get this change
//I cant delete this file
DmCommitLocalUpdate(hXsaction);
} else { //SS: BUGBUG :: validation for possible node should
//be done before the registry is switched
//the inmemory structure should be changed only on success
//if there is a failure in the registry apis..the
//in memory structure will be out of sync with registry
if (hXsaction) DmAbortLocalUpdate(hXsaction); }
return(dwStatus); }
/****
@func DWORD | FmpUpdateChangeResourceGroup| This update is called to update the group to which the resource belongs.
@parm IN BOOL | bSourceNode | set to TRUE, if the update originated at this node. @parm IN PFM_RESOURCE | pResource | A pointer to the resource whose possible node list is being updated.
@parm IN PFM_GROUP | pNewGroup | A pointer to the node to be added/removed from the possible node lis.
@comm The possible list of nodes for a resource is updated.
@rdesc Returns a result code. ERROR_SUCCESS on success.
****/ DWORD FmpUpdateChangeResourceGroup( IN BOOL bSourceNode, IN PFM_RESOURCE pResource, IN PFM_GROUP pNewGroup) { DWORD dwStatus = ERROR_SUCCESS; PFM_GROUP pOldGroup; PFM_DEPENDENCY_TREE pTree = NULL; HLOCALXSACTION hXsaction = NULL; HDMKEY hOldGroupKey = NULL; HDMKEY hNewGroupKey = NULL; PLIST_ENTRY pListEntry; PFM_DEPENDTREE_ENTRY pEntry;
pOldGroup = pResource->Group;
//
// Check to make sure the resource is not already in the group.
//
if (pOldGroup == pNewGroup) { dwStatus = ERROR_ALREADY_EXISTS; goto FnExit; }
//
// Synchronize both the old and the new groups.
// Lock the lowest by lowest Group Id first - to prevent deadlocks!
// Note - the order of release is unimportant.
//
// strictly, the comparison below cannot be equal!
//
if ( lstrcmpiW( OmObjectId( pOldGroup ), OmObjectId( pNewGroup ) ) <= 0 ) { FmpAcquireLocalGroupLock( pOldGroup ); FmpAcquireLocalGroupLock( pNewGroup ); } else { FmpAcquireLocalGroupLock( pNewGroup ); FmpAcquireLocalGroupLock( pOldGroup ); }
//start a transaction
hXsaction = DmBeginLocalUpdate();
if (!hXsaction) { dwStatus = GetLastError(); goto FnUnlock; }
//
// For now... both Groups must be owned by the same node.
//
if ( pResource->Group->OwnerNode != pNewGroup->OwnerNode ) { dwStatus = ERROR_HOST_NODE_NOT_GROUP_OWNER; goto FnUnlock; }
//
// Create a full dependency tree,
//
pTree = FmCreateFullDependencyTree(pResource); if ( pTree == NULL ) { dwStatus = GetLastError(); goto FnUnlock; }
//
// Add each resource in the dependency tree to its new group's list.
//
hNewGroupKey = DmOpenKey(DmGroupsKey, OmObjectId(pNewGroup), KEY_READ | KEY_WRITE); if (hNewGroupKey == NULL) { dwStatus = GetLastError(); goto FnUnlock; } hOldGroupKey = DmOpenKey(DmGroupsKey, OmObjectId(pOldGroup), KEY_READ | KEY_WRITE); if (hOldGroupKey == NULL) { dwStatus = GetLastError(); goto FnUnlock; }
//
// For each resource in the dependency tree, remove it from the
// old group list and add it to the new group list
//
pListEntry = pTree->ListHead.Flink; while (pListEntry != &pTree->ListHead) { pEntry = CONTAINING_RECORD(pListEntry, FM_DEPENDTREE_ENTRY, ListEntry); pListEntry = pListEntry->Flink;
dwStatus = DmLocalRemoveFromMultiSz(hXsaction, hOldGroupKey, CLUSREG_NAME_GRP_CONTAINS, OmObjectId(pEntry->Resource));
if (dwStatus != ERROR_SUCCESS) { goto FnUnlock; }
dwStatus = DmLocalAppendToMultiSz(hXsaction, hNewGroupKey, CLUSREG_NAME_GRP_CONTAINS, OmObjectId(pEntry->Resource));
if (dwStatus != ERROR_SUCCESS) { goto FnUnlock; }
} //
// Passed all the checks, do the in-memorymove.
//
pListEntry = pTree->ListHead.Flink; while (pListEntry != &pTree->ListHead) { pEntry = CONTAINING_RECORD(pListEntry, FM_DEPENDTREE_ENTRY, ListEntry); pListEntry = pListEntry->Flink;
//
// Move this resource
//
RemoveEntryList(&pEntry->Resource->ContainsLinkage);
InsertHeadList(&pNewGroup->Contains, &pEntry->Resource->ContainsLinkage); OmReferenceObject(pNewGroup); pEntry->Resource->Group = pNewGroup; ++pEntry->Resource->StateSequence;
ClusterEvent(CLUSTER_EVENT_RESOURCE_CHANGE,pEntry->Resource); OmDereferenceObject(pOldGroup); }
FnUnlock: //
// Now release all locks.
//
FmpReleaseLocalGroupLock( pNewGroup ); FmpReleaseLocalGroupLock( pOldGroup );
FnExit: if (pTree) FmDestroyFullDependencyTree(pTree); if (hOldGroupKey) DmCloseKey(hOldGroupKey); if (hNewGroupKey) DmCloseKey(hNewGroupKey); if (dwStatus == ERROR_SUCCESS) { ClusterEvent(CLUSTER_EVENT_GROUP_PROPERTY_CHANGE,pNewGroup); ClusterEvent(CLUSTER_EVENT_GROUP_PROPERTY_CHANGE,pOldGroup); DmCommitLocalUpdate(hXsaction); } else { if (hXsaction) DmAbortLocalUpdate(hXsaction); }
return(dwStatus);
}
DWORD FmpUpdateAddDependency( IN BOOL SourceNode, IN LPCWSTR ResourceId, IN LPCWSTR DependsOnId ) /*++
Routine Description:
GUM dispatch routine for adding a dependency
Arguments:
SourceNode - Supplies whether or not this node initiated the GUM update. Not used.
ResourceId - Supplies the resource ID of the resource that should have a dependency added.
DependsOnId - Supplies the resource ID of the resource that should provide for ResourceId.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise.
--*/
{ PFM_RESOURCE Resource; PFM_RESOURCE DependsOn; PDEPENDENCY dependency;
//
// Chittur Subbaraman (chitturs) - 4/18/99
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
dependency = LocalAlloc(LMEM_FIXED, sizeof(DEPENDENCY)); if (dependency == NULL) { CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY ); return(ERROR_NOT_ENOUGH_MEMORY); }
Resource = OmReferenceObjectById(ObjectTypeResource, ResourceId); if (Resource == NULL) { CL_LOGFAILURE( ERROR_RESOURCE_NOT_FOUND ); LocalFree(dependency); return(ERROR_RESOURCE_NOT_FOUND); }
DependsOn = OmReferenceObjectById(ObjectTypeResource, DependsOnId); if (DependsOn == NULL) { OmDereferenceObject(Resource); LocalFree(dependency); CL_LOGFAILURE( ERROR_DEPENDENCY_NOT_FOUND ); return(ERROR_DEPENDENCY_NOT_FOUND); }
dependency->DependentResource = Resource; dependency->ProviderResource = DependsOn; FmpAcquireResourceLock(); InsertTailList( &DependsOn->ProvidesFor, &dependency->ProviderLinkage ); InsertTailList( &Resource->DependsOn, &dependency->DependentLinkage ); FmpReleaseResourceLock();
ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, Resource );
//SS: we leave the reference counts on both the objects
//as a dependency referrring to them has been created.
return(ERROR_SUCCESS);
} // FmpUpdateAddDependency
DWORD FmpUpdateRemoveDependency( IN BOOL SourceNode, IN LPCWSTR ResourceId, IN LPCWSTR DependsOnId ) /*++
Routine Description:
GUM dispatch routine for adding a dependency
Arguments:
SourceNode - Supplies whether or not this node initiated the GUM update. Not used.
ResourceId - Supplies the resource ID of the resource that should have a dependency removed.
DependsOnId - Supplies the resource ID of the resource that provides for ResourceId.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise.
--*/
{ PFM_RESOURCE Resource; PFM_RESOURCE DependsOn; PDEPENDENCY dependency; PLIST_ENTRY ListEntry; DWORD Status=ERROR_SUCCESS;
//
// Chittur Subbaraman (chitturs) - 4/18/99
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
Resource = OmReferenceObjectById(ObjectTypeResource, ResourceId); if (Resource == NULL) { CL_LOGFAILURE( ERROR_RESOURCE_NOT_FOUND ); return(ERROR_RESOURCE_NOT_FOUND); }
DependsOn = OmReferenceObjectById(ObjectTypeResource, DependsOnId); if (DependsOn == NULL) { OmDereferenceObject(Resource); CL_LOGFAILURE( ERROR_RESOURCE_NOT_FOUND ); return(ERROR_RESOURCE_NOT_FOUND); }
//
// Walk through the dependency list of the resource searching
// for a match.
//
FmpAcquireResourceLock(); ListEntry = Resource->DependsOn.Flink; while (ListEntry != &Resource->DependsOn) { dependency = CONTAINING_RECORD(ListEntry, DEPENDENCY, DependentLinkage); CL_ASSERT(dependency->DependentResource == Resource); if (dependency->ProviderResource == DependsOn) { //
// Found a match. Remove it from its list and
// free it up.
//
RemoveEntryList(&dependency->ProviderLinkage); RemoveEntryList(&dependency->DependentLinkage); // dereference the providor and dependent resource
OmDereferenceObject(dependency->DependentResource); OmDereferenceObject(dependency->ProviderResource); LocalFree(dependency); break; } ListEntry = ListEntry->Flink; } FmpReleaseResourceLock();
if (ListEntry != &Resource->DependsOn) { //
// A match was found. Dereference the provider resource
// to account for the dependency removal and return success.
//
ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, Resource ); Status = ERROR_SUCCESS; } else { Status = ERROR_DEPENDENCY_NOT_FOUND; }
//SS: dereference the objects earlier referenced
OmDereferenceObject(Resource); OmDereferenceObject(DependsOn); return(Status);
} // FmpUpdateRemoveDependency
DWORD FmpUpdateDeleteGroup( IN BOOL SourceNode, IN LPCWSTR GroupId ) /*++
Routine Description:
GUM dispatch routine for deleting a group.
Arguments:
SourceNode - Supplies whether or not this node initiated the GUM update. Not used.
GroupId - Supplies the group ID.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise.
--*/
{ DWORD dwStatus = ERROR_SUCCESS; PFM_GROUP pGroup = NULL; PLIST_ENTRY listEntry; PPREFERRED_ENTRY preferredEntry; BOOL bLocked = FALSE;
//
// Chittur Subbaraman (chitturs) - 4/18/99
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
//
// Find the specified Group.
//
pGroup = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( pGroup == NULL ) { dwStatus = ERROR_GROUP_NOT_FOUND; return(dwStatus); }
ClRtlLogPrint(LOG_NOISE, "[FM] DeleteGroup %1!ws!, address = %2!lx!.\n", OmObjectId(pGroup), pGroup ); //
// Chittur Subbaraman (chitturs) - 1/12/99
//
// Try to acquire lock, and make sure the Contains list is empty.
//
// Most of the calls to manipulate groups make calls to the owner
// node of the group and this operation is serialized by GUM. So,
// there is no major danger if we do the operations in this function
// without holding the group lock. However, we can't rule out
// corruption 100% as of now.
//
// If you block within the GUM handler here, then no events in
// the cluster proceed forward and things come to a grinding halt.
//
// A case in point:
// (1) Thread 1 (the thread that calls this function) grabs the
// GUM lock and waits for the group lock.
// (2) Thread 2 (FmWorkerThread) grabs the group lock and calls
// resmon attempting to close a resource. It gets blocked on
// the resmon eventlist lock.
// (3) Thread 3 calls RmResourceControl to set the resource name
// which grabs the resmon eventlist lock and then in turn calls
// ClusterRegSetValue and then gets blocked on the GUM lock.
//
FmpTryAcquireLocalGroupLock( pGroup, bLocked );
if ( !IsListEmpty( &pGroup->Contains ) ) { dwStatus = ERROR_DIR_NOT_EMPTY; goto FnExit; }
//
// Close the Group's registry key.
//
DmRundownList( &pGroup->DmRundownList ); if ( pGroup->RegistryKey != NULL ) { DmCloseKey( pGroup->RegistryKey ); pGroup->RegistryKey = NULL; }
//
// Remove from the node list
//
dwStatus = OmRemoveObject( pGroup ); ClusterEvent( CLUSTER_EVENT_GROUP_DELETED, pGroup ); //
// This dereference would normally cause the group to eventually disappear,
// however the event notification above will keep a ref on the object
// until all notifications have been delivered.
//
OmDereferenceObject( pGroup );
//
// Make sure the preferred owners list is drained.
//
while ( !IsListEmpty( &pGroup->PreferredOwners ) ) { listEntry = RemoveHeadList(&pGroup->PreferredOwners); preferredEntry = CONTAINING_RECORD( listEntry, PREFERRED_ENTRY, PreferredLinkage ); OmDereferenceObject( preferredEntry->PreferredNode ); LocalFree( preferredEntry ); }
//
// Free the string associated with the AntiAffinityClassName field.
//
LocalFree ( pGroup->lpszAntiAffinityClassName );
pGroup->dwStructState |= FM_GROUP_STRUCT_MARKED_FOR_DELETE; FnExit: if( bLocked ) { FmpReleaseLocalGroupLock( pGroup ); }
//
// Dereference for reference above.
//
if (pGroup) OmDereferenceObject( pGroup );
return(dwStatus);
} // FmpUpdateDeleteGroup
/****
@func DWORD | FmpUpdateGroupIntendedOwner| This update is called on a move just before the source node requests the target node to take over the group.
@parm IN BOOL | bSourceNode | set to TRUE, if the update originated at this node. @parm IN PFM_GROUP | pszGroupId | The ID of the group that is about to move.
@parm IN PDWORD | pdwNodeId| A pointer to a DWORD that contains the ID of the node that is the destination of this move. It is set to ClusterInvalidNodeId by the destination node when it has accepted the group.
@comm The purpose of this update is to let all nodes know that a move is impending. If the source node dies while a move is in progress then preference is given to the target of the move rather than the node that is chosen by the FmpUpdateAssignOwnerToGroups
@rdesc Returns a result code. ERROR_SUCCESS on success. ****/ DWORD FmpUpdateGroupIntendedOwner( IN BOOL SourceNode, IN LPCWSTR pszGroupId, IN PDWORD pdwNodeId ) { PFM_GROUP pGroup = NULL; DWORD dwStatus = ERROR_SUCCESS; PNM_NODE pNode = NULL; PNM_NODE pPrevNode; WCHAR pszNodeId[6]; if ( !FmpFMGroupsInited ) { return(ERROR_SUCCESS); }
pGroup = OmReferenceObjectById( ObjectTypeGroup, pszGroupId );
if (pGroup == NULL) { dwStatus = ERROR_GROUP_NOT_FOUND; goto FnExit; }
if (*pdwNodeId != ClusterInvalidNodeId) { wsprintfW(pszNodeId, L"%u", *pdwNodeId);
pNode = OmReferenceObjectById(ObjectTypeNode, pszNodeId);
if (pNode == NULL) { dwStatus = ERROR_CLUSTER_NODE_NOT_FOUND; goto FnExit; } } else if (pGroup->pIntendedOwner == NULL) { dwStatus = ERROR_CLUSTER_INVALID_NODE; ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateGroupIntendedOwner: Group <%1!ws!> intended owner is already invalid, not setting....\n", pszGroupId); goto FnExit; } //
// HACKHACK: Chittur Subbaraman (chitturs) - 5/20/99
// Comment out as a temporary solution to avoid deadlocks.
//
// FmpAcquireLocalGroupLock(pGroup);
pPrevNode = pGroup->pIntendedOwner;
//set the new owner node, incr ref count
if (pNode) OmReferenceObject(pNode); pGroup->pIntendedOwner = pNode;
//decr ref count on previous owner
if (pPrevNode) OmDereferenceObject(pPrevNode); //
// HACKHACK: Chittur Subbaraman (chitturs) - 5/20/99
// Comment out as a temporary solution to avoid deadlocks.
//
// FmpReleaseLocalGroupLock(pGroup);
FnExit: if (pGroup) OmDereferenceObject(pGroup); if (pNode) OmDereferenceObject(pNode); return(dwStatus); }
/****
@func DWORD | FmpUpdateAssignOwnerToGroups| This update is made when a node goes down to take ownership of all the orphaned groups.
@parm IN BOOL | bSourceNode | set to TRUE, if the update originated at this node. @parm IN LPCWSTR | pszGroupId | The ID of the group that is about to move.
@parm IN PDWORD | pdwNodeId| A pointer to a DWORD that contains the ID of the node that is the destination of this move. It is set to ClusterInvalidNodeId by the destination node when it has accepted the group.
@comm The purpose of this update is to let all nodes know that a move is impending. If the source node dies while a move is in progress , then preference is given to the target of the move rather than the node that is chosen by the FmpClaimNodeGroups algorithm.
@rdesc returns ERROR_SUCCESS. ****/ DWORD FmpUpdateAssignOwnerToGroups( IN BOOL SourceNode, IN LPCWSTR pszNodeId ) { PNM_NODE pNode = NULL; DWORD dwStatus = ERROR_SUCCESS;
//
// Chittur Subbaraman (chitturs) - 4/18/99
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
pNode = OmReferenceObjectById( ObjectTypeNode, pszNodeId );
if (!pNode) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateAssignOwnersToGroups, %1!ws! node not found\n", pszNodeId); //should we return failure here
//is evict of a node synchronized with everything
goto FnExit; }
//if this update has already been seen after the node down
//ignore this one
if (gFmpNodeArray[NmGetNodeId(pNode)].dwNodeDownProcessingInProgress == 0) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateAssignOwnersToGroups, %1!ws! node down has been processed already\n", pszNodeId); goto FnExit; } //
// Assign ownership to all groups owned by the dead node
//
dwStatus = FmpAssignOwnersToGroups(pNode, NULL, NULL);
if (dwStatus != ERROR_SUCCESS) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateAssignOwnersToGroups failed %1!d!\n", dwStatus); } //mark that the node down processing has been done
gFmpNodeArray[NmGetNodeId(pNode)].dwNodeDownProcessingInProgress = 0; FnExit: if (pNode) OmDereferenceObject(pNode); return(dwStatus); }
/****
@func DWORD | FmpUpdateApproveJoin| The joining node makes this update call.
@parm IN BOOL | bSourceNode | set to TRUE, if the update originated at this node. @parm IN LPCWSTR | pszGroupId | The ID of the group that is about to move.
@parm IN PDWORD | pdwNodeId| A pointer to a DWORD that contains the ID of the node that is the destination of this move. It is set to ClusterInvalidNodeId by the destination node when it has accepted the group.
@comm The purpose of this update is to let all nodes know that a move is impending. If the source node dies while a move is in progress , then preference is given to the target of the move rather than the node that is chosen by the FmpClaimNodeGroups algorithm.
@rdesc returns ERROR_SUCCESS. ****/ DWORD FmpUpdateApproveJoin( IN BOOL SourceNode, IN LPCWSTR pszNodeId ) {
PNM_NODE pNode = NULL; DWORD dwStatus = ERROR_SUCCESS;
//
// Chittur Subbaraman (chitturs) - 4/18/99
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return(ERROR_SUCCESS); }
pNode = OmReferenceObjectById( ObjectTypeNode, pszNodeId );
if (!pNode) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateAssignOwnersToGroups, %1!ws! node not found\n", pszNodeId); //should we return failure here
//is evict of a node synchronized with everything
goto FnExit; }
if (pNode == NmLocalNode) { // SS: can I become the locker now
// If so, there what do I do
//i approve of my own join
goto FnExit; } //if a node is trying to join before the processing
//for its last death has been completed, ask it to retry
if (gFmpNodeArray[NmGetNodeId(pNode)].dwNodeDownProcessingInProgress == 1) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateApproveJoin, %1!ws! node down hasnt been processed as yet\n", pszNodeId); dwStatus = ERROR_RETRY; goto FnExit; } FnExit: if (pNode) OmDereferenceObject(pNode); return(dwStatus); }
/****
@func DWORD | FmpUpdateCreateGroup | GUM update handler for creating a group. @parm IN OUT PGUM_CREATE_GROUP | pGumGroup | Buffer containing group info
@parm IN BOOL | bSourceNode | Indicates whether this call originated from this node.
@comm This GUM update creates a group and is structured as a local transaction so that both registry entries and in-memory structures are updated consistently.
@rdesc Returns ERROR_SUCCESS on success. A Win32 error code otherwise. ****/ DWORD FmpUpdateCreateGroup( IN OUT PGUM_CREATE_GROUP pGumGroup, IN BOOL bSourceNode ) { DWORD dwStatus = ERROR_SUCCESS; HDMKEY hKey = NULL; DWORD dwDisposition; HLOCALXSACTION hXsaction = NULL; LPCWSTR lpszNodeId = NULL; PNM_NODE pNode = NULL; DWORD dwGroupIdLen = 0; DWORD dwGroupNameLen = 0; LPWSTR lpszGroupId = NULL; LPCWSTR lpszGroupName = NULL; BOOL bLocked = FALSE;
//
// Chittur Subbaraman (chitturs) - 5/27/99
//
// Restructure this GUM update as a local transaction.
//
dwGroupIdLen = pGumGroup->GroupIdLen; dwGroupNameLen = pGumGroup->GroupNameLen; lpszGroupId = pGumGroup->GroupId; lpszGroupName = (PWSTR)((PCHAR)lpszGroupId + dwGroupIdLen ); ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateGroup: Entry for group %1!ws!...\n", lpszGroupId); //
// Start a transaction
//
hXsaction = DmBeginLocalUpdate();
if ( !hXsaction ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateGroup, Failed in starting a transaction for group %1!ws!, Status =%2!d!....\n", lpszGroupId, dwStatus); return( dwStatus ); }
//
// Create the new group key.
//
hKey = DmLocalCreateKey( hXsaction, DmGroupsKey, lpszGroupId, 0, KEY_READ | KEY_WRITE, NULL, &dwDisposition ); if ( hKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateGroup, Failed in creating the group key for group %1!ws!, Status =%2!d!....\n", lpszGroupId, dwStatus); goto FnExit; } if ( dwDisposition != REG_CREATED_NEW_KEY ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateGroup used GUID %1!ws! that already existed! This is impossible.\n", lpszGroupId); dwStatus = ERROR_ALREADY_EXISTS; goto FnExit; }
CL_ASSERT( dwDisposition == REG_CREATED_NEW_KEY );
//
// Set the group name in the registry
//
dwStatus = DmLocalSetValue( hXsaction, hKey, CLUSREG_NAME_GRP_NAME, REG_SZ, ( CONST BYTE * ) lpszGroupName, ( lstrlenW( lpszGroupName ) + 1 ) * sizeof( WCHAR ) );
if( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateGroup: DmLocalSetValue for group %1!ws! fails, Status = %2!d!...\n", lpszGroupId, dwStatus); goto FnExit; } //
// We really shouldn't be acquiring locks here... but
// we'll try anyway. If we fail, we must return an error
// because we have nothing to return.
//
FmpTryAcquireGroupLock( bLocked, 500 ); if ( !bLocked ) { pGumGroup->Group = NULL; dwStatus = ERROR_SHARING_VIOLATION; goto FnExit; }
pGumGroup->Group = FmpCreateGroup( lpszGroupId, TRUE ); if ( pGumGroup->Group == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateGroup, FmpCreateFroup failed for group %1!ws!, Status =%2!d!....\n", lpszGroupId, dwStatus); goto FnExit; } else { if ( bSourceNode ) { OmReferenceObject( pGumGroup->Group ); OmReferenceObject( NmLocalNode ); pNode = NmLocalNode; } else { lpszNodeId = (PWSTR)((PCHAR)lpszGroupId + dwGroupIdLen + dwGroupNameLen ); pNode = OmReferenceObjectById( ObjectTypeNode, lpszNodeId ); if ( pNode == NULL ) { CL_LOGFAILURE( ERROR_CLUSTER_NODE_NOT_FOUND ); dwStatus = ERROR_CLUSTER_NODE_NOT_FOUND; ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateGroup, Could not find node for group %1!ws!, Status =%2!d!....\n", lpszGroupId, dwStatus); CsInconsistencyHalt( ERROR_CLUSTER_NODE_NOT_FOUND ); } }
CL_ASSERT( pGumGroup->Group->OwnerNode == NULL );
if ( !FmpInPreferredList( pGumGroup->Group, pNode , FALSE, NULL) ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateGroup, node %1!ws! is not in preferred list for group %2!ws!.\n", OmObjectId( pNode ), OmObjectId( pGumGroup->Group )); }
pGumGroup->Group->OwnerNode = pNode; if ( OmSetObjectName( pGumGroup->Group, lpszGroupName ) != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateGroup, Cannot set name for group %1!ws!...\n", OmObjectId( pGumGroup->Group )); } ClusterEvent( CLUSTER_EVENT_GROUP_ADDED, pGumGroup->Group ); } FnExit: if ( bLocked ) { FmpReleaseGroupLock( ); } if ( hKey != NULL ) { DmCloseKey( hKey ); }
if ( ( dwStatus == ERROR_SUCCESS ) && ( hXsaction != NULL ) ) { DmCommitLocalUpdate( hXsaction ); } else { if ( hXsaction ) DmAbortLocalUpdate( hXsaction ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateGroup: Exit for group %1!ws!, Status=%2!u!...\n", lpszGroupId, dwStatus);
return( dwStatus ); }
/****
@func DWORD | FmpUpdateCompleteGroupMove | This update is made when FmpTakeGroupRequest fails with an RPC error.
@parm IN BOOL | bSourceNode | Set to TRUE, if the update originated at this node. Not used. @parm IN LPCWSTR | pszNodeId | The ID of the dead node.
@parm IN LPCWSTR | pszGroupId | The ID of the group which was in the middle of the move.
@comm The purpose of this update is to let the ownership of the group which was in the middle of the move determined consistently.
@rdesc Returns ERROR_SUCCESS. ****/ DWORD FmpUpdateCompleteGroupMove( IN BOOL bSourceNode, IN LPCWSTR pszNodeId, IN LPCWSTR pszGroupId ) {
PNM_NODE pNode = NULL; PFM_GROUP pGroup = NULL; DWORD dwStatus = ERROR_SUCCESS;
//
// Chittur Subbaraman (chitturs) - 4/2/2000
//
// If FM groups are not fully initialized, then don't do anything.
// Don't check for shutdown since we need to handle take group
// exceptions for the quorum group even during a shutdown.
//
if ( !FmpFMGroupsInited ) { return( ERROR_SUCCESS ); }
pNode = OmReferenceObjectById( ObjectTypeNode, pszNodeId );
if ( !pNode ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCompleteGroupMove, %1!ws! node not found\n", pszNodeId); goto FnExit; }
pGroup = OmReferenceObjectById( ObjectTypeGroup, pszGroupId );
if ( !pGroup ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCompleteGroupMove, %1!ws! group not found\n", pszGroupId); goto FnExit; }
//
// Assign ownership to this group which was in the middle of a move
//
dwStatus = FmpAssignOwnersToGroups( pNode, pGroup, NULL );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCompleteGroupMove failed with error %1!d!\n", dwStatus); } FnExit: if ( pNode ) OmDereferenceObject( pNode ); if ( pGroup ) OmDereferenceObject( pGroup );
return( dwStatus ); }
DWORD FmpUpdateCheckAndSetGroupOwner( IN BOOL bSourceNode, IN LPCWSTR lpszGroupId, IN LPCWSTR lpszNodeId ) /*++
Routine Description:
GUM update handler called from FmpTakeGroupRequest for NT5 cluster to set the group owner ONLY IF its intended owner is the future owner node.
Arguments:
bSourceNode - Supplies whether or not this node was the source of the update
lpszGroupId - Supplies the id of the resource whose state is changing
lpszNodeId - Supplies the node id of the group owner.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PFM_GROUP pGroup = NULL; DWORD dwStatus = ERROR_SUCCESS; PNM_NODE pNode = NULL; PNM_NODE pPrevNode = NULL;
//dont check for shutdown - we cant afford to lose ownership notifications
//while we are shutting down
//since we dont destroy any fm structures - there shouldnt be a problem in
//handling these
if ( !FmpFMGroupsInited ) { return( ERROR_SUCCESS ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCheckAndSetGroupOwner: Entry for Group = <%1!ws!>....\n", lpszGroupId); //
// Chittur Subbaraman (chitturs) - 7/27/99
//
// This GUM handler sets the group ownership only if the future owner
// node is the group's intended owner. If the intended owner is NULL,
// it means the node down processing GUM handler has taken charge
// of this group. If the intended owner is not NULL and not the
// future owner node, then it means that the node down processing
// GUM handler has assigned ownership to the group and the group
// started moving to a different target before the FmpTakeGroupRequest
// that issued this GUM due as a part of the first move operation
// got a chance to execute. In both cases, lay your hands off the
// group.
//
pGroup = OmReferenceObjectById( ObjectTypeGroup, lpszGroupId );
if ( pGroup == NULL ) { ClRtlLogPrint(LOG_ERROR, "[FM] FmpUpdateCheckAndSetGroupOwner: GroupID = %1!ws! could not be found...\n", lpszGroupId); dwStatus = ERROR_GROUP_NOT_FOUND; goto FnExit; }
pNode = OmReferenceObjectById( ObjectTypeNode, lpszNodeId );
if ( pNode == NULL ) { ClRtlLogPrint(LOG_ERROR, "[FM] FmpUpdateCheckAndSetGroupOwner: NodeID = %1!ws! could not be found, Group = %2!ws!...\n", lpszNodeId, lpszGroupId); dwStatus = ERROR_CLUSTER_NODE_NOT_FOUND; goto FnExit; }
if ( pGroup->pIntendedOwner != pNode ) { ClRtlLogPrint(LOG_ERROR, "[FM] FmpUpdateCheckAndSetGroupOwner: Group = <%1!ws!> intended owner is invalid, not setting group ownership...\n", lpszGroupId); dwStatus = ERROR_GROUP_NOT_AVAILABLE; goto FnExit; } pPrevNode = pGroup->OwnerNode;
//
// Set the new owner node, incr ref count
//
OmReferenceObject( pNode ); pGroup->OwnerNode = pNode;
//
// Decrement the ref count on previous owner
//
OmDereferenceObject( pPrevNode );
//
// Generate an event to signify group owner node change
//
ClusterEvent( CLUSTER_EVENT_GROUP_CHANGE, pGroup ); FnExit: if ( pGroup ) OmDereferenceObject( pGroup ); if ( pNode ) OmDereferenceObject( pNode );
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCheckAndSetGroupOwner: Exit for Group = <%1!ws!>, Status=%2!u!....\n", lpszGroupId, dwStatus); return( dwStatus ); }
DWORD FmpUpdateCreateResourceType( IN PVOID Buffer ) /*++
Routine Description:
GUM update handler called for creating a resource type. For NT5.1 clusters, this GUM handler does both the registry and in-memory updates as a local transaction.
Arguments:
Buffer - Buffer containing resource type information. Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PFM_RESTYPE pResType = NULL; LPWSTR lpszTypeName; LPWSTR lpszDisplayName; LPWSTR lpszDllName; DWORD dwStatus = ERROR_SUCCESS; DWORD dwLooksAlive; DWORD dwIsAlive; DWORD dwDllNameLen; DWORD dwDisplayNameLen; DWORD dwTypeNameLen; DWORD dwClusterHighestVersion; DWORD dwDisposition; HLOCALXSACTION hXsaction = NULL; HDMKEY hTypeKey = NULL;
//
// Chittur Subbaraman (chitturs) - 2/8/2000
//
// Rewrite this GUM handler as a local transaction (for NT5.1 only)
//
lpszTypeName = ( LPWSTR ) Buffer;
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResourceType, Entry for resource type %1!ws!...\n", lpszTypeName);
pResType = OmReferenceObjectById( ObjectTypeResType, lpszTypeName ); if ( pResType ) { dwStatus = ERROR_ALREADY_EXISTS; ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Resource type %1!ws! already exists, Status = %2!d!...\n", lpszTypeName, dwStatus); OmDereferenceObject( pResType ); return( dwStatus ); }
dwTypeNameLen = ( lstrlenW( lpszTypeName ) + 1 ) * sizeof( WCHAR );
lpszDisplayName = ( LPWSTR ) ( ( PCHAR ) Buffer + dwTypeNameLen );
dwDisplayNameLen = ( lstrlenW( lpszDisplayName ) + 1 ) * sizeof( WCHAR );
lpszDllName = ( LPWSTR ) ( ( PCHAR ) Buffer + dwTypeNameLen + dwDisplayNameLen );
dwDllNameLen = ( lstrlenW( lpszDllName ) + 1 ) * sizeof( WCHAR );
NmGetClusterOperationalVersion( &dwClusterHighestVersion, NULL, NULL );
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) < NT51_MAJOR_VERSION ) { goto skip_registry_updates; }
dwLooksAlive = *( DWORD UNALIGNED * ) ( ( ( PCHAR ) Buffer + dwTypeNameLen + dwDisplayNameLen + dwDllNameLen ) ); dwIsAlive = *( DWORD UNALIGNED * ) ( ( ( PCHAR ) Buffer + dwTypeNameLen + dwDisplayNameLen + dwDllNameLen + sizeof( DWORD ) ) );
//
// Start a transaction
//
hXsaction = DmBeginLocalUpdate();
if ( !hXsaction ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Failed in starting a transaction for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); return( dwStatus ); }
hTypeKey = DmLocalCreateKey( hXsaction, DmResourceTypesKey, lpszTypeName, 0, KEY_READ | KEY_WRITE, NULL, &dwDisposition ); if ( hTypeKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Failed in creating the resource types key for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); goto FnExit; }
if ( dwDisposition != REG_CREATED_NEW_KEY ) { dwStatus = ERROR_ALREADY_EXISTS; ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Duplicate resource types key exists for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); goto FnExit; }
dwStatus = DmLocalSetValue( hXsaction, hTypeKey, CLUSREG_NAME_RESTYPE_DLL_NAME, REG_SZ, ( CONST BYTE * )lpszDllName, dwDllNameLen );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Failed in setting the DLL name for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); goto FnExit; }
dwStatus = DmLocalSetValue( hXsaction, hTypeKey, CLUSREG_NAME_RESTYPE_IS_ALIVE, REG_DWORD, ( CONST BYTE * )&dwIsAlive, sizeof( DWORD ) );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Failed in setting the Is Alive interval for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); goto FnExit; }
dwStatus = DmLocalSetValue( hXsaction, hTypeKey, CLUSREG_NAME_RESTYPE_LOOKS_ALIVE, REG_DWORD, ( CONST BYTE * )&dwLooksAlive, sizeof( DWORD ) );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Failed in setting the Looks Alive interval for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); goto FnExit; }
dwStatus = DmLocalSetValue( hXsaction, hTypeKey, CLUSREG_NAME_RESTYPE_NAME, REG_SZ, ( CONST BYTE * )lpszDisplayName, dwDisplayNameLen );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResourceType, Failed in setting the display name for resource type %1!ws!, Status =%2!d!....\n", lpszTypeName, dwStatus); goto FnExit; } skip_registry_updates: pResType = FmpCreateResType( lpszTypeName );
if ( pResType != NULL ) { dwStatus = FmpRmLoadResTypeDll( pResType ); if ( dwStatus == ERROR_SUCCESS ) { pResType->State = RESTYPE_STATE_LOADS; } else { ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResourceType: Unable to load dll for resource type %1!ws!, Status=%2!u!...\n", lpszTypeName, dwStatus); //
// Some nodes may not support this resource type. So, consider
// the loading failure as success. However, log the error.
//
dwStatus = ERROR_SUCCESS; } } else { dwStatus = GetLastError(); ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResourceType: Unable to create resource type %1!ws!, Status=%2!u!...\n", lpszTypeName, dwStatus); }
FnExit: if ( hTypeKey != NULL ) { DmCloseKey( hTypeKey ); }
if ( ( dwStatus == ERROR_SUCCESS ) && ( hXsaction != NULL ) ) { DmCommitLocalUpdate( hXsaction ); } else { if ( hXsaction ) DmAbortLocalUpdate( hXsaction ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResourceType: Exit for resource type %1!ws!, Status=%2!u!...\n", lpszTypeName, dwStatus);
return( dwStatus ); }
DWORD FmpUpdateCreateResource( IN OUT PGUM_CREATE_RESOURCE pGumResource ) { /*++
Routine Description:
GUM update handler called for creating a resource. For NT5.1 clusters, this GUM handler does both the registry and in-memory updates as a local transaction.
Arguments:
pGumResource - Structure containing resource information. Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/ DWORD dwStatus = ERROR_SUCCESS; HDMKEY hResourceKey = NULL; HDMKEY hGroupKey = NULL; DWORD dwDisposition; HLOCALXSACTION hXsaction = NULL; DWORD dwClusterHighestVersion; PGUM_CREATE_RESOURCE GumResource; LPWSTR lpszResourceId = NULL; LPWSTR lpszResourceName = NULL; LPWSTR lpszResourceType = NULL; PFM_GROUP pGroup = NULL; PFM_RESTYPE pResType = NULL; DWORD dwpollIntervals = CLUSTER_RESOURCE_USE_DEFAULT_POLL_INTERVAL; DWORD dwPersistentState = 0; DWORD dwResourceTypeLen = 0; DWORD dwFlags = 0; HDMKEY hParamKey = NULL;
//
// Chittur Subbaraman (chitturs) - 1/30/2000
//
// Restructure this GUM update as a local transaction.
//
lpszResourceId = (LPWSTR)( (PCHAR) pGumResource->GroupId + pGumResource->GroupIdLen );
lpszResourceName = (LPWSTR)( (PCHAR) pGumResource->GroupId + pGumResource->GroupIdLen + pGumResource->ResourceIdLen );
pGroup = OmReferenceObjectById( ObjectTypeGroup, pGumResource->GroupId );
if ( pGroup == NULL ) { CL_LOGFAILURE( ERROR_GROUP_NOT_FOUND ); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: Group for resource %1!ws! not found.\n", lpszResourceId); return( ERROR_GROUP_NOT_FOUND ); } ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResource: Entry for resource %1!ws!...\n", lpszResourceId); //
// If we are dealing with the mixed mode cluster, don't bother to
// do these registry updates since the API layer would do it.
//
NmGetClusterOperationalVersion( &dwClusterHighestVersion, NULL, NULL );
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) < NT51_MAJOR_VERSION ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResource: Skipping registry updates for resource %1!ws!...\n", lpszResourceId); goto skip_registry_updates; }
dwResourceTypeLen = *( DWORD UNALIGNED * )( (PCHAR) pGumResource->GroupId + pGumResource->GroupIdLen + pGumResource->ResourceIdLen + (lstrlenW(lpszResourceName)+1) * sizeof(WCHAR) );
lpszResourceType = (LPWSTR)( (PCHAR) pGumResource->GroupId + pGumResource->GroupIdLen + pGumResource->ResourceIdLen + (lstrlenW(lpszResourceName)+1) * sizeof(WCHAR) + sizeof( DWORD ) ); dwFlags = *( DWORD UNALIGNED * )( (PCHAR) pGumResource->GroupId + pGumResource->GroupIdLen + pGumResource->ResourceIdLen + (lstrlenW(lpszResourceName)+1) * sizeof(WCHAR) + sizeof( DWORD ) + dwResourceTypeLen );
//
// Start a transaction
//
hXsaction = DmBeginLocalUpdate();
if ( !hXsaction ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateResource, Failed in starting a transaction for resource %1!ws!, Status =%2!d!....\n", lpszResourceId, dwStatus); OmDereferenceObject( pGroup ); return( dwStatus ); }
//
// Create the new resources key.
//
hResourceKey = DmLocalCreateKey( hXsaction, DmResourcesKey, lpszResourceId, 0, KEY_READ | KEY_WRITE, NULL, &dwDisposition ); if ( hResourceKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateCreateResource, Failed in creating the resource key for resource %1!ws!, Status =%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; } if ( dwDisposition != REG_CREATED_NEW_KEY ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource used GUID %1!ws! that already existed! This is impossible.\n", lpszResourceId); dwStatus = ERROR_ALREADY_EXISTS; goto FnExit; }
CL_ASSERT( dwDisposition == REG_CREATED_NEW_KEY );
//
// Set the resource name in the registry
//
dwStatus = DmLocalSetValue( hXsaction, hResourceKey, CLUSREG_NAME_RES_NAME, REG_SZ, (CONST BYTE *)lpszResourceName, (lstrlenW(lpszResourceName)+1)*sizeof(WCHAR) );
if( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalSetValue (resource name) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
//
// Set the resource's type in the registry
// Note we reference the resource type and use its ID
// so that the case is correct.
//
pResType = OmReferenceObjectById( ObjectTypeResType, lpszResourceType ); CL_ASSERT( pResType != NULL ); dwStatus = DmLocalSetValue( hXsaction, hResourceKey, CLUSREG_NAME_RES_TYPE, REG_SZ, (CONST BYTE *) OmObjectId( pResType ), (lstrlenW( lpszResourceType ) + 1 )*sizeof(WCHAR) ); OmDereferenceObject( pResType );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalSetValue (resource type) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
//
// Set the resource's poll intervals in the registry.
//
dwStatus = DmLocalSetValue( hXsaction, hResourceKey, CLUSREG_NAME_RES_LOOKS_ALIVE, REG_DWORD, (CONST BYTE *)&dwpollIntervals, 4 ); if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalSetValue (looks alive) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
dwStatus = DmLocalSetValue( hXsaction, hResourceKey, CLUSREG_NAME_RES_IS_ALIVE, REG_DWORD, (CONST BYTE *)&dwpollIntervals, 4);
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalSetValue (is alive) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
//
// If this resource should be started in a separate monitor, set that
// parameter now.
//
if ( dwFlags & CLUSTER_RESOURCE_SEPARATE_MONITOR ) { DWORD dwSeparateMonitor = 1;
dwStatus = DmLocalSetValue( hXsaction, hResourceKey, CLUSREG_NAME_RES_SEPARATE_MONITOR, REG_DWORD, (CONST BYTE *)&dwSeparateMonitor, sizeof( dwSeparateMonitor ) ); if ( dwStatus != ERROR_SUCCESS) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalSetValue (separate monitor) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; } }
//
// Create a Parameters key for the resource.
//
hParamKey = DmLocalCreateKey( hXsaction, hResourceKey, CLUSREG_KEYNAME_PARAMETERS, 0, KEY_READ, NULL, &dwDisposition ); if ( hParamKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalCreateKey (parameters) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); CL_LOGFAILURE( dwStatus ); goto FnExit; } else { DmCloseKey( hParamKey ); }
hGroupKey = DmOpenKey( DmGroupsKey, OmObjectId(pGroup), KEY_READ | KEY_WRITE);
if ( hGroupKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmOpenKey (group key) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
//
// Chittur Subbaraman (chitturs) - 5/25/99
//
// Make sure you set the persistent state of the resource to
// ClusterResourceOffline before you create the resource. If
// this is not done, if you create a resource in a group which
// is online, the group's persistent state value (i.e., 1 in
// this case) is inherited by the resource in FmpQueryResourceInfo
// (only the memory state is set and not the registry state and
// this was a problem as well) and if you move such a group to
// another node, it will bring the newly created resource online.
//
dwStatus = DmLocalSetValue( hXsaction, hResourceKey, CLUSREG_NAME_RES_PERSISTENT_STATE, REG_DWORD, ( CONST BYTE * )&dwPersistentState, sizeof( DWORD ) ); if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalSetValue (persistent state) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; }
//
// Add the resource to the Contains value of the specified group.
//
dwStatus = DmLocalAppendToMultiSz( hXsaction, hGroupKey, CLUSREG_NAME_GRP_CONTAINS, lpszResourceId );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: DmLocalAppendToMultiSz (contains key) for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); goto FnExit; } skip_registry_updates: FmpAcquireResourceLock();
pGumResource->Resource = FmpCreateResource( pGroup, lpszResourceId, lpszResourceName, FALSE ); if ( pGumResource->Resource == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateCreateResource: FmpCreateResource for resource %1!ws! fails, Status = %2!d!...\n", lpszResourceId, dwStatus); } else { ClusterEvent( CLUSTER_EVENT_GROUP_PROPERTY_CHANGE, pGroup ); ClusterEvent( CLUSTER_EVENT_RESOURCE_ADDED, pGumResource->Resource ); if ( pGumResource->Resource ) { OmReferenceObject( pGumResource->Resource ); FmpPostWorkItem( FM_EVENT_RESOURCE_ADDED, pGumResource->Resource, 0 ); } }
FmpReleaseResourceLock();
FnExit: if ( pGroup != NULL ) { OmDereferenceObject( pGroup ); } if ( hResourceKey != NULL ) { DmCloseKey( hResourceKey ); }
if ( hGroupKey != NULL ) { DmCloseKey( hGroupKey ); }
if ( ( dwStatus == ERROR_SUCCESS ) && ( hXsaction != NULL ) ) { DmCommitLocalUpdate( hXsaction ); } else { if ( hXsaction ) DmAbortLocalUpdate( hXsaction ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateCreateResource: Exit for resource %1!ws!, Status=%2!u!...\n", lpszResourceId, dwStatus);
return( dwStatus ); }
DWORD FmpUpdateDeleteResource( IN BOOL bSourceNode, IN LPCWSTR lpszResourceId ) /*++
Routine Description:
GUM dispatch routine for deleting a resource. For NT5.1 clusters, this is structured as as local transaction.
Arguments:
bSourceNode - Supplies whether or not this node initiated the GUM update. Not used.
lpszResourceId - Supplies the resource ID.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise.
--*/ { PFM_RESOURCE pResource = NULL; PFM_GROUP pGroup = NULL; PLIST_ENTRY pListEntry = NULL; PDEPENDENCY pDependency = NULL; PPOSSIBLE_ENTRY pPossibleEntry = NULL; DWORD dwStatus; HLOCALXSACTION hXsaction = NULL; DWORD dwClusterHighestVersion; HDMKEY pGroupKey;
//
// Chittur Subbaraman (chitturs) - 9/7/2000
//
// Structure this GUM update as a local transaction.
//
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return( ERROR_SUCCESS ); }
pResource = OmReferenceObjectById( ObjectTypeResource, lpszResourceId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmpUpdateDeleteResource: Resource %1!ws! cannot be found....\n", lpszResourceId ); return( ERROR_RESOURCE_NOT_FOUND ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateDeleteResource: Delete resource %1!ws!, address %2!lx!....\n", lpszResourceId, pResource );
//
// NOTE: It is difficult to include the checkpoint removal in a local transaction, so keep it
// out for now. Also, note that these functions MUST be called BEFORE the Resources key is
// deleted since they enumerate the values under "Resources\RegSync" and "Resources\CryptoSync".
//
if ( pResource->Group->OwnerNode == NmLocalNode ) { CpckRemoveResourceCheckpoints( pResource ); CpRemoveResourceCheckpoints( pResource ); }
//
// Start a transaction
//
hXsaction = DmBeginLocalUpdate();
if ( !hXsaction ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateDeleteResource: Failed in starting a transaction for resource %1!ws!, Status =%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; }
//
// Cannot acquire group lock here to avoid deadlocks with this current design.
//
//
// Remove all registry entries corresponding to the DependsOn list.
//
pListEntry = pResource->DependsOn.Flink; while ( pListEntry != &pResource->DependsOn ) { pDependency = CONTAINING_RECORD( pListEntry, DEPENDENCY, DependentLinkage ); CL_ASSERT( pDependency->DependentResource == pResource ); pListEntry = pListEntry->Flink; //
// Note that the removal of registry entries is done as a local transaction.
//
dwStatus = FmpRemoveResourceDependency( hXsaction, pResource, pDependency->ProviderResource ); if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateDeleteResource: Unable to remove 'DependsOn' registry entries for resource %1!ws!, Status =%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; } }
//
// Remove all registry entries corresponding to the ProvidesFor list.
//
pListEntry = pResource->ProvidesFor.Flink; while ( pListEntry != &pResource->ProvidesFor ) { pDependency = CONTAINING_RECORD( pListEntry, DEPENDENCY, ProviderLinkage ); CL_ASSERT( pDependency->ProviderResource == pResource ); pListEntry = pListEntry->Flink; //
// Note that the removal of registry entries is done as a local transaction.
//
dwStatus = FmpRemoveResourceDependency( hXsaction, pDependency->DependentResource, pResource ); if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateDeleteResource: Unable to remove 'ProvidesFor' registry entries for resource %1!ws!, Status=%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; } }
//
// If we are dealing with a Whistler-Win2K cluster, don't bother to
// do these registry updates since the API layer would do it.
//
NmGetClusterOperationalVersion( &dwClusterHighestVersion, NULL, NULL );
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) < NT51_MAJOR_VERSION ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateDeleteResource: Skipping registry updates for resource %1!ws!...\n", lpszResourceId); goto skip_registry_updates; }
dwStatus = DmLocalDeleteTree( hXsaction, DmResourcesKey, OmObjectId( pResource ) );
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateDeleteResource: Unable to remove 'Resources' tree for resource %1!ws!, Status=%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; }
pGroupKey = DmOpenKey( DmGroupsKey, OmObjectId( pResource->Group ), KEY_READ | KEY_SET_VALUE );
if ( pGroupKey == NULL ) { dwStatus = GetLastError(); ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateDeleteResource: Unable to find 'Groups' key for resource %1!ws!, Status=%2!d!....\n", lpszResourceId, dwStatus); goto FnExit; }
dwStatus = DmLocalRemoveFromMultiSz( hXsaction, pGroupKey, CLUSREG_NAME_GRP_CONTAINS, OmObjectId( pResource ) );
DmCloseKey( pGroupKey );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateDeleteResource: Unable to remove contains list for resource %1!ws! in group %2!ws!, Status=%3!d!....\n", lpszResourceId, OmObjectId( pResource->Group ), dwStatus); goto FnExit; } skip_registry_updates: //
// Remove all list entries corresponding to the DependsOn list.
//
pListEntry = pResource->DependsOn.Flink; while ( pListEntry != &pResource->DependsOn ) { pDependency = CONTAINING_RECORD( pListEntry, DEPENDENCY, DependentLinkage ); pListEntry = pListEntry->Flink; RemoveEntryList( &pDependency->ProviderLinkage ); RemoveEntryList( &pDependency->DependentLinkage ); OmDereferenceObject( pDependency->DependentResource ); OmDereferenceObject( pDependency->ProviderResource ); LocalFree( pDependency ); }
//
// Remove all list entries corresponding to the ProvidesFor list.
//
pListEntry = pResource->ProvidesFor.Flink; while ( pListEntry != &pResource->ProvidesFor ) { pDependency = CONTAINING_RECORD( pListEntry, DEPENDENCY, ProviderLinkage ); pListEntry = pListEntry->Flink; RemoveEntryList( &pDependency->ProviderLinkage ); RemoveEntryList( &pDependency->DependentLinkage ); OmDereferenceObject( pDependency->DependentResource ); OmDereferenceObject( pDependency->ProviderResource ); LocalFree( pDependency ); } //
// Remove all entries from the possible owners list.
//
while ( !IsListEmpty( &pResource->PossibleOwners ) ) { pListEntry = RemoveHeadList( &pResource->PossibleOwners ); pPossibleEntry = CONTAINING_RECORD( pListEntry, POSSIBLE_ENTRY, PossibleLinkage ); OmDereferenceObject( pPossibleEntry->PossibleNode ); LocalFree( pPossibleEntry ); }
//
// Remove this resource from the Contains list.
//
RemoveEntryList( &pResource->ContainsLinkage );
OmDereferenceObject( pResource );
//
// Close the resource's registry key.
//
DmRundownList( &pResource->DmRundownList ); if ( pResource->RegistryKey != NULL ) { DmCloseKey( pResource->RegistryKey ); pResource->RegistryKey = NULL; }
//
// SS: we do not delete the reference to the resource here
// since we will shortly have to add one before posting a notification
// to the fm worker thread.
//
// Post a work item to close the resource in the resource handler.
// Note that this must be done asynchronously as we cannot call
// the resource monitor from a GUM handler. If we do, resources
// do funny things and make deadlocks.
//
FmpPostWorkItem( FM_EVENT_RESOURCE_DELETED, pResource, 0 );
//
// Decrement resource type reference.
//
if ( pResource->Type != NULL ) { OmDereferenceObject( pResource->Type ); pResource->Type = NULL; }
//
// Remove the resource from the resource list.
//
dwStatus = OmRemoveObject( pResource );
ClusterEvent( CLUSTER_EVENT_RESOURCE_DELETED, pResource ); ClusterEvent( CLUSTER_EVENT_GROUP_PROPERTY_CHANGE, pResource->Group );
//
// Mark the resource as deleted
//
pResource->dwStructState = FM_RESOURCE_STRUCT_MARKED_FOR_DELETE;
FnExit: OmDereferenceObject( pResource );
if ( ( dwStatus == ERROR_SUCCESS ) && ( hXsaction != NULL ) ) { DmCommitLocalUpdate( hXsaction ); } else { if ( hXsaction ) DmAbortLocalUpdate( hXsaction ); }
ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateDeleteResource: Exit for resource %1!ws!, Status=%2!u!...\n", lpszResourceId, dwStatus);
return( dwStatus ); } // FmpUpdateDeleteResource
DWORD FmpUpdateUseRandomizedNodeListForGroups( IN BOOL SourceNode, IN LPCWSTR pszNodeId, IN PFM_GROUP_NODE_LIST pGroupNodeList ) /*++
Routine Description:
GUM dispatch routine for using a randomized preferred list for group ownership on node down.
Arguments:
bSourceNode - Supplies whether or not this node initiated the GUM update. Not used.
pszNodeId - Supplies the ID of the node that is down.
pGroupNodeList - Randomized preferred node list for groups.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise.
--*/ { PNM_NODE pNode = NULL; DWORD dwStatus = ERROR_SUCCESS;
//
// Chittur Subbaraman (chitturs) - 4/19/2001
//
// If FM groups are not fully initialized or FM is shutting down, then
// don't do anything.
//
if ( !FmpFMGroupsInited || FmpShutdown ) { return( ERROR_SUCCESS ); }
pNode = OmReferenceObjectById( ObjectTypeNode, pszNodeId );
if ( !pNode ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateUseRandomizedNodeListForGroups: %1!ws! node not found...\n", pszNodeId); //
// Should we return failure here, is evict of a node synchronized with everything
//
goto FnExit; }
//
// If this update has already been seen after the node down, ignore this one
//
if ( gFmpNodeArray[NmGetNodeId(pNode)].dwNodeDownProcessingInProgress == 0 ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmpUpdateUseRandomizedNodeListForGroups: %1!ws! node down has been processed already...\n", pszNodeId); goto FnExit; }
//
// Assign ownership to all groups owned by the dead node
//
dwStatus = FmpAssignOwnersToGroups( pNode, NULL, pGroupNodeList );
if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmpUpdateUseRandomizedNodeListForGroups: FmpAssignOwnersToGroups failed %1!d!\n", dwStatus); }
//
// Mark that the node down processing has been done
//
gFmpNodeArray[NmGetNodeId(pNode)].dwNodeDownProcessingInProgress = 0; FnExit: if ( pNode ) OmDereferenceObject( pNode );
return( dwStatus ); }// FmpUpdateUseRandomizedNodeListForGroups
|