635 lines
17 KiB
C
635 lines
17 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
reslist.c
|
||
|
||
Abstract:
|
||
|
||
Cluster resource list processing routines.
|
||
|
||
Author:
|
||
|
||
Rod Gamache (rodga) 21-Apr-1997
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "fmp.h"
|
||
|
||
|
||
//
|
||
// Global data
|
||
//
|
||
|
||
//
|
||
// Local function prototypes
|
||
//
|
||
DWORD
|
||
FmpAddResourceEntry(
|
||
IN OUT PRESOURCE_ENUM *Enum,
|
||
IN LPDWORD Allocated,
|
||
IN PFM_RESOURCE Resource
|
||
);
|
||
|
||
|
||
|
||
DWORD
|
||
FmpGetResourceList(
|
||
OUT PRESOURCE_ENUM *ReturnEnum,
|
||
IN PFM_GROUP Group
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enumerates all the list of all resources in the Group and returns their
|
||
state.
|
||
|
||
Arguments:
|
||
|
||
ReturnEnum - Returns the requested objects.
|
||
|
||
Resource - Supplies the resource to filter. (i.e. if you supply this, you
|
||
get a list of resources within that Resource)
|
||
|
||
If not present, all resources are returned.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
Win32 error code on error.
|
||
|
||
Notes:
|
||
|
||
This routine should be called with the LocalGroupLock held.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
PRESOURCE_ENUM resourceEnum = NULL;
|
||
DWORD allocated;
|
||
PFM_RESOURCE resource;
|
||
PLIST_ENTRY listEntry;
|
||
|
||
allocated = ENUM_GROW_SIZE;
|
||
|
||
resourceEnum = LocalAlloc(LMEM_FIXED, RESOURCE_SIZE(ENUM_GROW_SIZE));
|
||
if ( resourceEnum == NULL ) {
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto error_exit;
|
||
}
|
||
|
||
ZeroMemory( resourceEnum, RESOURCE_SIZE(ENUM_GROW_SIZE) );
|
||
//set the contains quorum to -1, if the quorum is present
|
||
// in this group then the containsquorum is set to the index
|
||
// of the quorum resource
|
||
// The quorum resource should be brought offline last and be
|
||
// brought online first so that the registry replication data
|
||
// can be flushed
|
||
resourceEnum->ContainsQuorum = -1;
|
||
//resourceEnum->EntryCount = 0;
|
||
|
||
//
|
||
// Enumerate all resources in the group.
|
||
//
|
||
for ( listEntry = Group->Contains.Flink;
|
||
listEntry != &(Group->Contains);
|
||
listEntry = listEntry->Flink ) {
|
||
resource = CONTAINING_RECORD( listEntry,
|
||
FM_RESOURCE,
|
||
ContainsLinkage );
|
||
status = FmpAddResourceEntry( &resourceEnum,
|
||
&allocated,
|
||
resource );
|
||
if ( status != ERROR_SUCCESS ) {
|
||
FmpDeleteResourceEnum( resourceEnum );
|
||
goto error_exit;
|
||
}
|
||
//check if the resource is a quorum resource
|
||
if (resource->QuorumResource)
|
||
resourceEnum->ContainsQuorum = resourceEnum->EntryCount - 1;
|
||
resourceEnum->Entry[resourceEnum->EntryCount-1].State = resource->PersistentState;
|
||
}
|
||
|
||
*ReturnEnum = resourceEnum;
|
||
return(ERROR_SUCCESS);
|
||
|
||
error_exit:
|
||
|
||
*ReturnEnum = NULL;
|
||
return(status);
|
||
|
||
} // FmpGetResourceList
|
||
|
||
|
||
|
||
DWORD
|
||
FmpOnlineResourceList(
|
||
IN PRESOURCE_ENUM ResourceEnum,
|
||
IN PFM_GROUP pGroup
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings online all resources in the Enum list.
|
||
|
||
Arguments:
|
||
|
||
ResourceEnum - The list of resources to bring online.
|
||
|
||
pGroup - the group with which the resources are associated.
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE resource;
|
||
DWORD status;
|
||
DWORD returnStatus = ERROR_SUCCESS;
|
||
DWORD i;
|
||
|
||
|
||
//
|
||
// If the cluster service is shutting and this is not the quorum group,
|
||
// then fail immediately. Otherwise, try to bring the quorum online first.
|
||
//
|
||
if ( FmpShutdown &&
|
||
ResourceEnum->ContainsQuorum == -1 ) {
|
||
return(ERROR_INVALID_STATE);
|
||
}
|
||
|
||
// if the quorum resource is contained in here, bring it online first
|
||
if (ResourceEnum->ContainsQuorum >= 0)
|
||
{
|
||
CL_ASSERT((DWORD)ResourceEnum->ContainsQuorum < ResourceEnum->EntryCount);
|
||
|
||
resource = OmReferenceObjectById( ObjectTypeResource,
|
||
ResourceEnum->Entry[ResourceEnum->ContainsQuorum].Id );
|
||
|
||
|
||
// the resource should not vanish, we are holding the group lock after all
|
||
CL_ASSERT(resource != NULL);
|
||
//
|
||
// If we fail to find a resource, then just continue
|
||
//
|
||
if ( resource != NULL ) {
|
||
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOnlineResourceList: Previous quorum resource state for %1!ws! is %2!u!\r\n",
|
||
OmObjectId(resource), ResourceEnum->Entry[ResourceEnum->ContainsQuorum].State);
|
||
|
||
if ( (ResourceEnum->Entry[ResourceEnum->ContainsQuorum].State == ClusterResourceOnline) ||
|
||
(ResourceEnum->Entry[ResourceEnum->ContainsQuorum].State == ClusterResourceFailed) ) {
|
||
//
|
||
// Now bring the resource online if that is it's current state.
|
||
//
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOnlineResourceList: trying to bring quorum resource %1!ws! online, state %2!u!\n",
|
||
OmObjectId(resource),
|
||
resource->State);
|
||
|
||
status = FmpOnlineResource( resource, FALSE );
|
||
if ( status != ERROR_SUCCESS ) {
|
||
returnStatus = status;
|
||
}
|
||
}
|
||
OmDereferenceObject( resource );
|
||
}
|
||
}
|
||
|
||
// SS::: TODO what happens to the persistent state of the
|
||
// other resources - is it handled correctly - note that this is
|
||
// called on moving a group
|
||
// Will the restart policy do the right thing in terms of bringing
|
||
// them online
|
||
// if the quorum resource has failed, dont bother trying
|
||
// to bring the rest of the resourcess online
|
||
if ((returnStatus != ERROR_SUCCESS) && (returnStatus != ERROR_IO_PENDING))
|
||
{
|
||
FmpSubmitRetryOnline(ResourceEnum);
|
||
goto FnExit;
|
||
}
|
||
|
||
// bring online all of the other resources
|
||
for ( i = 0; i < ResourceEnum->EntryCount; i++ ) {
|
||
resource = OmReferenceObjectById( ObjectTypeResource,
|
||
ResourceEnum->Entry[i].Id );
|
||
|
||
|
||
//
|
||
// If we fail to find a resource, then just continue.
|
||
//
|
||
if ( resource == NULL ) {
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
continue;
|
||
}
|
||
|
||
//quorum resource has already been handled
|
||
if (resource->QuorumResource)
|
||
{
|
||
OmDereferenceObject(resource);
|
||
continue;
|
||
}
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOnlineResourceList: Previous resource state for %1!ws! is %2!u!\r\n",
|
||
OmObjectId(resource), ResourceEnum->Entry[i].State);
|
||
|
||
if ( (ResourceEnum->Entry[i].State == ClusterResourceOnline) ||
|
||
(ResourceEnum->Entry[i].State == ClusterResourceFailed) ) {
|
||
//
|
||
// Now bring the resource online if that is it's current state.
|
||
//
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOnlineResourceList: trying to bring resource %1!ws! online\n",
|
||
OmObjectId(resource));
|
||
|
||
status = FmpOnlineResource( resource, FALSE );
|
||
if ( returnStatus == ERROR_SUCCESS ) {
|
||
returnStatus = status;
|
||
}
|
||
//if this resource didnt come online because the quorum resource
|
||
//didnt come online, dont bother bringing the other resources online
|
||
//just a waste of time
|
||
if (status == ERROR_QUORUM_RESOURCE_ONLINE_FAILED)
|
||
{
|
||
//submit a timer callback to try and bring these resources
|
||
//online
|
||
FmpSubmitRetryOnline(ResourceEnum);
|
||
OmDereferenceObject( resource );
|
||
break;
|
||
}
|
||
|
||
}
|
||
OmDereferenceObject( resource );
|
||
}
|
||
|
||
FnExit:
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOnlineResourceList: Exit, status=%1!u!\r\n",
|
||
returnStatus);
|
||
return(returnStatus);
|
||
|
||
} // FmpOnlineResourceList
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
FmpOfflineResourceList(
|
||
IN PRESOURCE_ENUM ResourceEnum,
|
||
IN BOOL Restore
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes offline all resources in the Enum list.
|
||
|
||
Arguments:
|
||
|
||
ResourceEnum - The list of resources to take offline.
|
||
|
||
Restore - TRUE if we should set the resource back to it's previous state
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE resource;
|
||
DWORD status=ERROR_SUCCESS;
|
||
DWORD returnStatus = ERROR_SUCCESS;
|
||
DWORD i;
|
||
CLUSTER_RESOURCE_STATE prevState;
|
||
|
||
// offline all resources except the quorum resource
|
||
for ( i = 0; i < ResourceEnum->EntryCount; i++ ) {
|
||
resource = OmReferenceObjectById( ObjectTypeResource,
|
||
ResourceEnum->Entry[i].Id );
|
||
|
||
if ( resource == NULL ) {
|
||
return(ERROR_RESOURCE_NOT_FOUND);
|
||
}
|
||
|
||
//quorum resource is brought offline last
|
||
if (resource->QuorumResource)
|
||
{
|
||
OmDereferenceObject(resource);
|
||
continue;
|
||
}
|
||
//
|
||
// Now take the Resource offline, if we own it.
|
||
//
|
||
if ( resource->Group->OwnerNode == NmLocalNode ) {
|
||
prevState = resource->State;
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOfflineResourceList: Bring non quorum resource offline\n");
|
||
|
||
status = FmpOfflineResource( resource, FALSE );
|
||
if ( Restore ) {
|
||
//FmpPropagateResourceState( resource, prevState );
|
||
//resource->State = prevState;
|
||
}
|
||
}
|
||
|
||
OmDereferenceObject( resource );
|
||
|
||
if ( (status != ERROR_SUCCESS) &&
|
||
(status != ERROR_IO_PENDING) ) {
|
||
return(status);
|
||
}
|
||
if ( status == ERROR_IO_PENDING ) {
|
||
returnStatus = ERROR_IO_PENDING;
|
||
}
|
||
|
||
}
|
||
|
||
// bring the quorum resource offline now
|
||
// This allows other resources to come offline and save their checkpoints
|
||
// The quorum resource offline should block till the resources have
|
||
// finished saving the checkpoint
|
||
if ((ResourceEnum->ContainsQuorum >= 0) && (returnStatus == ERROR_SUCCESS))
|
||
{
|
||
CL_ASSERT((DWORD)ResourceEnum->ContainsQuorum < ResourceEnum->EntryCount);
|
||
|
||
resource = OmReferenceObjectById( ObjectTypeResource,
|
||
ResourceEnum->Entry[ResourceEnum->ContainsQuorum].Id );
|
||
|
||
if ( resource == NULL ) {
|
||
return(ERROR_RESOURCE_NOT_FOUND);
|
||
}
|
||
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[FM] FmpOfflineResourceList: Bring quorum resource offline\n");
|
||
|
||
//
|
||
// Now take the Resource offline, if we own it.
|
||
//
|
||
if ( resource->Group->OwnerNode == NmLocalNode ) {
|
||
status = FmpOfflineResource( resource, FALSE );
|
||
}
|
||
|
||
OmDereferenceObject( resource );
|
||
|
||
if ( (status != ERROR_SUCCESS) &&
|
||
(status != ERROR_IO_PENDING) ) {
|
||
return(status);
|
||
}
|
||
if ( status == ERROR_IO_PENDING ) {
|
||
returnStatus = ERROR_IO_PENDING;
|
||
}
|
||
}
|
||
|
||
return(returnStatus);
|
||
|
||
} // FmpOfflineResourceList
|
||
|
||
|
||
|
||
DWORD
|
||
FmpTerminateResourceList(
|
||
PRESOURCE_ENUM ResourceEnum
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Terminates all resources in the Enum list.
|
||
|
||
Arguments:
|
||
|
||
ResourceEnum - The list of resources to take offline.
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE resource;
|
||
DWORD i;
|
||
|
||
for ( i = 0; i < ResourceEnum->EntryCount; i++ ) {
|
||
resource = OmReferenceObjectById( ObjectTypeResource,
|
||
ResourceEnum->Entry[i].Id );
|
||
|
||
if ( resource == NULL ) {
|
||
return(ERROR_RESOURCE_NOT_FOUND);
|
||
}
|
||
|
||
//
|
||
// Now take the Resource offline, if we own it.
|
||
//
|
||
if ( resource->Group->OwnerNode == NmLocalNode ) {
|
||
FmpTerminateResource( resource );
|
||
}
|
||
|
||
OmDereferenceObject( resource );
|
||
}
|
||
//for now we dont care about the return
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // FmpTerminateResourceList
|
||
|
||
|
||
|
||
DWORD
|
||
FmpAddResourceEntry(
|
||
IN OUT PRESOURCE_ENUM *Enum,
|
||
IN LPDWORD Allocated,
|
||
IN PFM_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Worker routine for the enumeration of 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 number of entries allocated.
|
||
Resource - The Resource object being enumerated.
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS - if successful.
|
||
A Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
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 = LocalAlloc(LMEM_FIXED, RESOURCE_SIZE(newAllocated));
|
||
if ( newEnum == NULL ) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
CopyMemory(newEnum, resourceEnum, RESOURCE_SIZE(*Allocated));
|
||
*Allocated = newAllocated;
|
||
*Enum = newEnum;
|
||
LocalFree(resourceEnum);
|
||
resourceEnum = newEnum;
|
||
}
|
||
|
||
//
|
||
// Initialize new entry
|
||
//
|
||
newId = LocalAlloc(LMEM_FIXED, (lstrlenW(OmObjectId(Resource))+1) * sizeof(WCHAR));
|
||
if ( newId == NULL ) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
lstrcpyW(newId, OmObjectId(Resource));
|
||
resourceEnum->Entry[resourceEnum->EntryCount].Id = newId;
|
||
++resourceEnum->EntryCount;
|
||
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // FmpAddResourceEntry
|
||
|
||
|
||
|
||
VOID
|
||
FmpDeleteResourceEnum(
|
||
IN PRESOURCE_ENUM Enum
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes an RESOURCE_ENUM and associated name strings.
|
||
|
||
Arguments:
|
||
|
||
Enum - The RESOURCE_ENUM to delete. This pointer can be NULL.
|
||
|
||
Returns:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
This routine will take a NULL input pointer and just return.
|
||
|
||
--*/
|
||
|
||
{
|
||
PRESOURCE_ENUM_ENTRY enumEntry;
|
||
DWORD i;
|
||
|
||
if ( Enum == NULL ) {
|
||
return;
|
||
}
|
||
|
||
for ( i = 0; i < Enum->EntryCount; i++ ) {
|
||
enumEntry = &Enum->Entry[i];
|
||
LocalFree(enumEntry->Id);
|
||
}
|
||
|
||
LocalFree(Enum);
|
||
return;
|
||
|
||
} // FmpDeleteResourceEnum
|
||
|
||
|
||
DWORD FmpSubmitRetryOnline(
|
||
IN PRESOURCE_ENUM pResourceEnum)
|
||
{
|
||
|
||
PFM_RESLIST_ONLINE_RETRY_INFO pFmOnlineRetryInfo;
|
||
PRESOURCE_ENUM_ENTRY enumEntry;
|
||
DWORD dwSizeofResourceEnum;
|
||
DWORD dwStatus = ERROR_SUCCESS;
|
||
DWORD i;
|
||
DWORD dwSize;
|
||
|
||
//there is nothing to do
|
||
if (pResourceEnum->EntryCount < 1)
|
||
goto FnExit;
|
||
|
||
dwSizeofResourceEnum = sizeof(RESOURCE_ENUM) - sizeof(RESOURCE_ENUM_ENTRY) +
|
||
(sizeof(RESOURCE_ENUM_ENTRY) * pResourceEnum->EntryCount);
|
||
pFmOnlineRetryInfo = LocalAlloc(LMEM_FIXED,
|
||
(sizeof(FM_RESLIST_ONLINE_RETRY_INFO) - sizeof(RESOURCE_ENUM) +
|
||
dwSizeofResourceEnum));
|
||
|
||
if (!pFmOnlineRetryInfo)
|
||
{
|
||
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
CL_UNEXPECTED_ERROR(dwStatus);
|
||
goto FnExit;
|
||
}
|
||
|
||
//SS: unused for now
|
||
//reference the group object
|
||
pFmOnlineRetryInfo->pGroup = NULL;
|
||
memcpy(&(pFmOnlineRetryInfo->ResourceEnum), pResourceEnum, dwSizeofResourceEnum);
|
||
|
||
// allocate memory for Resource ID's and copy them from pResourceEnum
|
||
for ( i = 0; i < pResourceEnum->EntryCount; i++ ) {
|
||
enumEntry = &pResourceEnum->Entry[i];
|
||
pFmOnlineRetryInfo->ResourceEnum.Entry[i].Id = NULL;
|
||
dwSize = (lstrlenW(enumEntry->Id) +1)*sizeof(WCHAR);
|
||
pFmOnlineRetryInfo->ResourceEnum.Entry[i].Id = (LPWSTR)(LocalAlloc(LMEM_FIXED,dwSize));
|
||
if (!pFmOnlineRetryInfo->ResourceEnum.Entry[i].Id )
|
||
{
|
||
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
CL_UNEXPECTED_ERROR(dwStatus);
|
||
goto FnExit;
|
||
}
|
||
CopyMemory(pFmOnlineRetryInfo->ResourceEnum.Entry[i].Id, enumEntry->Id, dwSize);
|
||
}
|
||
|
||
|
||
dwStatus = FmpQueueTimerActivity(FM_TIMER_RESLIST_ONLINE_RETRY,
|
||
FmpReslistOnlineRetryCb, pFmOnlineRetryInfo );
|
||
|
||
FnExit:
|
||
return(dwStatus);
|
||
}
|
||
|