Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2601 lines
80 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;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
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);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Startup (on create)" );
try {
Error = (Startup)( ResourceType,
CLRES_VERSION_V1_00,
CLRES_VERSION_V1_00,
RmpSetResourceStatus,
RmpLogEvent,
&FunctionTable );
} except (EXCEPTION_EXECUTE_HANDLER) {
Error = GetExceptionCode();
}
RmpSetMonitorState(RmonIdle, NULL);
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
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);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Open" );
//
// 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;
}
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
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;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
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;
RmpSetMonitorState(RmonDeletingResource, Resource);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Close" );
try {
#ifdef COMRES
RESMON_CLOSE (Resource) ;
#else
(Resource->Close)(Resource->Id);
#endif
} except (EXCEPTION_EXECUTE_HANDLER) {
}
Resource->dwEntryPoint = 0;
RmpSetMonitorState(RmonIdle, Resource);
RmpRemoveDeadlockMonitorList ( pDueTimeEntry );
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;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
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);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Arbitrate" );
#ifdef COMRES
status = RESMON_ARBITRATE (Resource, RmpLostQuorumResource) ;
#else
status = (Resource->Arbitrate)(Resource->Id,
RmpLostQuorumResource);
#endif
if (status == ERROR_SUCCESS) {
Resource->IsArbitrated = TRUE;
}
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
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;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
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);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Release" );
#ifdef COMRES
status = RESMON_RELEASE (Resource) ;
#else
status = (Resource->Release)(Resource->Id);
#endif
Resource->IsArbitrated = FALSE;
RmpSetMonitorState(RmonIdle, NULL);
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
#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;
BOOL fAddPollEvent = FALSE;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
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);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Online" );
//
// 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();
}
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
if (status == ERROR_SUCCESS) {
SetEvent( Resource->OnlineEvent );
CloseHandle( Resource->OnlineEvent );
Resource->OnlineEvent = NULL;
Resource->State = ClusterResourceOnline;
if ( eventHandle ) {
fAddPollEvent = TRUE;
}
} 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 );
Resource->State = ClusterResourceOnlinePending;
//
// If we have an event handle, then add it to our list.
//
if ( eventHandle ) {
fAddPollEvent = TRUE;
}
}
}
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;
}
*pdwState = Resource->State;
RmpSetMonitorState(RmonIdle, NULL);
ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
//
// Notify poller thread that the list has changed
//
if ( fAddPollEvent )
{
ClRtlLogPrint(LOG_NOISE,
"[RM] s_RmOnlineResource: Adding event 0x%1!08lx! for resource %2!ws!\n",
eventHandle,
Resource->ResourceName);
status = RmpAddPollEvent( (PPOLL_EVENT_LIST)Resource->EventList,
eventHandle,
Resource );
if ( status != ERROR_SUCCESS ) {
ClRtlLogPrint(LOG_CRITICAL,
"[RM] s_RmOnlineResource: Failed to add event 0x%1!08lx! for resource %2!ws!, error %3!u!.\n",
eventHandle,
Resource->ResourceName,
status );
CL_LOGFAILURE(status);
Resource->State = ClusterResourceFailed;
}
}
RmpSignalPoller((PPOLL_EVENT_LIST)Resource->EventList);
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;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
Resource = (PRESOURCE)ResourceId;
CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
// Inbuffer is [unique].
if ( InBuffer == NULL )
InBufferSize = 0;
else if ( InBufferSize == 0 )
InBuffer = NULL;
//
// 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 );
//
// If the control code is a notification for resource name change, modify the resource
// name field in the resource structure to reflect that.
//
if ( ControlCode == CLUSCTL_RESOURCE_SET_NAME )
{
LPWSTR lpszNewBuffer, lpszOldBuffer;
lpszNewBuffer = LocalAlloc ( LPTR, InBufferSize );
if ( lpszNewBuffer != NULL )
{
lstrcpyW ( lpszNewBuffer, ( LPWSTR ) InBuffer );
lpszOldBuffer = InterlockedExchangePointer ( &Resource->ResourceName, lpszNewBuffer );
LocalFree ( lpszOldBuffer );
}
}
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
Resource->ResourceType,
Resource->ResourceName,
L"Resource control" );
#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
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
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;
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
// InBuffer is [unique].
if ( InBuffer == NULL )
InBufferSize = 0;
else if ( InBufferSize == 0 )
InBuffer = NULL;
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);
//
// Insert the DLL & entry point info into the deadlock monitoring list. Make sure
// you remove the entry after you finish the entry point call, else you will kill
// this process on a FALSE deadlock positive.
//
pDueTimeEntry = RmpInsertDeadlockMonitorList ( DllName,
ResourceTypeName,
NULL,
L"Resource type control" );
status = (resourceTypeControl)( ResourceTypeName,
ControlCode,
InBuffer,
InBufferSize,
OutBuffer,
OutBufferSize,
BytesReturned );
RmpSetMonitorState(RmonIdle, NULL);
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
}
}
#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);
pDueTimeEntry = RmpInsertDeadlockMonitorList ( DllName,
ResourceTypeName,
NULL,
L"Resource Type Control" );
hr = IClusterResControl_ResourceTypeControl (
ResDllInterfaces.pClusterResControl,
pbResourceTypeName,
ControlCode,
&vtIn,
&vtOut,
BytesReturned,
&status);
RmpSetMonitorState(RmonIdle, NULL);
RmpRemoveDeadlockMonitorList( pDueTimeEntry );
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
error_status_t
s_RmUpdateDeadlockDetectionParams(
IN handle_t IDL_handle,
IN DWORD dwDeadlockDetectionTimeout
)
/*++
Routine Description:
Changes the poll intervals defined for a resource.
Arguments:
IDL_handle - Unused.
dwDeadlockDetectionTimeout - Deadlock detection timeout.
Return Value:
ERROR_SUCCESS if successful
Win32 error otherwise
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
//
// Use the default for deadlock timeout if 0 is passed in.
//
dwDeadlockDetectionTimeout =
( dwDeadlockDetectionTimeout == 0 ) ?
CLUSTER_RESOURCE_DLL_DEFAULT_DEADLOCK_TIMEOUT_SECS :
dwDeadlockDetectionTimeout;
//
// Initialize the deadlock monitoring subsystem if it is not already initialized.
//
dwStatus = RmpDeadlockMonitorInitialize ( dwDeadlockDetectionTimeout );
if ( dwStatus != ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_CRITICAL, "[RM] s_RmUpdateDeadlockDetectionParams: Unable to initialize the deadlock monitor, error %1!u!.\n",
dwStatus);
goto FnExit;
}
dwStatus = RmpUpdateDeadlockDetectionParams ( dwDeadlockDetectionTimeout );
if ( dwStatus != ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_CRITICAL, "[RM] s_RmUpdateDeadlockDetectionParams: Unable to update the parameters for deadlock monitor, error %1!u!.\n",
dwStatus);
goto FnExit;
}
FnExit:
return ( dwStatus );
} // s_RmUpdateDeadlockDetectionParams
#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