|
|
/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
fmval.c Abstract:
Cluster manager api validation/support routines.
Author:
Sunita Shrivastava (sunitas) 29-April-1999.
Revision History:
--*/
#include "fmp.h"
#define LOG_MODULE FMVAL
////////////////////////////////////////////////////////
//
// Validation routines for Group operations.
//
////////////////////////////////////////////////////////
DWORD FmpValOnlineGroup( IN PFM_GROUP Group )
/*++
Routine Description:
Validation routine before group is brought online.
Arguments:
Group - Supplies a pointer to the group structure to bring online.
Comments:
Is called with the localgroup lock held
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/ { DWORD dwStatus = ERROR_SUCCESS; PLIST_ENTRY listEntry;
//if the group has been marked for delete, then fail this call
if (!IS_VALID_FM_GROUP(Group)) { dwStatus = ERROR_GROUP_NOT_AVAILABLE; goto FnExit; }
//
// Make sure the owning node can run the group.
//
if ( !FmpInPreferredList( Group, Group->OwnerNode ) ) { dwStatus = ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST; goto FnExit; }
//
// Make sure the owning node is not paused.
//
if (NmGetNodeState(Group->OwnerNode) == ClusterNodePaused) { dwStatus = ERROR_SHARING_PAUSED; goto FnExit; }
FnExit: return(dwStatus);
} // FmpValOnlineGroup
DWORD FmpValMoveGroup( IN PFM_GROUP Group, IN PNM_NODE DestinationNode OPTIONAL )
/*++
Routine Description:
Validation routine for group move.
Arguments:
Group - Supplies a pointer to the group structure to move.
DestinationNode - Supplies the node object to move the group to. If not present, then move it to THE OTHER node.
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/
{ DWORD dwStatus = ERROR_SUCCESS; //if the group has been marked for delete, then fail this call
if (!IS_VALID_FM_GROUP(Group)) { dwStatus = ERROR_GROUP_NOT_AVAILABLE; goto FnExit; }
if ( FmpIsGroupPending(Group) ) { dwStatus = ERROR_GROUP_NOT_AVAILABLE; goto FnExit; }
if ( Group->OwnerNode == NULL ) { dwStatus = ERROR_HOST_NODE_NOT_AVAILABLE; goto FnExit; }
FnExit: return(dwStatus);
} // FmpValMoveGroup
////////////////////////////////////////////////////////
//
// Validation routines for resource operations
//
////////////////////////////////////////////////////////
DWORD FmpValCreateResource( IN PFM_GROUP Group, IN LPWSTR ResourceId, IN LPCWSTR ResourceName, OUT PGUM_CREATE_RESOURCE *ppGumResource, OUT PDWORD pdwBufSize )
/*++
Routine Description:
Validation routine for resource creation.
Arguments:
Group - Supplies the group in which this resource belongs.
ResourceId - Supplies the Id of the resource to create.
ResourceName - Supplies the 'user-friendly' name of the resource.
ppGumResource - Message buffer to hold resource info.
pdwBufSize - Message buffer size.
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/ { DWORD dwStatus = ERROR_SUCCESS; PFM_RESOURCE Resource; LPCWSTR GroupId; PGUM_CREATE_RESOURCE GumResource; DWORD GroupIdLen; DWORD ResourceIdLen; DWORD ResourceNameLen; DWORD BufSize; HDMKEY ResourceKey; HDMKEY ParamsKey; DWORD Disposition;
*ppGumResource = NULL; *pdwBufSize = 0; //
// First create the parameters field.
//
ResourceKey = DmOpenKey( DmResourcesKey, ResourceId, MAXIMUM_ALLOWED ); if ( ResourceKey == NULL ) { ClRtlLogPrint(LOG_NOISE, "[FM] CreateResource: Failed to open registry key for %1!ws!, status = %2!u!.\n", ResourceId, GetLastError() ); dwStatus = GetLastError(); goto FnExit; } ParamsKey = DmCreateKey( ResourceKey, CLUSREG_KEYNAME_PARAMETERS, 0, KEY_READ | KEY_WRITE, NULL, &Disposition ); if ( ParamsKey != NULL ) { DmCloseKey( ParamsKey ); } DmCloseKey( ResourceKey );
//
// Allocate a message buffer.
//
GroupId = OmObjectId(Group); 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) { CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY ); dwStatus = ERROR_NOT_ENOUGH_MEMORY; goto FnExit; }
//
// 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);
*ppGumResource = GumResource; *pdwBufSize = BufSize;
FnExit: return(dwStatus);
} // FmpValCreateResource
DWORD FmpValDeleteResource( IN PFM_RESOURCE pResource )
/*++
Routine Description:
Validation routine for delete resource.
Arguments:
Resource - Supplies the resource to delete.
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/
{ DWORD dwStatus = ERROR_SUCCESS;
//
// Check if this is the quorum resource.
//
if ( pResource->QuorumResource ) { dwStatus = ERROR_QUORUM_RESOURCE; goto FnExit; }
//other core resources cannot be deleted either
if (pResource->ExFlags & CLUS_FLAG_CORE) { dwStatus = 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 ((pResource->State != ClusterResourceOffline) && (pResource->State != ClusterResourceFailed)) { dwStatus = ERROR_RESOURCE_ONLINE; goto FnExit; }
//
// Check whether this resource provides for any other resources.
// If so, it cannot be deleted.
//
if (!IsListEmpty(&pResource->ProvidesFor)) { dwStatus = ERROR_DEPENDENT_RESOURCE_EXISTS; goto FnExit; }
if (pResource->Group->MovingList) { dwStatus = ERROR_INVALID_STATE; goto FnExit; } FnExit: return(dwStatus);
} // FmpValDeleteResource
DWORD FmpValOnlineResource( IN PFM_RESOURCE pResource )
/*++
Routine Description:
This routine validates if a resource can be brought online.
Arguments:
Resource - A pointer to the resource to bring online.
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/ {
DWORD dwStatus = ERROR_SUCCESS; //if the resource has been marked for delete, then dont let
//it be brought online
if (!IS_VALID_FM_RESOURCE(pResource)) { dwStatus = ERROR_RESOURCE_NOT_AVAILABLE; goto FnExit; }
//
// Check if the resource has been initialized. If not, attempt
// to initialize the resource now.
//
if ( pResource->Monitor == NULL ) { dwStatus = FmpInitializeResource( pResource, TRUE ); }
FnExit: return(dwStatus); } // FmpValOnlineResource
DWORD FmpValOfflineResource( IN PFM_RESOURCE pResource )
/*++
Routine Description:
This routine validates if a given resource can be taken offline.
Arguments:
Resource - A pointer to the resource to take offline.
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/
{ DWORD dwStatus = ERROR_SUCCESS;
//if the resource has been marked for delete, then fail this call
if (!IS_VALID_FM_RESOURCE(pResource)) { dwStatus = ERROR_RESOURCE_NOT_AVAILABLE; goto FnExit; }
//
// Check if this is the quorum resource.
//
if ( pResource->QuorumResource ) { dwStatus = ERROR_QUORUM_RESOURCE; goto FnExit; }
//
// Check if the resource has been initialized. If not, return
// success because the resource is not online.
//
if ( pResource->Monitor == NULL ) { dwStatus = ERROR_SUCCESS; goto FnExit; }
//
// Chittur Subbaraman (chitturs) - 4/8/99
//
// Don't attempt to do anything if the resource has failed. You could
// get into some funny cases in which the resource switches between
// offline pending and failed states for ever.
//
if ( pResource->State == ClusterResourceFailed ) { dwStatus = ERROR_INVALID_STATE; goto FnExit; } FnExit: return(dwStatus);
} // FmpValOfflineResource
DWORD FmpValAddResourceDependency( IN PFM_RESOURCE pResource, IN PFM_RESOURCE pDependentResource )
/*++
Routine Description:
Validation routine for dependency addition.
Arguments:
Resource - The resource to add the dependent resource.
DependentResource - The dependent resource.
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/
{ DWORD dwStatus = ERROR_SUCCESS;
//if the resource has been marked for delete, then dont let
//it be brought online
if (!IS_VALID_FM_RESOURCE(pResource)) { dwStatus = ERROR_RESOURCE_NOT_AVAILABLE; goto FnExit; }
if (pResource->QuorumResource) { dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED; goto FnExit; } //
// If the resources are not in the same group, fail the
// call. Also fail if some one tries to make a resource
// dependent upon itself.
//
if ((pResource->Group != pDependentResource->Group) || (pResource == pDependentResource)) { dwStatus = ERROR_INVALID_PARAMETER; goto FnExit; }
// The resource to which the dependency is being added must be offline
// Otherwise, it looks like the dependency is in effect when the depending
// resource was not really brought online at the time the dependency existed
// must also be offline or failed.
// SS: For instance if a network name is dependent on two ip addresesses and
// is online and a third ip address resource dependency is added, the
// network name must be brought offline and online for the dependency
// to be truly in effect
//
if ((pResource->State != ClusterResourceOffline) && (pResource->State != ClusterResourceFailed)) { dwStatus = ERROR_RESOURCE_ONLINE; goto FnExit; }
//
// Make sure that we don't have any circular dependencies!
//
if ( FmDependentResource( pDependentResource, pResource, FALSE ) ) { dwStatus = ERROR_CIRCULAR_DEPENDENCY; goto FnExit; }
//
// Make sure that this dependency does not already exist!
//
if ( FmDependentResource(pResource, pDependentResource, TRUE)) { dwStatus = ERROR_DEPENDENCY_ALREADY_EXISTS; goto FnExit; }
FnExit: return(dwStatus);
} // FmpValAddResourceDependency
DWORD FmpValChangeResourceNode( IN PFM_RESOURCE pResource, IN LPCWSTR pszNodeId, IN BOOL bAdd, OUT PGUM_CHANGE_POSSIBLE_NODE *ppGumChange, OUT PDWORD pdwBufSize )
/*++
Routine Description:
Validation routine for changing the possible owner node of a resource.
Arguments:
pResource - A pointer to the resource structure.
pszNodeId - A pointer to the node id
bAdd - Indicates add or remove
ppGumChange - Message buffer to hold the resource info
pdwBufSize - Size of the message buffer Comments:
Lock must be held when this routine is called
Returns:
ERROR_SUCCESS if the validation is successful.
A Win32 error code if the validation fails.
--*/ { DWORD dwStatus = ERROR_SUCCESS; PLIST_ENTRY pListEntry; PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry = NULL; BOOL bNodeSupportsResType = FALSE; LPCWSTR pszResourceId; DWORD dwResourceLen; DWORD dwNodeLen; DWORD dwBufSize; PGUM_CHANGE_POSSIBLE_NODE pGumChange;
*ppGumChange = NULL; *pdwBufSize = 0;
//if the resource has been marked for delete, then perform
//any operations on it
if (!IS_VALID_FM_RESOURCE(pResource)) { dwStatus = ERROR_RESOURCE_NOT_AVAILABLE; goto FnExit; }
if ( pResource->QuorumResource ) { dwStatus = ERROR_INVALID_OPERATION_ON_QUORUM; goto FnExit; }
//
// We can't allow the owner node to be removed if the state
// of the resource or the group is not offline or failed.
//
if ( !bAdd && (lstrcmpi(NodeId, OmObjectId(NmLocalNode)) == 0) && (((pResource->State != ClusterResourceOffline) && (pResource->State != ClusterResourceFailed)) || (FmpGetGroupState( pResource->Group, TRUE ) != ClusterGroupOffline)) ) { dwStatus = ERROR_INVALID_STATE; goto FnExit; }
//make sure the node is on the list of possible nodes for this
// resource type
if (bAdd) { pListEntry = &(pResource->Type->PossibleNodeList); for (pListEntry = pListEntry->Flink; pListEntry != &(pResource->Type->PossibleNodeList); pListEntry = pListEntry->Flink) {
pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY, PossibleLinkage);
if (!lstrcmpW(OmObjectId(pResTypePosEntry->PossibleNode), pszNodeId)) { bNodeSupportsResType = TRUE; break; } } if (!bNodeSupportsResType) { dwStatus = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED; goto FnExit; } } pszResourceId = OmObjectId(pResource); dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
dwNodeLen = (lstrlenW(pszNodeId)+1)*sizeof(WCHAR);
dwBufSize = sizeof(GUM_CHANGE_POSSIBLE_NODE) - sizeof(WCHAR) + dwResourceLen + dwNodeLen; pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize); if (pGumChange == NULL) { CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY ); return(ERROR_NOT_ENOUGH_MEMORY); }
pGumChange->ResourceIdLen = dwResourceLen; CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen); CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen, pszNodeId, dwNodeLen);
*ppGumChange = pGumChange; *pdwBufSize = dwBufSize;
FnExit: return(dwStatus); } // FmpValChangeResourceNode
DWORD FmpValChangeResourceGroup( IN PFM_RESOURCE pResource, IN PFM_GROUP pNewGroup, OUT PGUM_CHANGE_GROUP *ppGumChange, OUT LPDWORD pdwBufSize) /*++
Routine Description:
Validation routine for changing a resource's group.
Arguments:
pResource - Pointer to the resource structure
pNewGroup - Pointer to the group to which the resource is moved to
ppGumChange - Message buffer to hold the resource info
pdwBufSize - Size of the message buffer
Comments:
Lock must be held when this routine is called
Returns:
ERROR_SUCCESS if validation is successful.
A Win32 error code otherwise.
--*/ { DWORD dwBufSize; LPCWSTR pszResourceId; DWORD dwResourceLen; LPCWSTR pszGroupId; DWORD dwGroupLen; DWORD dwStatus = ERROR_SUCCESS; PGUM_CHANGE_GROUP pGumChange; *pdwBufSize = 0; *ppGumChange = NULL;
// we need to validate here as well
// this is called by the server side
// this will help avoid a gum call if things have changed
// since the request started from the originator
// and got to the server
//if the resource has been marked for delete, then fail this call
if (!IS_VALID_FM_RESOURCE(pResource)) { dwStatus = ERROR_RESOURCE_NOT_AVAILABLE; goto FnExit; }
//
// Check if we're moving to same group.
//
if (pResource->Group == pNewGroup) { dwStatus = ERROR_ALREADY_EXISTS; goto FnExit; }
//
// 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 FnExit; }
pszResourceId = OmObjectId(pResource); dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
pszGroupId = OmObjectId(pNewGroup); dwGroupLen = (lstrlenW(pszGroupId)+1)*sizeof(WCHAR);
dwBufSize = sizeof(GUM_CHANGE_GROUP) - sizeof(WCHAR) + dwResourceLen + dwGroupLen; pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize); if (pGumChange == NULL) { dwStatus = ERROR_NOT_ENOUGH_MEMORY; goto FnExit; }
pGumChange->ResourceIdLen = dwResourceLen; CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen); CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen, pszGroupId, dwGroupLen);
*ppGumChange = pGumChange; *pdwBufSize = dwBufSize; FnExit: return(dwStatus); } // FmpValChangeResourceGroup
|