Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

803 lines
18 KiB

/*++
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 &&
(pszNodeId == OmObjectId(NmLocalNode)) &&
(((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