|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
fmclient.c
Abstract:
Cluster client side routines for RPC remote calls.
Author:
Rod Gamache (rodga) 8-Mar-1996
Revision History:
--*/
#include "fmp.h"
#define LOG_MODULE FMCLIENT
DWORD FmcOnlineGroupRequest( IN PFM_GROUP Group )
/*++
Routine Description:
This routine requests (THE) remote system to bring the Group Online.
Arguments:
Group - The Group to bring online.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD OwnerId;
CL_ASSERT(Group->OwnerNode != NmLocalNode); CL_ASSERT(Group->OwnerNode != NULL);
OwnerId = NmGetNodeId(Group->OwnerNode); status = FmsOnlineGroupRequest( Session[OwnerId], OmObjectId(Group) );
return(status);
} // FmcOnlineGroupRequest
DWORD FmcOfflineGroupRequest( IN PFM_GROUP Group )
/*++
Routine Description:
This routine requests a remote system to take the Group Offline.
Arguments:
Group - The Group to take online.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD OwnerId;
CL_ASSERT(Group->OwnerNode != NmLocalNode); CL_ASSERT(Group->OwnerNode != NULL);
OwnerId = NmGetNodeId(Group->OwnerNode); CL_ASSERT(Session[OwnerId] != NULL); status = FmsOfflineGroupRequest( Session[OwnerId], OmObjectId(Group) );
return(status);
} // FmcOfflineGroupRequest
DWORD FmcMoveGroupRequest( IN PFM_GROUP Group, IN PNM_NODE DestinationNode OPTIONAL )
/*++
Routine Description:
This routine requests (THE) remote system to move the Group there.
Arguments:
Group - The Group to bring online. DestinationNode - The node to move the Group to.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
Notes:
The Group lock must be held on entry. The Group lock is releaseed before returning.
--*/
{ DWORD status; DWORD OwnerId;
CL_ASSERT(Group->OwnerNode != NmLocalNode); #if 1
if ( Group ->OwnerNode == NULL ) { ClRtlLogPrint(LOG_ERROR, "[FM] MoveRequest for group with no owner!\n"); return(ERROR_HOST_NODE_NOT_AVAILABLE); } #endif
CL_ASSERT(Group->OwnerNode != NULL);
OwnerId = NmGetNodeId(Group->OwnerNode);
FmpReleaseLocalGroupLock( Group );
if (DestinationNode != NULL) { status = FmsMoveGroupRequest( Session[OwnerId], OmObjectId(Group ), OmObjectId(DestinationNode)); } else { status = FmsMoveGroupRequest( Session[OwnerId], OmObjectId(Group ), NULL); }
return(status);
} // FmcMoveGroupRequest
DWORD FmcTakeGroupRequest( IN PNM_NODE DestinationNode, IN LPCWSTR GroupId, IN PRESOURCE_ENUM ResourceList )
/*++
Routine Description:
This routine requests a remote system to move the Group there.
Arguments:
DestinationNode - The destination node GroupId - The Id of the Group to be moved. ResourceList - The list of the resources and their states.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status=ERROR_SUCCESS; RPC_BINDING_HANDLE Binding; PFM_GROUP group = NULL; DWORD nodeId;
//
// If the remote session is not established, then return failure.
//
if ( gpQuoResource == NULL ) { CsInconsistencyHalt(ERROR_INVALID_OPERATION_ON_QUORUM); }
group = OmReferenceObjectById( ObjectTypeGroup, GroupId ); if ( group == NULL ) { CsInconsistencyHalt(ERROR_GROUP_NOT_AVAILABLE); }
if ( gpQuoResource->Group == group ) { // Quorum group
// We don't need a lock on this usage, since there is only one
Binding = FmpRpcQuorumBindings[NmGetNodeId(DestinationNode)]; if ( Binding == NULL ) { ClRtlLogPrint(LOG_ERROR,"[FM] TakeRequest and no remote binding available\n"); OmDereferenceObject( group ); return(ERROR_HOST_NODE_NOT_AVAILABLE); }
OmDereferenceObject( group ); nodeId = NmGetNodeId(DestinationNode); try { NmStartRpc(nodeId); status = FmsTakeGroupRequest( Binding, GroupId, ResourceList ); } finally { NmEndRpc(nodeId); if( status != RPC_S_OK ) { NmDumpRpcExtErrorInfo(status); } }
} else { // Non-quorum group
OmDereferenceObject( group ); Binding = FmpRpcBindings[NmGetNodeId(DestinationNode)]; if ( Binding == NULL ) { ClRtlLogPrint(LOG_ERROR,"[FM] TakeRequest and no remote binding available\n"); return(ERROR_HOST_NODE_NOT_AVAILABLE); }
// This is a shared binding, so serialize usage.
//
// Charlie Wickham (charlwi) - 10/30/00
//
// 185575: removing use of unique RPC binding handles hence no longer
// any need to serialize take group requests.
//
// FmpAcquireBindingLock();
//
// Chittur Subbaraman (chitturs) - 9/30/99
//
// Enclose the RPC within a "try-finally" block so that the
// lock is released regardless of whether the RPC succeeds.
// Note that the caller of FmcTakeGroupRequest encloses
// that function in a "try-except" block.
//
nodeId = NmGetNodeId(DestinationNode); try { NmStartRpc(nodeId); status = FmsTakeGroupRequest( Binding, GroupId, ResourceList ); } finally { NmEndRpc(nodeId); if( status != RPC_S_OK ) { NmDumpRpcExtErrorInfo(status); }
// FmpReleaseBindingLock();
} }
return(status);
} // FmcTakeGroupRequest
DWORD FmcOnlineResourceRequest( IN PFM_RESOURCE Resource )
/*++
Routine Description:
This routine requests (THE) remote system to bring the Resource Online.
Arguments:
Resource - The resource to bring online.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD NodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
NodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[NodeId] != NULL); status = FmsOnlineResourceRequest( Session[NodeId], OmObjectId(Resource) );
return(status);
} // FmcOnlineResourceRequest
DWORD FmcOfflineResourceRequest( IN PFM_RESOURCE Resource )
/*++
Routine Description:
This routine requests (THE) remote system to take the Resource Offline.
Arguments:
Resource - The resource to take offline.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD NodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
NodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[NodeId] != NULL); status = FmsOfflineResourceRequest( Session[NodeId], OmObjectId(Resource) ); return(status);
} // FmcOfflineResourceRequest
DWORD FmcChangeResourceNode( IN PFM_RESOURCE Resource, IN PNM_NODE Node, IN BOOL Add )
/*++
Routine Description:
This routine requests the owner of the resource to perform the change resource node operation.
Arguments:
Resource - The resource to change the resource node.
Node - The node to be added/removed from the resource list.
Add - Specifies whether to add or remove the given node.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
Note:
The resource's lock must be held on entry. It is released prior to returning.
--*/
{ DWORD status; DWORD NodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
NodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[NodeId] != NULL); FmpReleaseLocalResourceLock( Resource ); status = FmsChangeResourceNode( Session[NodeId], OmObjectId(Resource), OmObjectId(Node), Add );
return(status);
} // FmcChangeResourceNode
DWORD FmcArbitrateResource( IN PFM_RESOURCE Resource )
/*++
Routine Description:
This routine requests a remote system to arbitrate a resource.
Arguments:
Resource - The resource to arbitrate.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD nodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
nodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[nodeId] != NULL);
status = FmsArbitrateResource( Session[nodeId], OmObjectId(Resource) ); return(status);
} // FmcArbitrateResource
VOID FmcDeleteEnum( IN PGROUP_ENUM Enum )
/*++
Routine Description:
This routine deletes an GROUP_ENUM and associated name strings.
Arguments:
Enum - The GROUP_ENUM to delete. This pointer can be NULL.
Returns:
None.
Notes:
This routine will take a NULL input pointer and just return.
--*/
{ DWORD i;
if ( Enum == NULL ) { return; }
for ( i = 0; i < Enum->EntryCount; i++ ) { MIDL_user_free(Enum->Entry[i].Id); }
MIDL_user_free(Enum); return;
} // FmcDeleteEnum
DWORD FmcFailResource( IN PFM_RESOURCE Resource )
/*++
Routine Description:
This routine requests a remote system to fail a resource.
Arguments:
Resource - The resource to fail.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD nodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
nodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[nodeId] != NULL);
status = FmsFailResource( Session[nodeId], OmObjectId(Resource) ); return(status);
} // FmcFailResource
PFM_RESOURCE FmcCreateResource( IN PFM_GROUP Group, IN LPWSTR ResourceId, IN LPCWSTR ResourceName, IN LPCWSTR ResourceType, IN DWORD dwFlags )
/*++
Routine Description:
This routine requests a remote system to create a resource. The remote system should 'own' the group.
Arguments:
Group - The group that the resource should be created inside.
ResourceId - The id of the resource to create.
ResourceName - The name of the resource to create.
ResourceType - Resource type name
dwFlags - Flags for the resource.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
Notes:
The Group lock should be held... and is released by this routine.
--*/
{ DWORD status; DWORD nodeId; PFM_RESOURCE resource = NULL; DWORD dwClusterHighestVersion;
CL_ASSERT(Group->OwnerNode != NULL);
nodeId = NmGetNodeId(Group->OwnerNode); CL_ASSERT(Session[nodeId] != NULL);
FmpReleaseLocalGroupLock( Group );
NmGetClusterOperationalVersion( &dwClusterHighestVersion, NULL, NULL ); if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) < NT51_MAJOR_VERSION ) { status = FmsCreateResource( Session[nodeId], OmObjectId(Group), ResourceId, ResourceName ); } else { status = FmsCreateResource2( Session[nodeId], OmObjectId(Group), ResourceId, ResourceName, ResourceType, dwFlags ); }
if ( status == ERROR_SUCCESS ) { resource = OmReferenceObjectById( ObjectTypeResource, ResourceId ); if ( resource != NULL ) { OmDereferenceObject( resource ); } } else { SetLastError(status); }
return(resource);
} // FmcCreateResource
DWORD FmcDeleteResource( IN PFM_RESOURCE Resource )
/*++
Routine Description:
This routine requests a remote system to delete a resource.
Arguments:
Resource - The resource to delete.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
Notes:
The Resource lock should be held... and is released by this routine.
--*/
{ DWORD status; DWORD nodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
nodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[nodeId] != NULL);
FmpReleaseLocalResourceLock( Resource );
status = FmsDeleteResource( Session[nodeId], OmObjectId(Resource) );
return(status);
} // FmcDeleteResource
DWORD FmcResourceControl( IN PNM_NODE Node, IN PFM_RESOURCE Resource, 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 to a remote system.
Arguments:
Node - the remote node to send the request to.
Resource - the resource to handle the request.
ControlCode - the control code for this request.
InBuffer - the input buffer.
InBufferSize - the size of the input buffer.
OutBuffer - the output buffer.
OutBuffer - the size of the output buffer.
BytesReturned - the length of the returned data.
Required - the number of bytes required if OutBuffer is not big enough.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD NodeId; DWORD Dummy; DWORD dwTmpBytesReturned; DWORD dwTmpBytesRequired;
NodeId = NmGetNodeId(Node); if ((NmGetNodeState(Node) != ClusterNodeUp) && ( NmGetNodeState(Node) != ClusterNodePaused)) { return(ERROR_HOST_NODE_NOT_AVAILABLE); }
CL_ASSERT(Session[NodeId] != NULL);
//to take care of the output reference pointer which cannot be NULL.
if (!OutBuffer) { OutBuffer = (PUCHAR)&Dummy; OutBufferSize = 0; } if (!BytesReturned) BytesReturned = &dwTmpBytesReturned; if (!Required) Required = &dwTmpBytesRequired;
status = FmsResourceControl( Session[NodeId], OmObjectId(Resource), ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required ); return(status);
} // FmcResourceControl
DWORD FmcResourceTypeControl( IN PNM_NODE Node, 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 type control request to a remote system.
Arguments:
Node - the remote node to send the request to.
ResourceTypeName - the name of the resource type to handle the request.
ControlCode - the control code for this request.
InBuffer - the input buffer.
InBufferSize - the size of the input buffer.
OutBuffer - the output buffer.
OutBuffer - the size of the output buffer.
BytesReturned - the length of the returned data.
Required - the number of bytes required if OutBuffer is not big enough.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD NodeId;
NodeId = NmGetNodeId(Node); if (( NmGetNodeState(Node) != ClusterNodeUp ) && ( NmGetNodeState(Node) != ClusterNodePaused )) { return(ERROR_HOST_NODE_NOT_AVAILABLE); }
CL_ASSERT(Session[NodeId] != NULL); status = FmsResourceTypeControl( Session[NodeId], ResourceTypeName, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required ); return(status);
} // FmcResourceTypeControl
DWORD FmcGroupControl( IN PNM_NODE Node, IN PFM_GROUP Group, 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 to a remote system.
Arguments:
Node - the remote node to send the request to.
Group - the group to handle the request.
ControlCode - the control code for this request.
InBuffer - the input buffer.
InBufferSize - the size of the input buffer.
OutBuffer - the output buffer.
OutBuffer - the size of the output buffer.
BytesReturned - the length of the returned data.
Required - the number of bytes required if OutBuffer is not big enough.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD NodeId;
NodeId = NmGetNodeId(Node); if (( NmGetNodeState(Node) != ClusterNodeUp ) && ( NmGetNodeState(Node) != ClusterNodePaused )) { return(ERROR_HOST_NODE_NOT_AVAILABLE); }
CL_ASSERT(Session[NodeId] != NULL); status = FmsGroupControl( Session[NodeId], OmObjectId(Group), ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required ); return(status);
} // FmcGroupControl
DWORD FmcPrepareQuorumResChange( IN PFM_RESOURCE Resource, IN LPCWSTR lpszQuoLogPath, IN DWORD dwMaxQuoLogSize )
/*++
Routine Description:
This routine requests a the owner of a potential quorum resource to prepare for quorum logging and registry replication.
Arguments:
Resource - The resource to on which we want to start logging.
lpszQuoLogPath - The Path where the cluster log files should be created.
dwMaxQuoLogSize - The new max Quorum Log Size.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD nodeId;
CL_ASSERT(Resource->Group->OwnerNode != NULL);
nodeId = NmGetNodeId(Resource->Group->OwnerNode); CL_ASSERT(Session[nodeId] != NULL);
status = FmsPrepareQuorumResChange( Session[nodeId], OmObjectId(Resource), lpszQuoLogPath, dwMaxQuoLogSize ); return(status);
} // FmcPrepareQuorumResChange
DWORD FmcCompleteQuorumResChange( IN PFM_RESOURCE pOldQuoRes, IN LPCWSTR lpszOldQuoLogPath )
/*++
Routine Description:
This routine requests a the owner of the previous quorum resource to clean up after quorum resource change is complete.
Arguments:
pOldQuoRes - The resource to on which we want to start logging.
lpszOldQuoLogPath - The Path where the cluster log files should be created.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD nodeId;
CL_ASSERT(pOldQuoRes->Group->OwnerNode != NULL);
nodeId = NmGetNodeId(pOldQuoRes->Group->OwnerNode); CL_ASSERT(Session[nodeId] != NULL);
status = FmsCompleteQuorumResChange( Session[nodeId], OmObjectId(pOldQuoRes), lpszOldQuoLogPath); return(status);
} // FmcCompleteQuorumResChange
DWORD FmcChangeResourceGroup( IN PFM_RESOURCE pResource, IN PFM_GROUP pNewGroup ) /*++
Routine Description:
This routine requests the owner of the resource to move the resource from one group to another.
Arguments:
Resource - The resource whose group is to be changed.
pNewGroup - The group to which the resource should be moved to.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
Note:
The group locks for both the old and the new group must be held on entry. They are release before making the rpc call.
--*/
{ DWORD status; DWORD NodeId;
CL_ASSERT(pResource->Group->OwnerNode != NULL);
NodeId = NmGetNodeId(pResource->Group->OwnerNode); CL_ASSERT(Session[NodeId] != NULL); FmpReleaseLocalGroupLock( pResource->Group ); FmpReleaseLocalGroupLock( pNewGroup ); status = FmsChangeResourceGroup( Session[NodeId], OmObjectId(pResource), OmObjectId(pNewGroup));
return(status);
} // FmcChangeResourceNode
DWORD FmcBackupClusterDatabase( IN PFM_RESOURCE pQuoResource, IN LPCWSTR lpszPathName )
/*++
Routine Description:
This routine requests the owner of a potential quorum resource to backup the quorum log and the checkpoint file to the specified path. This function is called with the resource lock held.
Arguments:
pQuoResource - 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.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{ DWORD status; DWORD nodeId;
CL_ASSERT( pQuoResource->Group->OwnerNode != NULL );
nodeId = NmGetNodeId( pQuoResource->Group->OwnerNode ); CL_ASSERT( Session[nodeId] != NULL );
//
// Chittur Subbaraman (chitturs) - 10/16/98
//
// Release the resource lock. Releasing the resource lock
// here can create a window during which this node thinks
// the other node is the owner and the other node thinks
// this node is the owner. But, unfortunately we've to treat
// this as an error case so that we don't run into deadlocks
// across multiple machines due to the lock being held while
// making the RPC.
//
FmpReleaseLocalResourceLock( pQuoResource );
status = FmsBackupClusterDatabase( Session[nodeId], OmObjectId( pQuoResource ), lpszPathName );
return( status ); } // FmcBackupClusterDatabase
/****
@func DWORD | FmcDeleteGroup| This makes a rpc call to the owner of the group to handle the delete group request.
@parm IN PFM_GROUB | pGroup | The group that must be deleted. @comm The owner node should make the GUM request to avoid deadlocks.
@rdesc Returns a result code. ERROR_SUCCESS on success. ****/ DWORD FmcDeleteGroupRequest( IN PFM_GROUP pGroup ) { DWORD dwOwnerId; DWORD dwStatus; dwOwnerId = NmGetNodeId(pGroup->OwnerNode);
CL_ASSERT(dwOwnerId != NmLocalNodeId);
//release the lock before making the rpc call
FmpReleaseLocalGroupLock( pGroup ); dwStatus = FmsDeleteGroupRequest( Session[dwOwnerId], OmObjectId(pGroup) ); return(dwStatus);
}
/****
@func DWORD | FmcAddResourceDependency | This makes an RPC to the owner of the resource to handle the dependency addition.
@parm IN PFM_RESOURCE | pResource | The resource to add the dependent resource.
@parm IN PFM_RESOURCE | pDependentResource | The dependent resource. @comm The owner node should make the GUM request to avoid deadlocks.
@rdesc Returns an error code. ERROR_SUCCESS on success. ****/ DWORD FmcAddResourceDependency( IN PFM_RESOURCE pResource, IN PFM_RESOURCE pDependentResource ) { DWORD dwOwnerId; DWORD dwStatus; dwOwnerId = NmGetNodeId( pResource->Group->OwnerNode );
CL_ASSERT( dwOwnerId != NmLocalNodeId ); //
// Release the lock before making the RPC call
//
FmpReleaseLocalResourceLock( pResource ); dwStatus = FmsAddResourceDependency( Session[dwOwnerId], OmObjectId( pResource ), OmObjectId( pDependentResource ) ); return( dwStatus ); }
/****
@func DWORD | FmcRemoveResourceDependency | This makes an RPC to the owner of the resource to handle the dependency removal.
@parm IN PFM_RESOURCE | pResource | The resource to remove the dependent resource from.
@parm IN PFM_RESOURCE | pDependentResource | The dependent resource. @comm The owner node should make the GUM request to avoid deadlocks.
@rdesc Returns an error code. ERROR_SUCCESS on success. ****/ DWORD FmcRemoveResourceDependency( IN PFM_RESOURCE pResource, IN PFM_RESOURCE pDependentResource ) { DWORD dwOwnerId; DWORD dwStatus; dwOwnerId = NmGetNodeId( pResource->Group->OwnerNode );
CL_ASSERT( dwOwnerId != NmLocalNodeId ); //
// Release the lock before making the RPC call
//
FmpReleaseLocalResourceLock( pResource ); dwStatus = FmsRemoveResourceDependency( Session[dwOwnerId], OmObjectId( pResource ), OmObjectId( pDependentResource ) ); return( dwStatus ); }
|