mirror of https://github.com/tongzx/nt5src
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.
2399 lines
70 KiB
2399 lines
70 KiB
/*++
|
|
|
|
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
|