/*++ Copyright (c) 1996 Microsoft Corporation Module Name: recv.c Abstract: Cluster FM remote receive request routines. Author: Rod Gamache (rodga) 21-Mar-1996 Revision History: --*/ #include "fmp.h" #define LOG_MODULE RECV // // Global data // extern BOOL FmpOkayToProceed; // // Local function prototypes // BOOL FmpEnumMyGroups( IN OUT PGROUP_ENUM *Enum, IN LPDWORD Allocated, IN PFM_GROUP Group, IN LPCWSTR Id ); BOOL FmpEnumResources( IN OUT PRESOURCE_ENUM *Enum, IN LPDWORD Allocated, IN PFM_RESOURCE Resource, IN LPCWSTR Id ); error_status_t s_FmsOnlineGroupRequest( IN handle_t IDL_handle, IN LPCWSTR GroupId ) /*++ Routine Description: Receives a Group Online Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. GroupId - The Id of the Group to bring online. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_GROUP group; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsOnlineGroupRequest: To bring group '%1!ws!' online\n", GroupId); // // Find the specified group. // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsOnlineGroupRequest: Could not find Group %1!ws!\n", GroupId); return(ERROR_GROUP_NOT_FOUND); } // // Only one of these requests per group at a time. // FmpAcquireLocalGroupLock( group ); // // Now bring it online. // if ( group->OwnerNode == NmLocalNode ) { // // Set the Group's Current State. // FmpSetGroupPersistentState( group, ClusterGroupOnline ); status = FmpOnlineGroup( group, TRUE ); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FmpReleaseLocalGroupLock( group ); OmDereferenceObject( group ); return(status); } // FmsOnlineGroupRequest error_status_t s_FmsOfflineGroupRequest( IN handle_t IDL_handle, IN LPCWSTR GroupId ) /*++ Routine Description: Receives a Group Offline Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. GroupId - The Id of the Group to bring offline. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_GROUP group; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsOfflineGroupRequest: To take group '%1!ws!' offline\n", GroupId); // // Find the specified group. // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsOfflineGroupRequest: Could not find Group %1!ws!\n", GroupId); return(ERROR_GROUP_NOT_FOUND); } // // Now take it offline if we are the owner. // if ( group->OwnerNode == NmLocalNode ) { // // Set the Group's Current State. // FmpSetGroupPersistentState( group, ClusterGroupOffline ); status = FmpOfflineGroup( group, FALSE, TRUE ); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } OmDereferenceObject( group ); return(status); } // FmsOfflineGroupRequest error_status_t s_FmsMoveGroupRequest( IN handle_t IDL_handle, IN LPCWSTR GroupId, IN LPCWSTR DestinationNode OPTIONAL ) /*++ Routine Description: Receives a Group Move Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. GroupId - The Id of the Group to move. DestinationNode - The Id of the node to move the Group to. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_GROUP group; PNM_NODE node = NULL; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsMoveGroupRequest: To move group '%1!ws!'\n", GroupId); // // // Find the specified group. // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsMoveGroupRequest: Could not find Group %1!ws!\n", GroupId); return(ERROR_GROUP_NOT_FOUND); } // // Find the specified destination node. // if ( ARGUMENT_PRESENT( DestinationNode ) ) { node = OmReferenceObjectById( ObjectTypeNode, DestinationNode ); if ( node == NULL ) { OmDereferenceObject( group ); ClRtlLogPrint(LOG_NOISE,"[FM] FmsMoveGroupRequest: Could not find Node %1!ws!\n", DestinationNode); return(ERROR_HOST_NODE_NOT_AVAILABLE); } } // // Make sure we are the owner of the Group. // FmpAcquireLocalGroupLock( group ); if ( group->OwnerNode == NmLocalNode ) { status = FmpDoMoveGroup( group, node, TRUE ); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FmpReleaseLocalGroupLock( group ); OmDereferenceObject( group ); if ( node != NULL ) { OmDereferenceObject( node ); } return(status); } // FmsMoveGroupRequest error_status_t s_FmsTakeGroupRequest( IN handle_t IDL_handle, IN LPCWSTR GroupId, IN PRESOURCE_ENUM ResourceList ) /*++ Routine Description: Receives a Take Group Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. GroupId - The Id of the Group to take locally. ResourceList - The list of resources and their states. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_GROUP group; DWORD status = ERROR_SUCCESS; //SS: removing this check from here //FmpTakeGroupRequest does this check since if this call returns a failure, //the intended owner needs to be reset to invalidnode to avoid inconsistencies //FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsTakeGroupRequest: To take group '%1!ws!'.\n", GroupId ); // // // Find the specified group. // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsTakeGroupRequest: Could not find Group %1!ws!\n", GroupId); if ( !FmpFMOnline ) { return(ERROR_CLUSTER_NODE_NOT_READY); } return(ERROR_GROUP_NOT_FOUND); } status = FmpTakeGroupRequest(group, ResourceList); OmDereferenceObject(group); return(status); } // FmsTakeGroupRequest error_status_t s_FmsOnlineResourceRequest( IN handle_t IDL_handle, IN LPCWSTR ResourceId ) /*++ Routine Description: Receives a Resource Online Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring online. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE resource; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsOnlineResourceRequest: To bring resource '%1!ws!' online\n", ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsOnlineResourceRequest: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } FmpAcquireLocalResourceLock( resource ); if (!(resource->QuorumResource) && !FmpInPreferredList( resource->Group, resource->Group->OwnerNode, TRUE, resource ) ) { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; goto FnExit; } // // Now bring it online. // CL_ASSERT( resource->Group != NULL ); if ( resource->Group->OwnerNode == NmLocalNode ) { // // This can only be invoked through the API, so force all // resources online. // status = FmOnlineResource( resource ); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FnExit: FmpReleaseLocalResourceLock( resource ); OmDereferenceObject( resource ); return(status); } // FmsOnlineResourceRequest error_status_t s_FmsOfflineResourceRequest( IN handle_t IDL_handle, IN LPCWSTR ResourceId ) /*++ Routine Description: Receives a Resource Offline Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring offline. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE resource; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsOfflineResourceRequest: To take resource '%1!ws!' offline\n", ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsOfflineResourceRequest: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } FmpAcquireLocalResourceLock(resource); // // Now take it offline if we are the owner. // CL_ASSERT( resource->Group != NULL ); if ( resource->Group->OwnerNode != NmLocalNode ) { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; goto FnExit; } //else handle it locally status = FmOfflineResource( resource ); FnExit: FmpReleaseLocalResourceLock(resource); OmDereferenceObject( resource ); return(status); } // FmsOfflineResourceRequest error_status_t s_FmsChangeResourceNode( IN handle_t IDL_handle, IN LPCWSTR ResourceId, IN LPCWSTR NodeId, IN BOOL Add ) /*++ Routine Description: Receives a Resource change node request from a remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to change a node. NodeId - The node id of the node to add or remove. Add - Indicates whether to add or remove the node. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE resource; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsChangeResourceNode: To %1!ws! node %2!ws! to/from resource '%3!ws!'.\n", Add ? L"Add" : L"Remove", NodeId, ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsChangeResourceNode: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } FmpAcquireLocalResourceLock( resource ); status = FmpChangeResourceNode(resource, NodeId, Add); FmpReleaseLocalResourceLock( resource ); OmDereferenceObject( resource ); return(status); } // FmsChangeResourceNode error_status_t s_FmsArbitrateResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId ) /*++ Routine Description: Arbitrates a Resource for a remote system. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring online. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE resource; DWORD status; // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsArbitrateResource: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } status = FmpRmArbitrateResource( resource ); OmDereferenceObject( resource ); return(status); } // FmsArbitrateResource error_status_t s_FmsQueryOwnedGroups( IN handle_t IDL_handle, OUT PGROUP_ENUM *OwnedGroups, OUT PRESOURCE_ENUM *OwnedResources ) /*++ Routine Description: Server side used to propagate FM state to a joining node. Arguments: IDL_handle - Supplies RPC binding handle, not used. OwnedGroups - Returns the list of groups owned by this node and their state. OwnedResources - Returns the list of resources contained by groups owned by this node and their state. Return Value: ERROR_SUCCESS if successful Win32 error otherwise. --*/ { DWORD status = ERROR_SUCCESS; DWORD allocated; PGROUP_ENUM groupEnum = NULL; PFM_GROUP group; PRESOURCE_ENUM resourceEnum = NULL; PFM_RESOURCE resource; DWORD i; allocated = ENUM_GROW_SIZE; groupEnum = MIDL_user_allocate(GROUP_SIZE(allocated)); if ( groupEnum == NULL ) { CL_LOGFAILURE(ERROR_NOT_ENOUGH_MEMORY); return(ERROR_NOT_ENOUGH_MEMORY); } groupEnum->EntryCount = 0; // // Enumerate all groups // OmEnumObjects( ObjectTypeGroup, FmpEnumMyGroups, &groupEnum, &allocated ); // // Enumerate all the resources in each group. // allocated = ENUM_GROW_SIZE; resourceEnum = MIDL_user_allocate(RESOURCE_SIZE(allocated)); if (resourceEnum == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; CL_LOGFAILURE(status); goto error_exit; } resourceEnum->EntryCount = 0; for (i=0; i < groupEnum->EntryCount; i++) { // // Get the group given its name. // group = OmReferenceObjectById( ObjectTypeGroup, groupEnum->Entry[i].Id ); if (group == NULL) { continue; } // // Enumerate all the resources in this group. // status = FmpEnumerateGroupResources(group, FmpEnumResources, &resourceEnum, &allocated); if ( status != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsQueryOwnedGroups: Failed group '%1!ws!', status %2!u!.\n", OmObjectId(group), status); } OmDereferenceObject(group); } *OwnedGroups = groupEnum; *OwnedResources = resourceEnum; return(ERROR_SUCCESS); error_exit: if (groupEnum != NULL) { // // Free up group enum // for (i=0; i < groupEnum->EntryCount; i++) { MIDL_user_free(groupEnum->Entry[i].Id); } MIDL_user_free(groupEnum); } return(status); } error_status_t s_FmsFailResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId ) /*++ Routine Description: Receives a Resource Fail Request from a remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to fail. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE resource; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsFailResource: To fail resource '%1!ws!'.\n", ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsFailResource: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } FmpAcquireLocalResourceLock( resource ); // // Now fail it. // if ( resource->Group->OwnerNode == NmLocalNode ) { status = FmpRmFailResource( resource ); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FmpReleaseLocalResourceLock( resource ); return(status); } // FmsFailResource error_status_t s_FmsCreateResource( IN handle_t IDL_handle, IN LPCWSTR GroupId, IN LPWSTR ResourceId, IN LPCWSTR ResourceName ) /*++ Routine Description: Receives a Create Resource Request from a remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. GroupId - The Id of the Group to create the resource inside. ResourceId - The Id of the Resource to create. ResourceName - The name of the Resource to create. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. Notes: The Resource lock is acquired to synchronize access to the resource. This satisfies locking the resource on all nodes in the cluster... so long as the local node is the owner of the resource. --*/ { PFM_GROUP group; DWORD status; PGUM_CREATE_RESOURCE gumResource; DWORD groupIdLen; DWORD resourceIdLen; DWORD resourceNameLen; DWORD bufSize; HDMKEY resourceKey; HDMKEY paramsKey; DWORD disposition; ClRtlLogPrint(LOG_NOISE, "[FM] FmsCreateResource: To create resource '%1!ws!'\n", ResourceId); // // Find the specified group. // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsCreateResource: Could not find Group %1!ws!\n", GroupId); return(ERROR_GROUP_NOT_FOUND); } FmpAcquireLocalGroupLock( group ); // // Now delete it on all nodes in the cluster if we are the owner. // if ( group->OwnerNode == NmLocalNode ) { // // Allocate a message buffer. // groupIdLen = (lstrlenW(GroupId)+1) * sizeof(WCHAR); resourceIdLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR); resourceNameLen = (lstrlenW(ResourceName)+1) * sizeof(WCHAR); bufSize = sizeof(GUM_CREATE_RESOURCE) - sizeof(WCHAR) + groupIdLen + resourceIdLen + resourceNameLen; gumResource = LocalAlloc(LMEM_FIXED, bufSize); if (gumResource == NULL) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmsCreateResource: Unable to allocate memory for resource %1!ws!\n", ResourceName); return(ERROR_NOT_ENOUGH_MEMORY); } // // Fill in message buffer. // gumResource->Resource = NULL; gumResource->GroupIdLen = groupIdLen; gumResource->ResourceIdLen = resourceIdLen; CopyMemory(gumResource->GroupId, GroupId, groupIdLen); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen, ResourceId, resourceIdLen); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen + resourceIdLen, ResourceName, resourceNameLen); // // Send message. // status = GumSendUpdate(GumUpdateFailoverManager, FmUpdateCreateResource, bufSize, gumResource); if ( ( status == ERROR_SUCCESS ) && ( gumResource->Resource != NULL ) ) FmpCleanupPossibleNodeList(gumResource->Resource); LocalFree(gumResource); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FmpReleaseLocalGroupLock( group ); return(status); } // FmsCreateResource error_status_t s_FmsDeleteResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId ) /*++ Routine Description: Receives a Delete Resource Request from a remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to delete. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. Notes: The Resource lock is acquired to synchronize access to the resource. This satisfies locking the resource on all nodes in the cluster... so long as the local node is the owner of the resource. --*/ { PFM_RESOURCE resource; DWORD status; DWORD resourceLen; FmpMustBeOnline(); ClRtlLogPrint(LOG_NOISE, "[FM] FmsDeleteResource: To delete resource '%1!ws!'\n", ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsDeleteResource: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } FmpAcquireLocalResourceLock( resource ); // // Now delete it on all nodes in the cluster if we are the owner. // if ( resource->Group->OwnerNode == NmLocalNode ) { // // Check if this is the quorum resource. // if ( resource->QuorumResource ) { status = ERROR_QUORUM_RESOURCE; goto FnExit; } //other core resources cannot be deleted either if (resource->ExFlags & CLUS_FLAG_CORE) { status = ERROR_CORE_RESOURCE; goto FnExit; } // // Check the state of the resource, before attempting to delete it. // It must be offline or failed in order to perform the delete. // if ((resource->State != ClusterResourceOffline) && (resource->State != ClusterResourceFailed)) { status = ERROR_RESOURCE_ONLINE; goto FnExit; } // // Check whether this resource provides for any other resources. // If so, it cannot be deleted. // if (!IsListEmpty(&resource->ProvidesFor)) { status = ERROR_DEPENDENT_RESOURCE_EXISTS; goto FnExit; } if (resource->Group->MovingList) { status = ERROR_INVALID_STATE; goto FnExit; } resourceLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR); FmpBroadcastDeleteControl(resource); // // Send message. // status = GumSendUpdateEx(GumUpdateFailoverManager, FmUpdateDeleteResource, 1, resourceLen, ResourceId); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FnExit: FmpReleaseLocalResourceLock( resource ); return(status); } // FmsDeleteResource BOOL FmpEnumMyGroups( IN OUT PGROUP_ENUM *Enum, IN LPDWORD Allocated, IN PFM_GROUP Group, IN LPCWSTR Id ) /*++ Routine Description: Worker callback routine for the enumeration of Groups. This routine adds the specified Group to the list that is being generated if it is owned by the local system. Arguments: Enum - The Group Enumeration list. Can be an output if a new list is allocated. Allocated - The current number of allocated entries in Enum. Group - The Group object being enumerated. Id - The Id of the Group object being enumerated. Returns: TRUE - to indicate that the enumeration should continue. --*/ { PGROUP_ENUM groupEnum; PGROUP_ENUM newEnum; DWORD newAllocated; DWORD index; LPWSTR newId; CLUSTER_GROUP_STATE state; // // If we don't own the Group, return now. // if (Group->OwnerNode != NmLocalNode) { return(TRUE); } groupEnum = *Enum; if ( groupEnum->EntryCount >= *Allocated ) { // // Time to grow the GROUP_ENUM // newAllocated = *Allocated + ENUM_GROW_SIZE; newEnum = MIDL_user_allocate(GROUP_SIZE(newAllocated)); if ( newEnum == NULL ) { return(FALSE); } CopyMemory(newEnum, groupEnum, GROUP_SIZE(*Allocated)); *Allocated = newAllocated; *Enum = newEnum; MIDL_user_free(groupEnum); groupEnum = newEnum; } // // Initialize new entry // newId = MIDL_user_allocate((lstrlenW(Id)+1) * sizeof(WCHAR)); if ( newId == NULL ) { return(FALSE); } lstrcpyW(newId, Id); groupEnum->Entry[groupEnum->EntryCount].Id = newId; groupEnum->Entry[groupEnum->EntryCount].State = Group->State; groupEnum->Entry[groupEnum->EntryCount].StateSequence = Group->StateSequence; ++groupEnum->EntryCount; return(TRUE); } // FmpEnumMyGroups BOOL FmpEnumResources( IN OUT PRESOURCE_ENUM *Enum, IN LPDWORD Allocated, IN PFM_RESOURCE Resource, IN LPCWSTR Id ) /*++ Routine Description: Worker callback routine for the enumeration of Group resources. This routine adds the specified resource to the list that is being generated. Arguments: Enum - The resource enumeration list. Can be an output if a new list is allocated. Allocated - The current number of allocated entries in Enum. Resource - The Resource object being enumerated. Id - The Id of the resource object being enumerated. Returns: TRUE - to indicate that the enumeration should continue. FALSE - to indicate that the enumeration should not continue. --*/ { PRESOURCE_ENUM resourceEnum; PRESOURCE_ENUM newEnum; DWORD newAllocated; DWORD index; LPWSTR newId; resourceEnum = *Enum; if ( resourceEnum->EntryCount >= *Allocated ) { // // Time to grow the RESOURCE_ENUM // newAllocated = *Allocated + ENUM_GROW_SIZE; newEnum = MIDL_user_allocate(RESOURCE_SIZE(newAllocated)); if ( newEnum == NULL ) { return(FALSE); } CopyMemory(newEnum, resourceEnum, RESOURCE_SIZE(*Allocated)); *Allocated = newAllocated; *Enum = newEnum; MIDL_user_free(resourceEnum); resourceEnum = newEnum; } // // Initialize new entry // newId = MIDL_user_allocate((lstrlenW(Id)+1) * sizeof(WCHAR)); if ( newId == NULL ) { return(FALSE); } lstrcpyW(newId, Id); resourceEnum->Entry[resourceEnum->EntryCount].Id = newId; resourceEnum->Entry[resourceEnum->EntryCount].State = Resource->State; resourceEnum->Entry[resourceEnum->EntryCount].StateSequence = Resource->StateSequence; ++resourceEnum->EntryCount; return(TRUE); } // FmpEnumResources error_status_t s_FmsResourceControl( IN handle_t IDL_handle, IN LPCWSTR ResourceId, IN DWORD ControlCode, IN PUCHAR InBuffer, IN DWORD InBufferSize, OUT PUCHAR OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesReturned, OUT LPDWORD Required ) /*++ Routine Description: This routine passes a resource control request from a remote system. Arguments: IDL_handle - the binding context - not used ResourceId - the Id of the Resource to control ControlCode - the control code for this request InBuffer - the input buffer InBufferSize - the size of the input buffer OutBuffer - the output buffer OutBufferSize - the size of the output buffer ByteReturned - the number of bytes returned in the output buffer Required - the number of bytes required if OutBuffer is not big enough. Returns: ERROR_SUCCESS if successful. Win32 error code on failure. --*/ { PFM_RESOURCE resource; DWORD status; DWORD bufSize; DWORD dataLength; CLUSPROP_BUFFER_HELPER props; // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsResourceControl: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } // // Since lpInBuffer is declared as [unique] in the IDL file, it can be NULL while dwBufferSize // is non-zero and vice-versa. To avoid confusion in the following code, we make them consistent // right here. // if ( InBuffer == NULL ) { InBufferSize = 0; } else if ( InBufferSize == 0 ) { InBuffer = NULL; } CL_ASSERT( resource->Group != NULL ); status = FmpRmResourceControl( resource, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required ); OmDereferenceObject(resource); return(status); } // FmsResourceControl error_status_t s_FmsResourceTypeControl( IN handle_t IDL_handle, IN LPCWSTR ResourceTypeName, IN DWORD ControlCode, IN PUCHAR InBuffer, IN DWORD InBufferSize, OUT PUCHAR OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesReturned, OUT LPDWORD Required ) /*++ Routine Description: This routine passes a resource control request from a remote system. Arguments: IDL_handle - the binding context - not used ResourceTypeName - the name of the Resource Type to control ControlCode - the control code for this request InBuffer - the input buffer InBufferSize - the size of the input buffer OutBuffer - the output buffer OutBufferSize - the size of the output buffer ByteReturned - the number of bytes returned in the output buffer Required - the number of bytes required if OutBuffer is not big enough. Returns: ERROR_SUCCESS if successful. Win32 error code on failure. --*/ { PFM_RESOURCE resource; DWORD status; // // Since lpInBuffer is declared as [unique] in the IDL file, it can be NULL while dwBufferSize // is non-zero and vice-versa. To avoid confusion in the following code, we make them consistent // right here. // if ( InBuffer == NULL ) { InBufferSize = 0; } else if ( InBufferSize == 0 ) { InBuffer = NULL; } status = FmpRmResourceTypeControl( ResourceTypeName, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required ); if ((status == ERROR_MOD_NOT_FOUND) || (status == ERROR_PROC_NOT_FOUND)) { FmpRemovePossibleNodeForResType(ResourceTypeName, NmLocalNode); } #if 0 if ( ((status == ERROR_SUCCESS) || (status == ERROR_RESOURCE_PROPERTIES_STORED)) && (ControlCode & CLCTL_MODIFY_MASK) ) { ClusterEvent( CLUSTER_EVENT_RESTYPE_PROPERTY_CHANGE, XXX ); } #endif return(status); } // FmsResourceTypeControl error_status_t s_FmsGroupControl( IN handle_t IDL_handle, IN LPCWSTR GroupId, IN DWORD ControlCode, IN PUCHAR InBuffer, IN DWORD InBufferSize, OUT PUCHAR OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesReturned, OUT LPDWORD Required ) /*++ Routine Description: This routine processes a group control request from a remote system. Arguments: IDL_handle - the binding context - not used GroupId - the Id of the Group to control ControlCode - the control code for this request InBuffer - the input buffer InBufferSize - the size of the input buffer OutBuffer - the output buffer OutBufferSize - the size of the output buffer ByteReturned - the number of bytes returned in the output buffer Required - the number of bytes required if OutBuffer is not big enough. Returns: ERROR_SUCCESS if successful. Win32 error code on failure. --*/ { PFM_GROUP group; DWORD status; // // Find the specified group // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsGroupControl: Could not find Group %1!ws!\n", GroupId); return(ERROR_GROUP_NOT_FOUND); } // // Since lpInBuffer is declared as [unique] in the IDL file, it can be NULL while dwBufferSize // is non-zero and vice-versa. To avoid confusion in the following code, we make them consistent // right here. // if ( InBuffer == NULL ) { InBufferSize = 0; } else if ( InBufferSize == 0 ) { InBuffer = NULL; } status = FmpGroupControl(group, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required); OmDereferenceObject(group); return(status); } // FmsGroupControl error_status_t s_FmsPrepareQuorumResChange( IN handle_t IDL_handle, IN LPCWSTR ResourceId, IN LPCWSTR lpszQuoLogPath, IN DWORD dwMaxQuoLogSize ) /*++ Routine Description: Receives a request to prepare a resource to become the quorum resource. A resource must be able to support a quorum log file and registry replication files. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the resource to be made the quorum resource. lpszQuoLogPath - The path where the logs must be created. dwMaxQuoLogSize - The maximum size of the quorum log file. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE pResource=NULL; DWORD Status; ClRtlLogPrint(LOG_NOISE, "[FM] FmsPrepareQuorumResChange: Entry\r\n"); // Find the specified resource. // pResource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsPrepareQuorumResource: Could not find Resource %1!ws!\n", ResourceId); Status = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } CL_ASSERT( pResource->Group != NULL ); if ( pResource->Group->OwnerNode == NmLocalNode ) Status = FmpPrepareQuorumResChange(pResource, lpszQuoLogPath, dwMaxQuoLogSize); else Status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; FnExit: if (pResource) OmDereferenceObject( pResource ); return(Status); } // FmsPrepareQuorumResChange error_status_t s_FmsCompleteQuorumResChange( IN handle_t IDL_handle, IN LPCWSTR lpszOldQuoResId, IN LPCWSTR lpszOldQuoLogPath ) /*++ Routine Description: Receives a request to clean up quorum logging and cluster registry files on the old quorum resource. Arguments: IDL_handle - The binding context - not used. lpszOldQuoResId - The Id of the resource to be made the quorum resource. lpszQuoLogPath - The path where the logs must be created. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE pResource=NULL; DWORD Status; ClRtlLogPrint(LOG_NOISE, "[FM] FmsCompleteQuorumResChange: Entry\r\n"); // Find the specified resource. // pResource = OmReferenceObjectById( ObjectTypeResource, lpszOldQuoResId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsCompleteQuorumResource: Could not find Resource %1!ws!\n", lpszOldQuoResId); Status = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } CL_ASSERT( pResource->Group != NULL ); if ( pResource->Group->OwnerNode == NmLocalNode ) Status = FmpCompleteQuorumResChange(lpszOldQuoResId, lpszOldQuoLogPath); else Status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; FnExit: if (pResource) OmDereferenceObject( pResource ); return(Status); } // FmsCompleteQuorumResChange error_status_t s_FmsQuoNodeOnlineResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId, IN LPCWSTR NodeId, OUT LPDWORD State ) /*++ Routine Description: Receives a RmResourceOnline request from (THE) remote system and returns status for that request. This system must own the quorum resource. This is the first half of the sling shot. We acquire locks and then RPC back to the originating node with a request to perform the online. This request is only valid for non-quorum resources. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring online. NodeId - The Id of the Node that originated the request. State - Returns the new state of the resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { //not used return(ERROR_INVALID_FUNCTION); } // FmsQuoNodeOnlineResource error_status_t s_FmsQuoNodeOfflineResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId, IN LPCWSTR NodeId, OUT LPDWORD State ) /*++ Routine Description: Receives a Resource Offline Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring offline. NodeId - The Id of the Node that originated the request. State - Returns the new state of the resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { //not used return(ERROR_INVALID_FUNCTION); }// FmsQuoNodeOfflineResource error_status_t s_FmsRmOnlineResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId, OUT LPDWORD pdwState ) /*++ Routine Description: Receives a RmResourceOnline request from quorum node and returns status for that request. This system was the originator of the original online request. This is the second half of the sling shot. It just does the online request. This request is only valid for non-quorum resources. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring online. State - Returns the new state of the resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. Notes: We can't acquire any locks... but the originating thread has the lock held for us. --*/ { PFM_RESOURCE resource; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRmOnlineResource: To bring resource '%1!ws!' online\n", ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRmOnlineResource: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } // // This must not be done on the quorum resource, and the local system // must not own the quorum resource. We'll assume that the quorum // resource migrated while we were performng this request. // CL_ASSERT( gpQuoResource != NULL ); CL_ASSERT( gpQuoResource->Group != NULL ); CL_ASSERT( gpQuoResource->Group->OwnerNode != NULL ); if ( resource->QuorumResource || (gpQuoResource->Group->OwnerNode == NmLocalNode) ) { OmDereferenceObject( resource ); return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER); } // // The local node must own the resource. // CL_ASSERT( resource->Group != NULL ); CL_ASSERT( resource->Group->OwnerNode != NULL ); if ( resource->Group->OwnerNode != NmLocalNode ) { OmDereferenceObject( resource ); return(ERROR_RESOURCE_NOT_AVAILABLE); } // // Just call the function that does the work. // OmNotifyCb( resource, NOTIFY_RESOURCE_PREONLINE ); status = RmOnlineResource( resource->Id, pdwState ); //call the synchronous notifications on the resource FmpCallResourceNotifyCb(resource, *pdwState); OmDereferenceObject( resource ); return(status); } // FmsRmOnlineResource error_status_t s_FmsRmOfflineResource( IN handle_t IDL_handle, IN LPCWSTR ResourceId, OUT LPDWORD pdwState ) /*++ Routine Description: Receives a Resource Offline Request from (THE) remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the Resource to bring offline. State - Returns the new state of the resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. Notes: We can't acquire any locks... but the originating thread has the lock held for us. --*/ { PFM_RESOURCE resource; DWORD status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRmOfflineResource: To take resource '%1!ws!' offline\n", ResourceId); // // Find the specified resource. // resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRmOfflineResource: Could not find Resource %1!ws!\n", ResourceId); return(ERROR_RESOURCE_NOT_FOUND); } // // This must not be done on the quorum resource, and the local system // must not own the quorum resource. We'll assume that the quorum // resource migrated while we were performng this request. // CL_ASSERT( gpQuoResource != NULL ); CL_ASSERT( gpQuoResource->Group != NULL ); CL_ASSERT( gpQuoResource->Group->OwnerNode != NULL ); if ( resource->QuorumResource || (gpQuoResource->Group->OwnerNode == NmLocalNode) ) { OmDereferenceObject( resource ); return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER); } // // The local node must own the resource. // CL_ASSERT( resource->Group != NULL ); CL_ASSERT( resource->Group->OwnerNode != NULL ); if ( resource->Group->OwnerNode != NmLocalNode ) { OmDereferenceObject( resource ); return(ERROR_RESOURCE_NOT_AVAILABLE); } // // Just call the function that does the work. // OmNotifyCb( resource, NOTIFY_RESOURCE_PREOFFLINE ); status = RmOfflineResource( resource->Id, pdwState ); //call the post offline obj synchronous notifications FmpCallResourceNotifyCb(resource, *pdwState); OmDereferenceObject( resource ); return(status); } // FmsRmOfflineResource error_status_t s_FmsBackupClusterDatabase( IN handle_t IDL_handle, IN LPCWSTR ResourceId, IN LPCWSTR lpszPathName ) /*++ Routine Description: Receives a request to backup the quorum log file and the checkpoint file Arguments: IDL_handle - The binding context - not used. ResourceId - The Id of the quorum resource lpszPathName - The directory path name where the files have to be backed up. This path must be visible to the node on which the quorum resource is online. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE pResource = NULL; DWORD Status; FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsBackupClusterDatabase: Entry...\r\n"); // // Chittur Subbaraman (chitturs) - 10/12/1998 // // Find the specified quorum resource // pResource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsBackupClusterDatabase: Could not find Resource %1!ws!\n", ResourceId); Status = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } FmpAcquireLocalResourceLock( pResource ); CL_ASSERT( pResource->Group != NULL ); // // Make sure the local node owns the quorum resource // if ( pResource->Group->OwnerNode == NmLocalNode ) { Status = FmpBackupClusterDatabase( pResource, lpszPathName ); } else { Status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsBackupClusterDatabase: This node is not the quorum resource owner...\n" ); } FmpReleaseLocalResourceLock( pResource ); FnExit: if ( pResource ) OmDereferenceObject( pResource ); return( Status ); } // FmsBackupClusterDatabase error_status_t s_FmsChangeResourceGroup( IN handle_t IDL_handle, IN LPCWSTR pszResourceId, IN LPCWSTR pszGroupId ) /*++ Routine Description: Receives a Resource change group request from a remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. pszResourceId - The Id of the Resource to change a resource pszGroupId - The Id of the Group to change to. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE pResource = NULL; PFM_GROUP pNewGroup = NULL; DWORD dwStatus; PFM_GROUP pOldGroup; FmpMustBeOnline( ); // // Find the specified resource. // pResource = OmReferenceObjectById( ObjectTypeResource, pszResourceId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsChangeResourceNode: Could not find Resource %1!ws!\n", pszResourceId); dwStatus = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } // // Find the specified group. // pNewGroup = OmReferenceObjectById( ObjectTypeGroup, pszGroupId ); if ( pNewGroup == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsChangeResourceGroupe: Could not find NewGroup %1!ws!\n", pszGroupId); dwStatus = ERROR_GROUP_NOT_FOUND; goto FnExit; } ClRtlLogPrint(LOG_NOISE, "[FM] s_FmChangeResourceGroup : Resource <%1!ws!> NewGroup %2!ws!\n", OmObjectId( pResource ), OmObjectId( pNewGroup )); // // 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( pResource->Group ), OmObjectId( pNewGroup ) ) <= 0 ) { FmpAcquireLocalGroupLock( pResource->Group ); FmpAcquireLocalGroupLock( pNewGroup ); } else { FmpAcquireLocalGroupLock( pNewGroup ); FmpAcquireLocalGroupLock( pResource->Group ); } //remember the old group for freeing locks pOldGroup = pResource->Group; //boy if we are not the owner any more //shunt the request to the new owner if ( pResource->Group->OwnerNode != NmLocalNode ) { // Note: FmcChangeResourceNode must release the resource lock. dwStatus = FmcChangeResourceGroup( pResource, pNewGroup ); goto FnExit; } else { dwStatus = FmpChangeResourceGroup( pResource, pNewGroup ); } FmpReleaseLocalGroupLock( pNewGroup ); FmpReleaseLocalGroupLock( pOldGroup ); FnExit: if ( pResource ) OmDereferenceObject( pResource ); if ( pNewGroup ) OmDereferenceObject( pNewGroup ); ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsChangeResourceGroup : returned <%1!u!>\r\n", dwStatus); return( dwStatus ); } //s_FmsChangeResourceGroup error_status_t s_FmsDeleteGroupRequest( IN handle_t IDL_handle, IN LPCWSTR pszGroupId ) /*++ Routine Description: Receives a delete group request from a remote system and returns the status for that request. Arguments: IDL_handle - The binding context - not used. pszGroupId - The Id of the group to be deleted. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_GROUP pGroup = NULL; DWORD dwStatus = ERROR_SUCCESS; FmpMustBeOnline( ); // // Find the specified group. // pGroup = OmReferenceObjectById( ObjectTypeGroup, pszGroupId ); if ( pGroup == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsDeleteGroupRequest: Could not find group %1!ws!\n", pszGroupId); dwStatus = ERROR_GROUP_NOT_FOUND; goto FnExit; } FmpAcquireLocalGroupLock( pGroup ); if ( pGroup->OwnerNode == NmLocalNode ) { dwStatus = FmpDeleteGroup( pGroup ); } else { // // FmcDeleteGroup releases the group lock // dwStatus = FmcDeleteGroupRequest( pGroup ); goto FnExit; } FmpReleaseLocalGroupLock( pGroup ); FnExit: if ( pGroup ) OmDereferenceObject( pGroup ); return( dwStatus ); } //s_FmsChangeResourceGroup error_status_t s_FmsAddResourceDependency( IN handle_t IDL_handle, IN LPCWSTR pszResourceId, IN LPCWSTR pszDependsOnId ) /*++ Routine Description: Receives an add resource dependency request from a remote system and returns the status for that request. Arguments: IDL_handle - The binding context - not used. pszResourceId - The Id of the resource to add a dependent resource. pszDependentResourceId - The Id of the dependent resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE pResource = NULL; PFM_RESOURCE pDependentResource = NULL; DWORD dwStatus = ERROR_SUCCESS; DWORD dwResourceLen; DWORD dwDependsOnLen; // // Chittur Subbaraman (chitturs) - 5/16/99 // // Handle add resource dependency RPC calls from non-owner nodes // FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsAddResourceDependency: Resource <%1!ws!>, Dependent Resource <%2!ws!>\n", pszResourceId, pszDependsOnId); // // Find the specified resources. // pResource = OmReferenceObjectById( ObjectTypeResource, pszResourceId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsAddResourceDependency: Could not find resource <%1!ws!>\n", pszResourceId); dwStatus = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } pDependentResource = OmReferenceObjectById( ObjectTypeResource, pszDependsOnId ); if ( pDependentResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsAddResourceDependency: Could not find dependent resource <%1!ws!>\n", pszDependsOnId); dwStatus = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } // // Acquire the resource lock // FmpAcquireLocalResourceLock( pResource ); if ( pResource->Group->OwnerNode != NmLocalNode ) { dwStatus = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; goto FnUnlock; } dwStatus = FmpValAddResourceDependency( pResource, pDependentResource ); if ( dwStatus != ERROR_SUCCESS ) { goto FnUnlock; } dwResourceLen = ( lstrlenW( pszResourceId ) + 1 ) * sizeof( WCHAR ); dwDependsOnLen = ( lstrlenW( pszDependsOnId ) + 1 ) * sizeof( WCHAR ); dwStatus = GumSendUpdateEx( GumUpdateFailoverManager, FmUpdateAddDependency, 2, dwResourceLen, pszResourceId, dwDependsOnLen, pszDependsOnId ); if ( dwStatus == ERROR_SUCCESS ) { FmpBroadcastDependencyChange( pResource, pszDependsOnId, FALSE ); } FnUnlock: FmpReleaseLocalResourceLock( pResource ); FnExit: if ( pResource ) OmDereferenceObject( pResource ); if ( pDependentResource ) OmDereferenceObject( pDependentResource ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsAddResourceDependency Exit: Status = %1!u!\n", dwStatus); return( dwStatus ); } // s_FmsAddResourceDependency error_status_t s_FmsRemoveResourceDependency( IN handle_t IDL_handle, IN LPCWSTR pszResourceId, IN LPCWSTR pszDependsOnId ) /*++ Routine Description: Receives a remove resource dependency request from a remote system and returns the status for that request. Arguments: IDL_handle - The binding context - not used. pszResourceId - The Id of the resource to remove a dependent resource from. pszDependentResourceId - The Id of the dependent resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. --*/ { PFM_RESOURCE pResource = NULL; PFM_RESOURCE pDependentResource = NULL; DWORD dwStatus = ERROR_SUCCESS; DWORD dwResourceLen; DWORD dwDependsOnLen; // // Chittur Subbaraman (chitturs) - 5/16/99 // // Handle remove resource dependency RPC calls from non-owner nodes // FmpMustBeOnline( ); ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRemoveResourceDependency: Resource <%1!ws!>, Dependent Resource <%2!ws!>\n", pszResourceId, pszDependsOnId); // // Find the specified resources. // pResource = OmReferenceObjectById( ObjectTypeResource, pszResourceId ); if ( pResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRemoveResourceDependency: Could not find resource <%1!ws!>\n", pszResourceId); dwStatus = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } pDependentResource = OmReferenceObjectById( ObjectTypeResource, pszDependsOnId ); if ( pDependentResource == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRemoveResourceDependency: Could not find dependent resource <%1!ws!>\n", pszDependsOnId); dwStatus = ERROR_RESOURCE_NOT_FOUND; goto FnExit; } // // Acquire the resource lock // FmpAcquireLocalResourceLock( pResource ); dwStatus = FmpValRemoveResourceDependency( pResource, pDependentResource ); if ( dwStatus != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_NOISE, "[FM] s_FmsRemoveResourceDependency: FmpValRemoveResourceDependency returns %1!u!\n", dwStatus); goto FnUnlock; } if ( pResource->Group->OwnerNode != NmLocalNode ) { dwStatus = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; goto FnUnlock; } pszResourceId = OmObjectId( pResource ); dwResourceLen = ( lstrlenW( pszResourceId ) + 1 ) * sizeof( WCHAR ); pszDependsOnId = OmObjectId( pDependentResource ); dwDependsOnLen = ( lstrlenW( pszDependsOnId ) + 1 ) * sizeof( WCHAR ); dwStatus = GumSendUpdateEx( GumUpdateFailoverManager, FmUpdateRemoveDependency, 2, dwResourceLen, pszResourceId, dwDependsOnLen, pszDependsOnId ); if ( dwStatus == ERROR_SUCCESS ) { FmpBroadcastDependencyChange( pResource, pszDependsOnId, TRUE ); } FnUnlock: FmpReleaseLocalResourceLock( pResource ); FnExit: if ( pResource ) OmDereferenceObject( pResource ); if ( pDependentResource ) OmDereferenceObject( pDependentResource ); ClRtlLogPrint(LOG_NOISE, "[FM] FmsRemoveResourceDependency Exit: Status = %1!u!\n", dwStatus); return( dwStatus ); } // s_FmsRemoveResourceDependency error_status_t s_FmsCreateResource2( IN handle_t IDL_handle, IN LPCWSTR GroupId, IN LPWSTR ResourceId, IN LPCWSTR ResourceName, IN LPCWSTR ResourceType, IN DWORD dwFlags ) /*++ Routine Description: Receives a Create Resource Request from a remote system and returns status for that request. Arguments: IDL_handle - The binding context - not used. GroupId - The Id of the Group to create the resource inside. ResourceId - The Id of the Resource to create. ResourceName - The name of the Resource to create. ResourceType - The name of the Resource Type. dwFlags - Flags for the resource. Return Value: ERROR_SUCCESS if successful. A Win32 error code on error. Notes: The Resource lock is acquired to synchronize access to the resource. This satisfies locking the resource on all nodes in the cluster... so long as the local node is the owner of the resource. --*/ { PFM_GROUP group; DWORD status; PGUM_CREATE_RESOURCE gumResource; DWORD groupIdLen; DWORD resourceIdLen; DWORD resourceNameLen; DWORD resourceTypeLen; DWORD bufSize; HDMKEY resourceKey; HDMKEY paramsKey; DWORD disposition; FmpMustBeOnline(); ClRtlLogPrint(LOG_NOISE, "[FM] FmsCreateResource2: To create resource '%1!ws!'\n", ResourceId); // // Find the specified group. // group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] FmsCreateResource2: Could not find Group %1!ws!\n", GroupId); return(ERROR_GROUP_NOT_FOUND); } FmpAcquireLocalGroupLock( group ); // // Now delete it on all nodes in the cluster if we are the owner. // if ( group->OwnerNode == NmLocalNode ) { // // Allocate a message buffer. // groupIdLen = (lstrlenW(GroupId)+1) * sizeof(WCHAR); resourceIdLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR); resourceNameLen = (lstrlenW(ResourceName)+1) * sizeof(WCHAR); resourceTypeLen = (lstrlenW(ResourceType)+1) * sizeof(WCHAR); bufSize = sizeof(GUM_CREATE_RESOURCE) - sizeof(WCHAR) + groupIdLen + resourceIdLen + resourceNameLen + resourceTypeLen + 2 * sizeof( DWORD ); gumResource = LocalAlloc(LMEM_FIXED, bufSize); if (gumResource == NULL) { ClRtlLogPrint(LOG_CRITICAL, "[FM] FmsCreateResource2: Unable to allocate memory for resource %1!ws!\n", ResourceName); return(ERROR_NOT_ENOUGH_MEMORY); } // // Fill in message buffer. // gumResource->Resource = NULL; gumResource->GroupIdLen = groupIdLen; gumResource->ResourceIdLen = resourceIdLen; CopyMemory(gumResource->GroupId, GroupId, groupIdLen); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen, ResourceId, resourceIdLen); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen + resourceIdLen, ResourceName, resourceNameLen); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen + resourceIdLen + resourceNameLen, &resourceTypeLen, sizeof( DWORD ) ); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen + resourceIdLen + resourceNameLen + sizeof( DWORD ), ResourceType, resourceTypeLen ); CopyMemory((PCHAR)gumResource->GroupId + groupIdLen + resourceIdLen + resourceNameLen + sizeof( DWORD ) + resourceTypeLen, &dwFlags, sizeof( DWORD ) ); // // Send message. // status = GumSendUpdate(GumUpdateFailoverManager, FmUpdateCreateResource, bufSize, gumResource); if ( ( status == ERROR_SUCCESS ) && ( gumResource->Resource != NULL ) ) { // // If the GUM call was successful, ensure that the resource DLL initialization stuff is // also done so that APIs following the CreateClusterResource API can make assumptions // that the resource is fully created. Note that the GUM call above will post a work item // for the FM worker thread to initialize a resource but there is no guarantee when the // FM worker thread will act on the work item. The following call will make sure we // won't return from this API until the initialization is fully done thus not giving any // chance for APIs such as ChangeClusterResourceGroup that follow this API to screw things // up. For backward compatibility reasons (consider a create call originating from a // W2K node), we still keep the work item posting in GUM and it won't do any harm since // the FmpInitializeResource call is idempotent. // FmpClusterWideInitializeResource ( gumResource->Resource ); FmpCleanupPossibleNodeList(gumResource->Resource); } if( ( gumResource->Resource == NULL ) && FmpShutdown ) { status = ERROR_CLUSTER_NODE_SHUTTING_DOWN; } LocalFree(gumResource); } else { status = ERROR_HOST_NODE_NOT_RESOURCE_OWNER; } FmpReleaseLocalGroupLock( group ); return(status); } // FmsCreateResource2