2025-04-27 07:49:33 -04:00

635 lines
17 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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);
}