|
|
/*++
Copyright (c) 1995-1997 Microsoft Corporation
Module Name:
resource.c
Abstract:
Implements the management of the resource list. This includes adding resources to the list and deleting them from the list.
Author:
John Vert (jvert) 1-Dec-1995
Revision History: Sivaprasad Padisetty (sivapad) 06-18-1997 Added the COM support
--*/ #include "resmonp.h"
#include "stdio.h"
#define RESMON_MODULE RESMON_MODULE_RMAPI
//
// Local data
//
//
// Function prototypes local to this module
//
LPWSTR GetParameter( IN HKEY ClusterKey, IN LPCWSTR ValueName );
//
// Local functions
//
DWORD s_RmLoadResourceTypeDll( IN handle_t IDL_handle, IN LPCWSTR lpszResourceType, IN LPCWSTR lpszDllName ) {
RESDLL_FNINFO ResDllFnInfo; #ifdef COMRES
RESDLL_INTERFACES ResDllInterfaces; #endif
DWORD dwStatus;
dwStatus = RmpLoadResType( lpszResourceType, lpszDllName, &ResDllFnInfo, #ifdef COMRES
&ResDllInterfaces, #endif
NULL);
if (ResDllFnInfo.hDll) FreeLibrary(ResDllFnInfo.hDll); #ifdef COMRES
if (ResDllInterfaces.pClusterResource) IClusterResource_Release (ResDllInterfaces.pClusterResource) ; if (ResDllInterfaces.pClusterQuorumResource) IClusterQuorumResource_Release (ResDllInterfaces.pClusterQuorumResource) ; if (ResDllInterfaces.pClusterResControl) IClusterResControl_Release ( ResDllInterfaces.pClusterResControl ) ; #endif //COMRES
return(dwStatus);
}
RESID s_RmCreateResource( IN handle_t IDL_handle, IN LPCWSTR DllName, IN LPCWSTR ResourceType, IN LPCWSTR ResourceId, IN DWORD LooksAlivePoll, IN DWORD IsAlivePoll, IN RM_NOTIFY_KEY NotifyKey, IN DWORD PendingTimeout, OUT LPDWORD Status ) /*++
Routine Description:
Creates a resource to be monitored by the resource monitor. This involves allocating necessary structures, and loading its DLL. This does *NOT* insert the resource into the monitoring list or attempt to bring the resource on-line.
Arguments:
IDL_handle - Supplies RPC binding handle, currently unused
DllName - Supplies the name of the resource DLL
ResourceType - Supplies the type of resource
ResourceId - Supplies the Id of this specific resource
LooksAlivePoll - Supplies the LooksAlive poll interval
IsAlivePoll - Supplies the IsAlive poll interval
PendingTimeout - Supplies the Pending Timeout value for this resource
NotifyKey - Supplies a key to be passed to the notification callback if this resource's state changes.
Return Value:
ResourceId - Returns a unique identifer to be used to identify this resource for later operations.
--*/
{ PRESOURCE Resource=NULL; DWORD Error; HKEY ResKey; PSTARTUP_ROUTINE Startup; PCLRES_FUNCTION_TABLE FunctionTable; DWORD quorumCapable; DWORD valueType; DWORD valueData; DWORD valueSize; DWORD retry; DWORD Reason; LPWSTR pszDllName = (LPWSTR) DllName;
CL_ASSERT(IsAlivePoll != 0);
Resource = RmpAlloc(sizeof(RESOURCE)); if (Resource == NULL) { Error = ERROR_NOT_ENOUGH_MEMORY; CL_LOGFAILURE(Error); goto ErrorExit; } ZeroMemory( Resource, sizeof(RESOURCE) ); //Resource->Dll = NULL;
//Resource->Flags = 0;
//Resource->DllName = NULL;
//Resource->ResourceType = NULL;
//Resource->ResourceId = NULL;
//Resource->ResourceName = NULL;
//Resource->TimerEvent = NULL;
//Resource->OnlineEvent = NULL;
//Resource->IsArbitrated = FALSE;
Resource->Signature = RESOURCE_SIGNATURE; Resource->NotifyKey = NotifyKey; Resource->LooksAlivePollInterval = LooksAlivePoll; Resource->IsAlivePollInterval = IsAlivePoll; Resource->State = ClusterResourceOffline;
if ( PendingTimeout <= 10 ) { Resource->PendingTimeout = PENDING_TIMEOUT; } else { Resource->PendingTimeout = PendingTimeout; }
Resource->DllName = RmpAlloc((lstrlenW(DllName) + 1)*sizeof(WCHAR)); if (Resource->DllName == NULL) { Error = ERROR_NOT_ENOUGH_MEMORY; CL_LOGFAILURE(Error); goto ErrorExit; } lstrcpyW(Resource->DllName, DllName);
Resource->ResourceType = RmpAlloc((lstrlenW(ResourceType) + 1)*sizeof(WCHAR)); if (Resource->ResourceType == NULL) { Error = ERROR_NOT_ENOUGH_MEMORY; CL_LOGFAILURE(Error); goto ErrorExit; } lstrcpyW(Resource->ResourceType, ResourceType);
Resource->ResourceId = RmpAlloc((lstrlenW(ResourceId) + 1)*sizeof(WCHAR)); if (Resource->ResourceId == NULL) { Error = ERROR_NOT_ENOUGH_MEMORY; CL_LOGFAILURE(Error); goto ErrorExit; } lstrcpyW(Resource->ResourceId, ResourceId);
// Expand any environment variables included in the DLL path name.
if ( wcschr( DllName, L'%' ) != NULL ) { pszDllName = ClRtlExpandEnvironmentStrings( DllName ); if ( pszDllName == NULL ) { Error = GetLastError(); ClRtlLogPrint(LOG_UNUSUAL, "[RM] Error expanding environment strings in '%1!ls!, error %2!u!.\n", DllName, Error); goto ErrorExit; } }
//
// Load the specified DLL and find the required entrypoints.
//
Resource->Dll = LoadLibraryW(pszDllName); if (Resource->Dll == NULL) { #ifdef COMRES
HRESULT hr ; CLSID clsid ; Error = GetLastError(); // Save the previous error. Return it instead of COM error on failure
ClRtlLogPrint(LOG_CRITICAL, "[RM] Error loading resource dll %1!ws!, error %2!u!.\n", pszDllName, Error);
hr = CLSIDFromProgID(DllName, &clsid) ;
if (FAILED (hr)) { ClRtlLogPrint(LOG_CRITICAL, "[RM] CLSIDFromProgID %1!ws!, hr = %2!u!.\n", DllName, hr);
hr = CLSIDFromString( (LPWSTR) DllName, //Pointer to the string representation of the CLSID
&clsid//Pointer to the CLSID
);
if (FAILED (hr)) { ClRtlLogPrint(LOG_CRITICAL, "[RM] CLSIDFromString Also failed %1!ws!, hr = %2!u!.\n", DllName, hr);
goto ComError ; } }
if ((hr = CoCreateInstance (&clsid, NULL, CLSCTX_ALL, &IID_IClusterResource, (LPVOID *) &Resource->pClusterResource)) != S_OK) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Error CoCreateInstance Prog ID %1!ws!, error %2!u!.\n", DllName, hr); goto ComError ; }
Resource->dwType = RESMON_TYPE_COM ;
hr = IClusterResource_QueryInterface (Resource->pClusterResource, &IID_IClusterQuorumResource, &Resource->pClusterQuorumResource) ; if (FAILED(hr)) Resource->pClusterQuorumResource = NULL ;
quorumCapable = (Resource->pClusterQuorumResource)?1:0 ;
hr = IClusterResource_QueryInterface ( Resource->pClusterResource, &IID_IClusterResControl, &Resource->pClusterResControl ) ; if (FAILED(hr)) Resource->pClusterResControl = NULL ; goto comOpened ; ComError: #else
Error = GetLastError(); #endif
ClRtlLogPrint(LOG_CRITICAL, "[RM] Error loading resource dll %1!ws!, error %2!u!.\n", DllName, Error); CL_LOGFAILURE(Error); ClusterLogEvent2(LOG_CRITICAL, LOG_CURRENT_MODULE, __FILE__, __LINE__, RMON_CANT_LOAD_RESTYPE, sizeof(Error), &Error, DllName, ResourceType); goto ErrorExit; } #ifdef COMRES
else { Resource->dwType = RESMON_TYPE_DLL ; } comOpened: #endif
//
// Invoke debugger if one is specified.
//
if ( RmpDebugger ) { //
// Wait for debugger to come online.
//
retry = 100; while ( retry-- && !IsDebuggerPresent() ) { Sleep(100); } OutputDebugStringA("[RM] Just loaded resource DLL "); OutputDebugStringW(DllName); OutputDebugStringA("\n"); DebugBreak(); }
#ifdef COMRES
if (Resource->dwType == RESMON_TYPE_DLL) { #endif
//
// We must have a startup routine to find all the other functions.
//
Startup = (PSTARTUP_ROUTINE)GetProcAddress(Resource->Dll, STARTUP_ROUTINE); if ( Startup != NULL ) { FunctionTable = NULL; RmpSetMonitorState(RmonStartingResource, Resource); try { Error = (Startup)( ResourceType, CLRES_VERSION_V1_00, CLRES_VERSION_V1_00, RmpSetResourceStatus, RmpLogEvent, &FunctionTable ); } except (EXCEPTION_EXECUTE_HANDLER) { Error = GetExceptionCode(); } RmpSetMonitorState(RmonIdle, NULL); if ( Error != ERROR_SUCCESS ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup call to %1!ws!, error %2!u!.\n", DllName, Error ); ClusterLogEvent2(LOG_CRITICAL, LOG_CURRENT_MODULE, __FILE__, __LINE__, RMON_CANT_INIT_RESTYPE, sizeof(Error), &Error, DllName, ResourceType); goto ErrorExit; } Error = ERROR_INVALID_DATA; if ( FunctionTable == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, FunctionTable is NULL!\n"); Reason = 0; ClusterLogEvent2(LOG_CRITICAL, LOG_CURRENT_MODULE, __FILE__, __LINE__, RMON_RESTYPE_BAD_TABLE, sizeof(Reason), &Reason, DllName, ResourceType); goto ErrorExit; } if ( FunctionTable->Version != CLRES_VERSION_V1_00 ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, Invalid Version Number!\n"); Reason = 1; ClusterLogEvent2(LOG_CRITICAL, LOG_CURRENT_MODULE, __FILE__, __LINE__, RMON_RESTYPE_BAD_TABLE, sizeof(Reason), &Reason, DllName, ResourceType); goto ErrorExit; } if ( FunctionTable->TableSize != CLRES_V1_FUNCTION_SIZE ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, Invalid function table size!\n"); Reason = 2; ClusterLogEvent2(LOG_CRITICAL, LOG_CURRENT_MODULE, __FILE__, __LINE__, RMON_RESTYPE_BAD_TABLE, sizeof(Reason), &Reason, DllName, ResourceType); goto ErrorExit; } #ifdef COMRES
Resource->pOpen = FunctionTable->V1Functions.Open; Resource->pClose = FunctionTable->V1Functions.Close; Resource->pOnline = FunctionTable->V1Functions.Online; Resource->pOffline = FunctionTable->V1Functions.Offline; Resource->pTerminate = FunctionTable->V1Functions.Terminate; Resource->pLooksAlive = FunctionTable->V1Functions.LooksAlive; Resource->pIsAlive = FunctionTable->V1Functions.IsAlive;
Resource->pArbitrate = FunctionTable->V1Functions.Arbitrate; Resource->pRelease = FunctionTable->V1Functions.Release; Resource->pResourceControl = FunctionTable->V1Functions.ResourceControl; Resource->pResourceTypeControl = FunctionTable->V1Functions.ResourceTypeControl;
Error = ERROR_INVALID_DATA; if ( Resource->pOpen == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Open routine for resource dll %1!ws!\n", DllName); goto ErrorExit; }
if ( Resource->pClose == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Close routine for resource dll %1!ws!\n", DllName); goto ErrorExit; }
if ( Resource->pOnline == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Online routine for resource dll %1!ws!\n", DllName); goto ErrorExit; }
if ( Resource->pOffline == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Offline routine for resource dll %1!ws!\n", DllName); goto ErrorExit; }
if ( Resource->pTerminate == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Terminate routine for resource dll %1!ws!\n", DllName); goto ErrorExit; }
if ( Resource->pLooksAlive == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null LooksAlive routine for resource dll %1!ws!\n", DllName); goto ErrorExit; }
if ( Resource->pIsAlive == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null IsAlive routine for resource dll %1!ws!\n", DllName); goto ErrorExit; } } else { ClRtlLogPrint(LOG_CRITICAL, "[RM] Could not find startup routine in resource DLL %1!ws!.\n", DllName); Error = ERROR_INVALID_DATA; goto ErrorExit; }
if ( (Resource->pArbitrate) && (Resource->pRelease) ) { quorumCapable = 1; } else { quorumCapable = 0; } } #else // COMRES
Resource->Open = FunctionTable->V1Functions.Open; Resource->Close = FunctionTable->V1Functions.Close; Resource->Online = FunctionTable->V1Functions.Online; Resource->Offline = FunctionTable->V1Functions.Offline; Resource->Terminate = FunctionTable->V1Functions.Terminate; Resource->LooksAlive = FunctionTable->V1Functions.LooksAlive; Resource->IsAlive = FunctionTable->V1Functions.IsAlive;
Resource->Arbitrate = FunctionTable->V1Functions.Arbitrate; Resource->Release = FunctionTable->V1Functions.Release; Resource->ResourceControl = FunctionTable->V1Functions.ResourceControl; Resource->ResourceTypeControl = FunctionTable->V1Functions.ResourceTypeControl;
Error = ERROR_INVALID_DATA; if ( Resource->Open == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Open routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
if ( Resource->Close == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Close routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
if ( Resource->Online == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Online routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
if ( Resource->Offline == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Offline routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
if ( Resource->Terminate == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Terminate routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
if ( Resource->LooksAlive == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null LooksAlive routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
if ( Resource->IsAlive == NULL ) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null IsAlive routine for resource dll %1!ws!\n", pszDllName); goto ErrorExit; }
} else { ClRtlLogPrint(LOG_CRITICAL, "[RM] Could not find startup routine in resource DLL %1!ws!.\n", pszDllName); Error = ERROR_INVALID_DATA; goto ErrorExit; }
if ( (Resource->Arbitrate) && (Resource->Release) ) { quorumCapable = 1; } else { quorumCapable = 0; } #endif // COMRES
Resource->State = ClusterResourceOffline;
//
// Open the resource's cluster registry key so that it can
// be easily accessed from the Create entrypoint.
//
Error = ClusterRegOpenKey(RmpResourcesKey, ResourceId, KEY_READ, &ResKey); if (Error != ERROR_SUCCESS) { CL_LOGFAILURE(Error); goto ErrorExit; }
//
// Get the resource name.
//
Resource->ResourceName = GetParameter( ResKey, CLUSREG_NAME_RES_NAME ); if ( Resource->ResourceName == NULL ) { Error = GetLastError(); ClusterRegCloseKey(ResKey); ClRtlLogPrint(LOG_UNUSUAL, "[RM] Error reading resource name for %1!ws!, error %2!u!.\n", Resource->ResourceId, Error); CL_LOGFAILURE(Error); goto ErrorExit; }
//
// Call Open entrypoint.
// This is done with the lock held to serialize calls to the
// resource DLL and serialize access to the shared memory region.
//
AcquireListLock();
RmpSetMonitorState(RmonInitializingResource, Resource);
//
// N.B. This is the only call that we make without locking the
// eventlist lock! We can't, because we don't know that the event
// list is yet.
//
try { #ifdef COMRES
Resource->Id = RESMON_OPEN (Resource, ResKey) ; #else
Resource->Id = (Resource->Open)(Resource->ResourceName, ResKey, Resource ); #endif
} except (EXCEPTION_EXECUTE_HANDLER) { SetLastError(GetExceptionCode()); Resource->Id = 0; } if (Resource->Id == 0) { Error = GetLastError(); } else { Error = RmpInsertResourceList(Resource, NULL); }
//set the monitor state and close the key
RmpSetMonitorState(RmonIdle, NULL); ClusterRegCloseKey(ResKey);
if (Error != ERROR_SUCCESS) { //CL_LOGFAILURE(Error);
ClRtlLogPrint(LOG_UNUSUAL, "[RM] RmpInsertResourceList failed, returned %1!u!\n", Error); ReleaseListLock(); goto ErrorExit;
}
ReleaseListLock();
if (Resource->Id == 0) { ClRtlLogPrint(LOG_CRITICAL, "[RM] Open of resource %1!ws! returned null!\n", Resource->ResourceName); if ( Error == ERROR_SUCCESS ) { Error = ERROR_RESOURCE_NOT_FOUND; } //CL_LOGFAILURE(Error);
goto ErrorExit; }
*Status = ERROR_SUCCESS;
if ( pszDllName != DllName ) { LocalFree( pszDllName ); }
//
// Resource object has been successfully loaded into memory and
// its entrypoints determined. We now have a valid RESID that
// can be used in subsequent calls.
//
return((RESID)Resource);
ErrorExit:
if (Resource != NULL) { if (Resource->Dll != NULL) { FreeLibrary(Resource->Dll); } #ifdef COMRES
if (Resource->pClusterResource) IClusterResource_Release (Resource->pClusterResource) ; if (Resource->pClusterQuorumResource) IClusterQuorumResource_Release (Resource->pClusterQuorumResource) ; if (Resource->pClusterResControl) IClusterResControl_Release ( Resource->pClusterResControl ) ; #endif
RmpFree(Resource->DllName); RmpFree(Resource->ResourceType); RmpFree(Resource->ResourceName); RmpFree(Resource->ResourceId); RmpFree(Resource); } if ( pszDllName != DllName ) { LocalFree( pszDllName ); } ClRtlLogPrint(LOG_CRITICAL, "[RM] Failed creating resource %1!ws!, error %2!u!.\n", ResourceId, Error); *Status = Error; return(0);
} // RmCreateResource
VOID s_RmCloseResource( IN OUT RESID *ResourceId )
/*++
Routine Description:
Closes the specified resource. This includes removing it from the poll list, freeing any associated memory, and unloading its DLL.
Arguments:
ResourceId - Supplies a pointer to the resource ID. This will be set to NULL after cleanup is complete to indicate to RPC that the client side context can be destroyed.
Return Value:
None.
--*/
{ PRESOURCE Resource; BOOL Closed;
Resource = (PRESOURCE)*ResourceId;
CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE); CL_ASSERT(Resource->Flags & RESOURCE_INSERTED);
AcquireListLock(); if (Resource->ListEntry.Flink != NULL) { RmpRemoveResourceList(Resource); Closed = FALSE; } else { Closed = TRUE; }
ReleaseListLock();
if (!Closed) { //
// Call the DLL to close the resource.
//
AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList ); //
// If the Online Thread is still pending, wait a little bit for it.
//
if ( Resource->TimerEvent ) { SetEvent( Resource->TimerEvent ); Resource->TimerEvent = NULL; } Resource->dwEntryPoint = RESDLL_ENTRY_CLOSE; try { #ifdef COMRES
RESMON_CLOSE (Resource) ; #else
(Resource->Close)(Resource->Id); #endif
} except (EXCEPTION_EXECUTE_HANDLER) { } Resource->dwEntryPoint = 0; ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList ); } Resource->Signature = 0;
if ( Resource->OnlineEvent ) { SetEvent( Resource->OnlineEvent ); CloseHandle( Resource->OnlineEvent ); Resource->OnlineEvent = NULL; }
//
// Free the resource dll.
//
#ifdef COMRES
if (Resource->dwType == RESMON_TYPE_DLL) { FreeLibrary(Resource->Dll); } else { IClusterResource_Release (Resource->pClusterResource) ; if (Resource->pClusterQuorumResource) IClusterQuorumResource_Release (Resource->pClusterQuorumResource) ; if (Resource->pClusterResControl) IClusterResControl_Release ( Resource->pClusterResControl ) ; } #else
FreeLibrary(Resource->Dll); #endif
RmpFree(Resource->DllName); RmpFree(Resource->ResourceType); RmpFree(Resource->ResourceName); RmpFree(Resource->ResourceId);
RmpFree(Resource);
*ResourceId = NULL;
} // RmCloseResource
VOID RPC_RESID_rundown( IN RESID Resource )
/*++
Routine Description:
RPC rundown procedure for a RESID. Just closes the handle.
Arguments:
Resource - supplies the RESID that is to be rundown.
Return Value:
None.
--*/
{ //
// Chittur Subbaraman (chitturs) - 5/10/2001
//
// Don't do anything on RPC rundown. If clussvc dies, then resmon main thread detects it and
// runs down (close, terminate) resources. Merely, closing the resource here may cause
// it to be delivered when resource dlls don't expect it.
//
#if 0
s_RmCloseResource(&Resource); #endif
} // RESID_rundown
error_status_t s_RmChangeResourceParams( IN RESID ResourceId, IN DWORD LooksAlivePoll, IN DWORD IsAlivePoll, IN DWORD PendingTimeout )
/*++
Routine Description:
Changes the poll intervals defined for a resource.
Arguments:
ResourceId - Supplies the resource ID.
LooksAlivePoll - Supplies the new LooksAlive poll in ms units
IsAlivePoll - Supplies the new IsAlive poll in ms units
Return Value:
ERROR_SUCCESS if successful
Win32 error otherwise
--*/
{ PRESOURCE Resource; BOOL Inserted;
//
// If the resmon is shutting down, just return since you can't trust any resource structures
// accessed below.
//
if ( RmpShutdown ) return ( ERROR_SUCCESS ); Resource = (PRESOURCE)ResourceId; CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE); AcquireListLock();
Inserted = (Resource->Flags & RESOURCE_INSERTED); if (Inserted) { //
// Remove the resource from the list, update its properties,
// and reinsert it. The reinsertion will put it back in the
// right spot to reflect the new poll intervals.
//
RmpRemoveResourceList(Resource); } Resource->LooksAlivePollInterval = LooksAlivePoll; Resource->IsAlivePollInterval = IsAlivePoll; Resource->PendingTimeout = PendingTimeout; if (Inserted) { RmpInsertResourceList( Resource, (PPOLL_EVENT_LIST) Resource->EventList); } ReleaseListLock();
return(ERROR_SUCCESS);
} // RmChangeResourcePoll
error_status_t s_RmArbitrateResource( IN RESID ResourceId )
/*++
Routine Description:
Arbitrate for the resource.
Arguments:
ResourceId - Supplies the resource to be arbitrated.
Return Value:
ERROR_SUCCESS if successful.
A Win32 error code on failure.
--*/
{ PRESOURCE Resource; DWORD status;
Resource = (PRESOURCE)ResourceId; CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
#ifdef COMRES
if (Resource->dwType == RESMON_TYPE_DLL) { if ( (Resource->pArbitrate == NULL) || (Resource->pRelease == NULL) ) { return(ERROR_NOT_QUORUM_CAPABLE); } } else { if (!Resource->pClusterQuorumResource) return(ERROR_NOT_QUORUM_CAPABLE); } #else
if ( (Resource->Arbitrate == NULL) || (Resource->Release == NULL) ) { return(ERROR_NOT_QUORUM_CAPABLE); } #endif
//
// Chittur Subbaraman (chitturs) - 10/15/99
//
// Commenting out lock acquisition - This is done so that the
// arbitration request can proceed into the disk resource without
// any blockage. There have been cases where either some resource
// gets blocked in its "IsAlive" with this lock held or the resmon
// itself calling into clussvc to set a property (for instance) and
// this call gets blocked there. This results in an arbitration stall
// and the clussvc on this node dies. Note that arbitrate only needs to
// be serialized with release and the disk resource is supposed
// to take care of that.
//
#if 0
//
// Lock the resource list and attempt to bring the resource on-line.
// The lock is required to synchronize access to the resource list and
// to serialize any calls to resource DLLs. Only one thread may be
// calling a resource DLL at any time. This prevents resource DLLs
// from having to worry about being thread-safe.
//
AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList ); #else
//
// Try to acquire spin lock for synchronizing with resource rundown.
// Return failure if you cannot get the lock.
//
if ( !RmpAcquireSpinLock( Resource, FALSE ) ) return ( ERROR_BUSY ); #endif
//
// Update shared state to indicate we are arbitrating a resource
//
RmpSetMonitorState(RmonArbitrateResource, Resource);
#ifdef COMRES
status = RESMON_ARBITRATE (Resource, RmpLostQuorumResource) ; #else
status = (Resource->Arbitrate)(Resource->Id, RmpLostQuorumResource); #endif
if (status == ERROR_SUCCESS) { Resource->IsArbitrated = TRUE; }
RmpSetMonitorState(RmonIdle, NULL);
#if 0
ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList ); #else
RmpReleaseSpinLock( Resource ); #endif
return(status);
} // s_RmArbitrateResource(
error_status_t s_RmReleaseResource( IN RESID ResourceId )
/*++
Routine Description:
Release the resource.
Arguments:
ResourceId - Supplies the resource to be released.
Return Value:
ERROR_SUCCESS if successful.
A Win32 error code on failure.
--*/
{ PRESOURCE Resource; DWORD status;
Resource = (PRESOURCE)ResourceId; CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
#ifdef COMRES
if (Resource->dwType == RESMON_TYPE_DLL) { if (Resource->pRelease == NULL) { return(ERROR_NOT_QUORUM_CAPABLE); } } else { if (!Resource->pClusterQuorumResource) return(ERROR_NOT_QUORUM_CAPABLE); } #else
if ( Resource->Release == NULL ) { return(ERROR_NOT_QUORUM_CAPABLE); } #endif
//
// Lock the resource list and attempt to bring the resource on-line.
// The lock is required to synchronize access to the resource list and
// to serialize any calls to resource DLLs. Only one thread may be
// calling a resource DLL at any time. This prevents resource DLLs
// from having to worry about being thread-safe.
//
#if 0 // Not needed right now
AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList ); #endif
//
// Update shared state to indicate we ar arbitrating a resource
//
RmpSetMonitorState(RmonReleaseResource, Resource);
#ifdef COMRES
status = RESMON_RELEASE (Resource) ; #else
status = (Resource->Release)(Resource->Id); #endif
Resource->IsArbitrated = FALSE;
RmpSetMonitorState(RmonIdle, NULL); #if 0 // Not needed right now
ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList ); #endif
return(status);
} // s_RmReleaseResource(
error_status_t s_RmOnlineResource( IN RESID ResourceId, OUT LPDWORD pdwState )
/*++
Routine Description:
Brings the specified resource into the online state.
Arguments:
ResourceId - Supplies the resource to be brought online.
pdwState - The new state of the resource is returned.
Return Value:
--*/
{ PRESOURCE Resource; DWORD status; HANDLE timerThread; HANDLE eventHandle = NULL; DWORD threadId;
Resource = (PRESOURCE)ResourceId; CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE); CL_ASSERT(Resource->EventHandle == NULL );
*pdwState = ClusterResourceFailed;
if ( Resource->State > ClusterResourcePending ) { return(ERROR_INVALID_STATE); }
//
// Create an event to allow the SetResourceStatus callback to synchronize
// execution with this thread.
//
if ( Resource->OnlineEvent ) { return(ERROR_NOT_READY); }
Resource->OnlineEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if ( Resource->OnlineEvent == NULL ) { return(GetLastError()); }
//
// Lock the resource list and attempt to bring the resource on-line.
// The lock is required to synchronize access to the resource list and
// to serialize any calls to resource DLLs. Only one thread may be
// calling a resource DLL at any time. This prevents resource DLLs
// from having to worry about being thread-safe.
//
AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
//
// Update shared state to indicate we are bringing a resource online
//
RmpSetMonitorState(RmonOnlineResource, Resource);
//
// Call Online entrypoint. Regardless of whether this succeeds or
// not, the resource has been successfully added to the list. If the
// online call fails, the resource immediately enters the failed state.
//
Resource->CheckPoint = 0; try { #ifdef COMRES
status = RESMON_ONLINE (Resource, &eventHandle) ; #else
status = (Resource->Online)(Resource->Id, &eventHandle); #endif
} except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } if (status == ERROR_SUCCESS) { SetEvent( Resource->OnlineEvent ); CloseHandle( Resource->OnlineEvent ); Resource->OnlineEvent = NULL;
if ( eventHandle ) { status = RmpAddPollEvent( (PPOLL_EVENT_LIST)Resource->EventList, eventHandle, Resource ); if ( status == ERROR_SUCCESS ) { Resource->State = ClusterResourceOnline; } else { CL_LOGFAILURE(status); Resource->State = ClusterResourceFailed; } } else { Resource->State = ClusterResourceOnline; } } else if ( status == ERROR_IO_PENDING ) { status = ERROR_SUCCESS; //
// If the Resource DLL returns pending, then start a timer.
//
CL_ASSERT(Resource->TimerEvent == NULL ); Resource->TimerEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if ( Resource->TimerEvent == NULL ) { CL_UNEXPECTED_ERROR(status = GetLastError()); } else { timerThread = CreateThread( NULL, 0, RmpTimerThread, Resource, 0, &threadId ); if ( timerThread == NULL ) { CL_UNEXPECTED_ERROR(status = GetLastError()); } else { //
// Chittur Subbaraman (chitturs) - 1/12/99
//
// Raise the timer thread priority to highest. This
// is necessary to avoid certain cases in which the
// timer thread is sluggish to close out the timer event
// handle before a second online. Note that there are
// no major performance implications by doing this since
// the timer thread is in a wait state most of the time.
//
if ( !SetThreadPriority( timerThread, THREAD_PRIORITY_HIGHEST ) ) { ClRtlLogPrint(LOG_UNUSUAL, "[RM] s_RmOnlineResource: Error setting priority of timer " "thread for resource %1!ws!\n", Resource->ResourceName); CL_LOGFAILURE( GetLastError() ); } CloseHandle( timerThread ); //
// If we have an event handle, then add it to our list.
//
if ( eventHandle ) { status = RmpAddPollEvent( (PPOLL_EVENT_LIST)Resource->EventList, eventHandle, Resource ); if ( status == ERROR_SUCCESS ) { Resource->State = ClusterResourceOnlinePending; } else { ClRtlLogPrint(LOG_UNUSUAL, "[RM] Failed to add event %1!u! for resource %2!ws!, error %3!u!.\n", eventHandle, Resource->ResourceName, status ); CL_LOGFAILURE(status); Resource->State = ClusterResourceFailed; } } else { Resource->State = ClusterResourceOnlinePending; //Resource->WaitHint = PENDING_TIMEOUT;
//Resource->CheckPoint = 0;
} } } SetEvent( Resource->OnlineEvent ); } else { CloseHandle( Resource->OnlineEvent ); Resource->OnlineEvent = NULL; ClRtlLogPrint(LOG_CRITICAL, "[RM] OnlineResource failed, resource %1!ws!, status = %2!u!.\n", Resource->ResourceName, status);
ClusterLogEvent1(LOG_CRITICAL, LOG_CURRENT_MODULE, __FILE__, __LINE__, RMON_ONLINE_FAILED, sizeof(status), &status, Resource->ResourceName); Resource->State = ClusterResourceFailed; }
RmpSetMonitorState(RmonIdle, NULL); ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
//
// Notify poller thread that the list has changed
//
RmpSignalPoller((PPOLL_EVENT_LIST)Resource->EventList);
*pdwState = Resource->State; return(status);
} // RmOnlineResource
VOID s_RmTerminateResource( IN RESID ResourceId )
/*++
Routine Description:
Brings the specified resource into the offline state immediately.
Arguments:
ResourceId - Supplies the resource to be brought online.
Return Value:
The new state of the resource.
--*/
{ DWORD State;
RmpOfflineResource(ResourceId, FALSE, &State);
return;
} // RmTerminateResource
error_status_t s_RmOfflineResource( IN RESID ResourceId, OUT LPDWORD pdwState )
/*++
Routine Description:
Brings the specified resource into the offline state by shutting it down gracefully.
Arguments:
ResourceId - Supplies the resource to be brought online. pdwState - Returns the new state of the resource.
Return Value:
ERROR_SUCCESS if successful, else returns code.
--*/
{ return(RmpOfflineResource(ResourceId, TRUE, pdwState));
} // RmOfflineResource
error_status_t s_RmFailResource( IN RESID ResourceId )
/*++
Routine Description:
Fail the given resource.
Arguments:
ResourceId - Supplies the resource ID.
Return Value:
ERROR_SUCCESS if successful
Win32 error otherwise
--*/
{ PRESOURCE Resource;
Resource = (PRESOURCE)ResourceId; CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
if ( Resource->State == ClusterResourceOnline ) { Resource->State = ClusterResourceFailed; RmpPostNotify(Resource, NotifyResourceStateChange); return(ERROR_SUCCESS); } else { return(ERROR_RESMON_INVALID_STATE); }
} // RmChangeResourcePoll
error_status_t s_RmShutdownProcess( IN handle_t IDL_handle )
/*++
Routine Description:
Set the shutdown flag and trigger a poller thread to exit. The termination of any poller thread will notify the main thread to clean up and shutdown.
Arguments:
IDL_handle - Supplies RPC binding handle, currently unused
Return Value:
ERROR_SUCCESS
--*/
{ //
// Check if we've already been called here before. This can happen
// as a result of the Failover Manager calling us to perform a clean
// shutdown. The main thread also will call here, in case it is shutting
// down because of a failure of one of the threads.
//
if ( !RmpShutdown ) { RmpShutdown = TRUE; //
// Wake up the main thread so that it can cleanup.
//
SetEvent( RmpRewaitEvent ); } return(ERROR_SUCCESS);
} // RmShutdownProcess
error_status_t s_RmResourceControl( IN RESID ResourceId, IN DWORD ControlCode, IN PUCHAR InBuffer, IN DWORD InBufferSize, OUT PUCHAR OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesReturned, OUT LPDWORD Required )
/*++
Routine Description:
Process a resource control request.
Arguments:
ResourceId - the resource that is being controlled.
ControlCode - the control request, reduced to just the function code.
InBuffer - the input buffer for this control request.
InBufferSize - the size of the input buffer.
OutBuffer - the output buffer.
OutBufferSize - the size of the output buffer.
BytesReturned - the number of bytes returned.
Required - the number of bytes required if OutBuffer is not big enough.
Return Value:
ERROR_SUCCESS if successful
A Win32 error code on failure
--*/
{ PRESOURCE Resource; DWORD status = ERROR_INVALID_FUNCTION;
Resource = (PRESOURCE)ResourceId; CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
//
// Lock the resource list and send down the control request.
// The lock is required to synchronize access to the resource list and
// to serialize any calls to resource DLLs. Only one thread may be
// calling a resource DLL at any time. This prevents resource DLLs
// from having to worry about being thread-safe.
//
AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
#ifdef COMRES
if (Resource->pResourceControl || Resource->pClusterResControl) { RmpSetMonitorState(RmonResourceControl, Resource); status = RESMON_RESOURCECONTROL( Resource, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned ); RmpSetMonitorState(RmonIdle, NULL); } #else
if ( Resource->ResourceControl ) { RmpSetMonitorState(RmonResourceControl, Resource); status = (Resource->ResourceControl)( Resource->Id, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned ); RmpSetMonitorState(RmonIdle, NULL); } #endif
if ( status == ERROR_INVALID_FUNCTION ) {
DWORD characteristics = CLUS_CHAR_UNKNOWN;
switch ( ControlCode ) {
case CLUSCTL_RESOURCE_GET_COMMON_PROPERTY_FMTS: status = ResUtilGetPropertyFormats( RmpResourceCommonProperties, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_GET_CLASS_INFO: if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) { *BytesReturned = 0; *Required = sizeof(CLUS_RESOURCE_CLASS_INFO); if ( OutBuffer == NULL ) { status = ERROR_SUCCESS; } else { status = ERROR_MORE_DATA; } } else { PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer; ptrResClassInfo->rc = CLUS_RESCLASS_UNKNOWN; ptrResClassInfo->SubClass = 0; *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO); status = ERROR_SUCCESS; } break;
case CLUSCTL_RESOURCE_GET_CHARACTERISTICS: #ifdef COMRES
if (Resource->dwType == RESMON_TYPE_DLL) { if ( (Resource->pArbitrate != NULL) && (Resource->pRelease != NULL) ) { characteristics = CLUS_CHAR_QUORUM; } } else { if (!Resource->pClusterQuorumResource) characteristics = CLUS_CHAR_QUORUM; } #else
if ( (Resource->Arbitrate != NULL) && (Resource->Release != NULL) ) { characteristics = CLUS_CHAR_QUORUM; } #endif
if ( OutBufferSize < sizeof(DWORD) ) { *BytesReturned = 0; *Required = sizeof(DWORD); if ( OutBuffer == NULL ) { status = ERROR_SUCCESS; } else { status = ERROR_MORE_DATA; } } else { *BytesReturned = sizeof(DWORD); *(LPDWORD)OutBuffer = characteristics; status = ERROR_SUCCESS; } break;
case CLUSCTL_RESOURCE_GET_FLAGS: status = RmpResourceGetFlags( Resource, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES: *BytesReturned = 0; status = ERROR_SUCCESS; break;
case CLUSCTL_RESOURCE_ENUM_COMMON_PROPERTIES: status = RmpResourceEnumCommonProperties( OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_GET_RO_COMMON_PROPERTIES: status = RmpResourceGetCommonProperties( Resource, TRUE, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES: status = RmpResourceGetCommonProperties( Resource, FALSE, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_VALIDATE_COMMON_PROPERTIES: status = RmpResourceValidateCommonProperties( Resource, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_SET_COMMON_PROPERTIES: status = RmpResourceSetCommonProperties( Resource, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES: status = RmpResourceEnumPrivateProperties( Resource, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES: if ( OutBufferSize < sizeof(DWORD) ) { *BytesReturned = 0; *Required = sizeof(DWORD); if ( OutBuffer == NULL ) { status = ERROR_SUCCESS; } else { status = ERROR_MORE_DATA; } } else { LPDWORD ptrDword = (LPDWORD) OutBuffer; *ptrDword = 0; *BytesReturned = sizeof(DWORD); status = ERROR_SUCCESS; } break;
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES: status = RmpResourceGetPrivateProperties( Resource, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES: status = RmpResourceValidatePrivateProperties( Resource, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES: status = RmpResourceSetPrivateProperties( Resource, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_SET_NAME: //
// Chittur Subbaraman (chitturs) - 6/28/99
//
// The setting of the name in the cluster registry is done
// in NT5 by clussvc. So, resmon does not have to do any work
// except return a success code in case a resource DLL returns
// ERROR_INVALID_FUNCTION.
//
status = ERROR_SUCCESS; break;
default: break; } } else { // If the function is returning a buffer size without
// copying data, move this info around to satisfy RPC.
if ( *BytesReturned > OutBufferSize ) { *Required = *BytesReturned; *BytesReturned = 0; status = ERROR_MORE_DATA; } } if ( ( status != ERROR_SUCCESS ) && ( status != ERROR_MORE_DATA ) && ( status != ERROR_INVALID_FUNCTION ) ) { ClRtlLogPrint(LOG_UNUSUAL, "[RM] s_RmResourceControl: Resource <%1!ws!> control operation " "0x%2!08lx! gives status=%3!u!...\n", Resource->ResourceName, ControlCode, status); }
ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
return(status);
} // RmResourceControl
error_status_t s_RmResourceTypeControl( IN handle_t IDL_handle, IN LPCWSTR ResourceTypeName, IN LPCWSTR DllName, IN DWORD ControlCode, IN PUCHAR InBuffer, IN DWORD InBufferSize, OUT PUCHAR OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesReturned, OUT LPDWORD Required )
/*++
Routine Description:
Process a resource type control request.
Arguments:
IDL_handle - not used.
ResourceTypeName - the resource type name that is being controlled.
DllName - the name of the dll.
ControlCode - the control request, reduced to just the function code.
InBuffer - the input buffer for this control request.
InBufferSize - the size of the input buffer.
OutBuffer - the output buffer.
OutBufferSize - the size of the output buffer.
BytesReturned - the number of bytes returned.
Required - the number of bytes required if OutBuffer is not big enough.
Return Value:
ERROR_SUCCESS if successful
A Win32 error code on failure
--*/
{
RESDLL_FNINFO ResDllFnInfo; #ifdef COMRES
RESDLL_INTERFACES ResDllInterfaces; #endif
DWORD status = ERROR_INVALID_FUNCTION; DWORD characteristics = CLUS_CHAR_UNKNOWN;
status = RmpLoadResType(ResourceTypeName, DllName, &ResDllFnInfo, #ifdef COMRES
&ResDllInterfaces, #endif
&characteristics);
if (status != ERROR_SUCCESS) { return(status); }
status = ERROR_INVALID_FUNCTION;
if (ResDllFnInfo.hDll && ResDllFnInfo.pResFnTable) {
PRESOURCE_TYPE_CONTROL_ROUTINE resourceTypeControl = NULL ;
resourceTypeControl = ResDllFnInfo.pResFnTable->V1Functions.ResourceTypeControl;
if (resourceTypeControl) { RmpSetMonitorState(RmonResourceTypeControl, NULL); status = (resourceTypeControl)( ResourceTypeName, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned ); RmpSetMonitorState(RmonIdle, NULL); } } #ifdef COMRES
else if (ResDllInterfaces.pClusterResControl) { HRESULT hr ; VARIANT vtIn, vtOut ; SAFEARRAY sfIn = {1, 0, 1, 0, InBuffer, {InBufferSize, 0} } ; SAFEARRAY sfOut = {1, FADF_FIXEDSIZE, 1, 0, OutBuffer, {OutBufferSize, 0} } ; SAFEARRAY *psfOut = &sfOut ; BSTR pbResourceTypeName ;
vtIn.vt = VT_ARRAY | VT_UI1 ; vtOut.vt = VT_ARRAY | VT_UI1 | VT_BYREF ;
vtIn.parray = &sfIn ; vtOut.pparray = &psfOut ;
pbResourceTypeName = SysAllocString (ResourceTypeName) ;
if (pbResourceTypeName == NULL) { CL_LOGFAILURE( ERROR_NOT_ENOUGH_MEMORY) ; goto FnExit ; // Use the default processing
} RmpSetMonitorState(RmonResourceTypeControl, NULL); hr = IClusterResControl_ResourceTypeControl ( ResDllInterfaces.pClusterResControl, pbResourceTypeName, ControlCode, &vtIn, &vtOut, BytesReturned, &status);
RmpSetMonitorState(RmonIdle, NULL); SysFreeString (pbResourceTypeName) ;
if (FAILED(hr)) { CL_LOGFAILURE(hr); // Use the default processing
status = ERROR_INVALID_FUNCTION; } } #endif
if ( status == ERROR_INVALID_FUNCTION ) {
switch ( ControlCode ) {
case CLUSCTL_RESOURCE_TYPE_GET_COMMON_RESOURCE_PROPERTY_FMTS: status = ResUtilGetPropertyFormats( RmpResourceTypeCommonProperties, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_GET_CLASS_INFO: if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) { *BytesReturned = 0; *Required = sizeof(CLUS_RESOURCE_CLASS_INFO); if ( OutBuffer == NULL ) { status = ERROR_SUCCESS; } else { status = ERROR_MORE_DATA; } } else { PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer; ptrResClassInfo->rc = CLUS_RESCLASS_UNKNOWN; ptrResClassInfo->SubClass = 0; *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO); status = ERROR_SUCCESS; } break;
case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES: *BytesReturned = 0; status = ERROR_SUCCESS; break;
case CLUSCTL_RESOURCE_TYPE_GET_CHARACTERISTICS: if ( OutBufferSize < sizeof(DWORD) ) { *BytesReturned = 0; *Required = sizeof(DWORD); if ( OutBuffer == NULL ) { status = ERROR_SUCCESS; } else { status = ERROR_MORE_DATA; } } else { *BytesReturned = sizeof(DWORD); *(LPDWORD)OutBuffer = characteristics; status = ERROR_SUCCESS; } break;
case CLUSCTL_RESOURCE_TYPE_GET_FLAGS: status = RmpResourceTypeGetFlags( ResourceTypeName, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_GET_REGISTRY_CHECKPOINTS: *BytesReturned = 0; *Required = 0; status = ERROR_SUCCESS; break;
case CLUSCTL_RESOURCE_TYPE_ENUM_COMMON_PROPERTIES: status = RmpResourceTypeEnumCommonProperties( ResourceTypeName, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_GET_RO_COMMON_PROPERTIES: status = RmpResourceTypeGetCommonProperties( ResourceTypeName, TRUE, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES: status = RmpResourceTypeGetCommonProperties( ResourceTypeName, FALSE, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_VALIDATE_COMMON_PROPERTIES: status = RmpResourceTypeValidateCommonProperties( ResourceTypeName, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_TYPE_SET_COMMON_PROPERTIES: status = RmpResourceTypeSetCommonProperties( ResourceTypeName, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES: status = RmpResourceTypeEnumPrivateProperties( ResourceTypeName, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_GET_RO_PRIVATE_PROPERTIES: if ( OutBufferSize < sizeof(DWORD) ) { *BytesReturned = 0; *Required = sizeof(DWORD); if ( OutBuffer == NULL ) { status = ERROR_SUCCESS; } else { status = ERROR_MORE_DATA; } } else { LPDWORD ptrDword = (LPDWORD) OutBuffer; *ptrDword = 0; *BytesReturned = sizeof(DWORD); status = ERROR_SUCCESS; } break;
case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_PROPERTIES: status = RmpResourceTypeGetPrivateProperties( ResourceTypeName, OutBuffer, OutBufferSize, BytesReturned, Required ); break;
case CLUSCTL_RESOURCE_TYPE_VALIDATE_PRIVATE_PROPERTIES: status = RmpResourceTypeValidatePrivateProperties( ResourceTypeName, InBuffer, InBufferSize ); break;
case CLUSCTL_RESOURCE_TYPE_SET_PRIVATE_PROPERTIES: status = RmpResourceTypeSetPrivateProperties( ResourceTypeName, InBuffer, InBufferSize ); break;
default: break;
} } else { // If the function is returning a buffer size without
// copying data, move this info around to satisfy RPC.
if ( *BytesReturned > OutBufferSize ) { *Required = *BytesReturned; *BytesReturned = 0; } if ( (status == ERROR_MORE_DATA) && (OutBuffer == NULL) ) { status = ERROR_SUCCESS; } }
FnExit:
if (ResDllFnInfo.hDll) FreeLibrary(ResDllFnInfo.hDll); #ifdef COMRES
if (ResDllInterfaces.pClusterResource) IClusterResource_Release (ResDllInterfaces.pClusterResource) ; if (ResDllInterfaces.pClusterQuorumResource) IClusterQuorumResource_Release (ResDllInterfaces.pClusterQuorumResource) ; if (ResDllInterfaces.pClusterResControl) IClusterResControl_Release ( ResDllInterfaces.pClusterResControl ) ; #endif
return(status);
} // RmResourceTypeControl
LPWSTR GetParameter( IN HKEY ClusterKey, IN LPCWSTR ValueName )
/*++
Routine Description:
Reads a REG_SZ parameter from the cluster regitry, and allocates the necessary storage for it.
Arguments:
ClusterKey - supplies the cluster key where the parameter is stored.
ValueName - supplies the name of the value.
Return Value:
A pointer to a buffer containing the parameter value on success.
NULL on failure.
--*/
{ LPWSTR value; DWORD valueLength; DWORD valueType; DWORD status;
valueLength = 0; status = ClusterRegQueryValue( ClusterKey, ValueName, &valueType, NULL, &valueLength ); if ( (status != ERROR_SUCCESS) && (status != ERROR_MORE_DATA) ) { SetLastError(status); return(NULL); } if ( valueType == REG_SZ ) { valueLength += sizeof(UNICODE_NULL); } value = LocalAlloc(LMEM_FIXED, valueLength); if ( value == NULL ) { return(NULL); } status = ClusterRegQueryValue(ClusterKey, ValueName, &valueType, (LPBYTE)value, &valueLength); if ( status != ERROR_SUCCESS) { LocalFree(value); SetLastError(status); value = NULL; }
return(value);
} // GetParameter
#ifdef COMRES
RESID Resmon_Open ( IN PRESOURCE Resource, IN HKEY ResourceKey ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pOpen) (Resource->ResourceName, ResourceKey, Resource) ; } else { HRESULT hr ; OLERESID ResId = 0 ;
BSTR pbResourceName = SysAllocString (Resource->ResourceName) ;
if (pbResourceName == NULL) { SetLastError ( ERROR_NOT_ENOUGH_MEMORY) ; CL_LOGFAILURE( ERROR_NOT_ENOUGH_MEMORY) ; goto ErrorExit ; }
hr = IClusterResource_Open(Resource->pClusterResource, pbResourceName, (OLEHKEY)ResourceKey, (OLERESOURCE_HANDLE)Resource, &ResId);
SysFreeString (pbResourceName) ;
if (FAILED(hr)) { SetLastError (hr) ; CL_LOGFAILURE(hr); } ErrorExit: return (RESID) ResId ; } }
VOID Resmon_Close ( IN PRESOURCE Resource ) { if (Resource->dwType == RESMON_TYPE_DLL) { (Resource->pClose) (Resource->Id) ; } else { HRESULT hr ;
hr = IClusterResource_Close (Resource->pClusterResource, (OLERESID)Resource->Id); if (FAILED(hr)) { SetLastError (hr) ; CL_LOGFAILURE(hr); } } }
DWORD Resmon_Online ( IN PRESOURCE Resource, IN OUT LPHANDLE EventHandle ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pOnline) (Resource->Id, EventHandle) ; } else { HRESULT hr ; long lRet ;
hr = IClusterResource_Online(Resource->pClusterResource, (OLERESID)Resource->Id, (LPOLEHANDLE)EventHandle, &lRet);
if (FAILED(hr)) { SetLastError (lRet = hr) ; // Return a error
CL_LOGFAILURE(hr); } return lRet ; } }
DWORD Resmon_Offline ( IN PRESOURCE Resource ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pOffline) (Resource->Id) ; } else { HRESULT hr ; long lRet ;
hr = IClusterResource_Offline(Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
if (FAILED(hr)) { SetLastError (lRet = hr) ; // Return a error
CL_LOGFAILURE(hr); } return lRet ; } }
VOID Resmon_Terminate ( IN PRESOURCE Resource ) { if (Resource->dwType == RESMON_TYPE_DLL) { (Resource->pTerminate) (Resource->Id) ; } else { HRESULT hr ;
hr = IClusterResource_Terminate (Resource->pClusterResource, (OLERESID)Resource->Id); if (FAILED(hr)) { SetLastError (hr) ; CL_LOGFAILURE(hr); } } }
BOOL Resmon_LooksAlive ( IN PRESOURCE Resource ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pLooksAlive) (Resource->Id) ; } else { HRESULT hr ; long lRet ;
hr = IClusterResource_LooksAlive (Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
if (FAILED(hr)) { SetLastError (hr) ; CL_LOGFAILURE(hr); lRet = 0 ; // Incase of failure return 0 to indicate LooksAlive is failed.
} return lRet ; } }
BOOL Resmon_IsAlive ( IN PRESOURCE Resource ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pIsAlive) (Resource->Id) ; } else { HRESULT hr ; long lRet ;
hr = IClusterResource_IsAlive (Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
if (FAILED(hr)) { SetLastError (hr) ; CL_LOGFAILURE(hr); lRet = 0 ; // Incase of failure return 0 to indicate IsAlive is failed.
} return lRet ; } }
DWORD Resmon_Arbitrate ( IN PRESOURCE Resource, IN PQUORUM_RESOURCE_LOST LostQuorumResource ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pArbitrate) (Resource->Id, LostQuorumResource) ; } else { HRESULT hr ; long lRet ;
hr = IClusterQuorumResource_QuorumArbitrate(Resource->pClusterQuorumResource, (OLERESID)Resource->Id, (POLEQUORUM_RESOURCE_LOST)LostQuorumResource, &lRet);
if (FAILED(hr)) { SetLastError (lRet = hr) ; CL_LOGFAILURE(hr); } return lRet ; } }
DWORD Resmon_Release ( IN PRESOURCE Resource ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pRelease) (Resource->Id) ; } else { HRESULT hr ; long lRet ;
hr = IClusterQuorumResource_QuorumRelease(Resource->pClusterQuorumResource, (OLERESID)Resource->Id, &lRet);
if (FAILED(hr)) { SetLastError (lRet = hr) ; CL_LOGFAILURE(hr); } return lRet ; } }
DWORD Resmon_ResourceControl ( IN PRESOURCE Resource, IN DWORD ControlCode, IN PVOID InBuffer, IN DWORD InBufferSize, OUT PVOID OutBuffer, IN DWORD OutBufferSize, OUT LPDWORD BytesReturned ) { if (Resource->dwType == RESMON_TYPE_DLL) { return (Resource->pResourceControl)( Resource->Id, ControlCode, InBuffer, InBufferSize, OutBuffer, OutBufferSize, BytesReturned ); } else { long status ; HRESULT hr ; VARIANT vtIn, vtOut ; SAFEARRAY sfIn = {1, 0, 1, 0, InBuffer, {InBufferSize, 0} } ; SAFEARRAY sfOut = {1, FADF_FIXEDSIZE, 1, 0, OutBuffer, {OutBufferSize, 0} } ; SAFEARRAY *psfOut = &sfOut ;
vtIn.vt = VT_ARRAY | VT_UI1 ; vtOut.vt = VT_ARRAY | VT_UI1 | VT_BYREF ;
vtIn.parray = &sfIn ; vtOut.pparray = &psfOut ;
hr = IClusterResControl_ResourceControl ( Resource->pClusterResControl, (OLERESID)Resource->Id, (long)ControlCode, &vtIn, &vtOut, (long *)BytesReturned, &status);
if (FAILED(hr)) { CL_LOGFAILURE(hr); // Use the default processing
status = ERROR_INVALID_FUNCTION; }
return (DWORD)status ; } }
#endif // COMRES
|