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

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name:
  4. resource.c
  5. Abstract:
  6. Implements the management of the resource list. This includes
  7. adding resources to the list and deleting them from the list.
  8. Author:
  9. John Vert (jvert) 1-Dec-1995
  10. Revision History:
  11. Sivaprasad Padisetty (sivapad) 06-18-1997 Added the COM support
  12. --*/
  13. #include "resmonp.h"
  14. #include "stdio.h"
  15. #define RESMON_MODULE RESMON_MODULE_RMAPI
  16. //
  17. // Local data
  18. //
  19. //
  20. // Function prototypes local to this module
  21. //
  22. LPWSTR
  23. GetParameter(
  24. IN HKEY ClusterKey,
  25. IN LPCWSTR ValueName
  26. );
  27. //
  28. // Local functions
  29. //
  30. DWORD s_RmLoadResourceTypeDll(
  31. IN handle_t IDL_handle,
  32. IN LPCWSTR lpszResourceType,
  33. IN LPCWSTR lpszDllName
  34. )
  35. {
  36. RESDLL_FNINFO ResDllFnInfo;
  37. #ifdef COMRES
  38. RESDLL_INTERFACES ResDllInterfaces;
  39. #endif
  40. DWORD dwStatus;
  41. dwStatus = RmpLoadResType(
  42. lpszResourceType,
  43. lpszDllName,
  44. &ResDllFnInfo,
  45. #ifdef COMRES
  46. &ResDllInterfaces,
  47. #endif
  48. NULL);
  49. if (ResDllFnInfo.hDll)
  50. FreeLibrary(ResDllFnInfo.hDll);
  51. #ifdef COMRES
  52. if (ResDllInterfaces.pClusterResource)
  53. IClusterResource_Release (ResDllInterfaces.pClusterResource) ;
  54. if (ResDllInterfaces.pClusterQuorumResource)
  55. IClusterQuorumResource_Release (ResDllInterfaces.pClusterQuorumResource) ;
  56. if (ResDllInterfaces.pClusterResControl)
  57. IClusterResControl_Release (
  58. ResDllInterfaces.pClusterResControl
  59. ) ;
  60. #endif //COMRES
  61. return(dwStatus);
  62. }
  63. RESID
  64. s_RmCreateResource(
  65. IN handle_t IDL_handle,
  66. IN LPCWSTR DllName,
  67. IN LPCWSTR ResourceType,
  68. IN LPCWSTR ResourceId,
  69. IN DWORD LooksAlivePoll,
  70. IN DWORD IsAlivePoll,
  71. IN RM_NOTIFY_KEY NotifyKey,
  72. IN DWORD PendingTimeout,
  73. OUT LPDWORD Status
  74. )
  75. /*++
  76. Routine Description:
  77. Creates a resource to be monitored by the resource monitor.
  78. This involves allocating necessary structures, and loading its DLL.
  79. This does *NOT* insert the resource into the monitoring list or
  80. attempt to bring the resource on-line.
  81. Arguments:
  82. IDL_handle - Supplies RPC binding handle, currently unused
  83. DllName - Supplies the name of the resource DLL
  84. ResourceType - Supplies the type of resource
  85. ResourceId - Supplies the Id of this specific resource
  86. LooksAlivePoll - Supplies the LooksAlive poll interval
  87. IsAlivePoll - Supplies the IsAlive poll interval
  88. PendingTimeout - Supplies the Pending Timeout value for this resource
  89. NotifyKey - Supplies a key to be passed to the notification
  90. callback if this resource's state changes.
  91. Return Value:
  92. ResourceId - Returns a unique identifer to be used to identify
  93. this resource for later operations.
  94. --*/
  95. {
  96. PRESOURCE Resource=NULL;
  97. DWORD Error;
  98. HKEY ResKey;
  99. PSTARTUP_ROUTINE Startup;
  100. PCLRES_FUNCTION_TABLE FunctionTable;
  101. DWORD quorumCapable;
  102. DWORD valueType;
  103. DWORD valueData;
  104. DWORD valueSize;
  105. DWORD retry;
  106. DWORD Reason;
  107. LPWSTR pszDllName = (LPWSTR) DllName;
  108. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  109. CL_ASSERT(IsAlivePoll != 0);
  110. Resource = RmpAlloc(sizeof(RESOURCE));
  111. if (Resource == NULL) {
  112. Error = ERROR_NOT_ENOUGH_MEMORY;
  113. CL_LOGFAILURE(Error);
  114. goto ErrorExit;
  115. }
  116. ZeroMemory( Resource, sizeof(RESOURCE) );
  117. //Resource->Dll = NULL;
  118. //Resource->Flags = 0;
  119. //Resource->DllName = NULL;
  120. //Resource->ResourceType = NULL;
  121. //Resource->ResourceId = NULL;
  122. //Resource->ResourceName = NULL;
  123. //Resource->TimerEvent = NULL;
  124. //Resource->OnlineEvent = NULL;
  125. //Resource->IsArbitrated = FALSE;
  126. Resource->Signature = RESOURCE_SIGNATURE;
  127. Resource->NotifyKey = NotifyKey;
  128. Resource->LooksAlivePollInterval = LooksAlivePoll;
  129. Resource->IsAlivePollInterval = IsAlivePoll;
  130. Resource->State = ClusterResourceOffline;
  131. if ( PendingTimeout <= 10 ) {
  132. Resource->PendingTimeout = PENDING_TIMEOUT;
  133. } else {
  134. Resource->PendingTimeout = PendingTimeout;
  135. }
  136. Resource->DllName = RmpAlloc((lstrlenW(DllName) + 1)*sizeof(WCHAR));
  137. if (Resource->DllName == NULL) {
  138. Error = ERROR_NOT_ENOUGH_MEMORY;
  139. CL_LOGFAILURE(Error);
  140. goto ErrorExit;
  141. }
  142. lstrcpyW(Resource->DllName, DllName);
  143. Resource->ResourceType = RmpAlloc((lstrlenW(ResourceType) + 1)*sizeof(WCHAR));
  144. if (Resource->ResourceType == NULL) {
  145. Error = ERROR_NOT_ENOUGH_MEMORY;
  146. CL_LOGFAILURE(Error);
  147. goto ErrorExit;
  148. }
  149. lstrcpyW(Resource->ResourceType, ResourceType);
  150. Resource->ResourceId = RmpAlloc((lstrlenW(ResourceId) + 1)*sizeof(WCHAR));
  151. if (Resource->ResourceId == NULL) {
  152. Error = ERROR_NOT_ENOUGH_MEMORY;
  153. CL_LOGFAILURE(Error);
  154. goto ErrorExit;
  155. }
  156. lstrcpyW(Resource->ResourceId, ResourceId);
  157. // Expand any environment variables included in the DLL path name.
  158. if ( wcschr( DllName, L'%' ) != NULL ) {
  159. pszDllName = ClRtlExpandEnvironmentStrings( DllName );
  160. if ( pszDllName == NULL ) {
  161. Error = GetLastError();
  162. ClRtlLogPrint(LOG_UNUSUAL, "[RM] Error expanding environment strings in '%1!ls!, error %2!u!.\n",
  163. DllName,
  164. Error);
  165. goto ErrorExit;
  166. }
  167. }
  168. //
  169. // Load the specified DLL and find the required entrypoints.
  170. //
  171. Resource->Dll = LoadLibraryW(pszDllName);
  172. if (Resource->Dll == NULL) {
  173. #ifdef COMRES
  174. HRESULT hr ;
  175. CLSID clsid ;
  176. Error = GetLastError(); // Save the previous error. Return it instead of COM error on failure
  177. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error loading resource dll %1!ws!, error %2!u!.\n",
  178. pszDllName, Error);
  179. hr = CLSIDFromProgID(DllName, &clsid) ;
  180. if (FAILED (hr))
  181. {
  182. ClRtlLogPrint(LOG_CRITICAL, "[RM] CLSIDFromProgID %1!ws!, hr = %2!u!.\n",
  183. DllName, hr);
  184. hr = CLSIDFromString( (LPWSTR) DllName, //Pointer to the string representation of the CLSID
  185. &clsid//Pointer to the CLSID
  186. );
  187. if (FAILED (hr))
  188. {
  189. ClRtlLogPrint(LOG_CRITICAL, "[RM] CLSIDFromString Also failed %1!ws!, hr = %2!u!.\n",
  190. DllName, hr);
  191. goto ComError ;
  192. }
  193. }
  194. if ((hr = CoCreateInstance (&clsid, NULL, CLSCTX_ALL, &IID_IClusterResource, (LPVOID *) &Resource->pClusterResource)) != S_OK)
  195. {
  196. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error CoCreateInstance Prog ID %1!ws!, error %2!u!.\n", DllName, hr);
  197. goto ComError ;
  198. }
  199. Resource->dwType = RESMON_TYPE_COM ;
  200. hr = IClusterResource_QueryInterface (Resource->pClusterResource, &IID_IClusterQuorumResource,
  201. &Resource->pClusterQuorumResource) ;
  202. if (FAILED(hr))
  203. Resource->pClusterQuorumResource = NULL ;
  204. quorumCapable = (Resource->pClusterQuorumResource)?1:0 ;
  205. hr = IClusterResource_QueryInterface (
  206. Resource->pClusterResource,
  207. &IID_IClusterResControl,
  208. &Resource->pClusterResControl
  209. ) ;
  210. if (FAILED(hr))
  211. Resource->pClusterResControl = NULL ;
  212. goto comOpened ;
  213. ComError:
  214. #else
  215. Error = GetLastError();
  216. #endif
  217. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error loading resource dll %1!ws!, error %2!u!.\n",
  218. DllName, Error);
  219. CL_LOGFAILURE(Error);
  220. ClusterLogEvent2(LOG_CRITICAL,
  221. LOG_CURRENT_MODULE,
  222. __FILE__,
  223. __LINE__,
  224. RMON_CANT_LOAD_RESTYPE,
  225. sizeof(Error),
  226. &Error,
  227. DllName,
  228. ResourceType);
  229. goto ErrorExit;
  230. }
  231. #ifdef COMRES
  232. else {
  233. Resource->dwType = RESMON_TYPE_DLL ;
  234. }
  235. comOpened:
  236. #endif
  237. //
  238. // Invoke debugger if one is specified.
  239. //
  240. if ( RmpDebugger ) {
  241. //
  242. // Wait for debugger to come online.
  243. //
  244. retry = 100;
  245. while ( retry-- &&
  246. !IsDebuggerPresent() ) {
  247. Sleep(100);
  248. }
  249. OutputDebugStringA("[RM] Just loaded resource DLL ");
  250. OutputDebugStringW(DllName);
  251. OutputDebugStringA("\n");
  252. DebugBreak();
  253. }
  254. #ifdef COMRES
  255. if (Resource->dwType == RESMON_TYPE_DLL)
  256. {
  257. #endif
  258. //
  259. // We must have a startup routine to find all the other functions.
  260. //
  261. Startup = (PSTARTUP_ROUTINE)GetProcAddress(Resource->Dll,
  262. STARTUP_ROUTINE);
  263. if ( Startup != NULL ) {
  264. FunctionTable = NULL;
  265. RmpSetMonitorState(RmonStartingResource, Resource);
  266. //
  267. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  268. // you remove the entry after you finish the entry point call, else you will kill
  269. // this process on a FALSE deadlock positive.
  270. //
  271. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  272. Resource->ResourceType,
  273. Resource->ResourceName,
  274. L"Startup (on create)" );
  275. try {
  276. Error = (Startup)( ResourceType,
  277. CLRES_VERSION_V1_00,
  278. CLRES_VERSION_V1_00,
  279. RmpSetResourceStatus,
  280. RmpLogEvent,
  281. &FunctionTable );
  282. } except (EXCEPTION_EXECUTE_HANDLER) {
  283. Error = GetExceptionCode();
  284. }
  285. RmpSetMonitorState(RmonIdle, NULL);
  286. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  287. if ( Error != ERROR_SUCCESS ) {
  288. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup call to %1!ws!, error %2!u!.\n",
  289. DllName, Error );
  290. ClusterLogEvent2(LOG_CRITICAL,
  291. LOG_CURRENT_MODULE,
  292. __FILE__,
  293. __LINE__,
  294. RMON_CANT_INIT_RESTYPE,
  295. sizeof(Error),
  296. &Error,
  297. DllName,
  298. ResourceType);
  299. goto ErrorExit;
  300. }
  301. Error = ERROR_INVALID_DATA;
  302. if ( FunctionTable == NULL ) {
  303. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, FunctionTable is NULL!\n");
  304. Reason = 0;
  305. ClusterLogEvent2(LOG_CRITICAL,
  306. LOG_CURRENT_MODULE,
  307. __FILE__,
  308. __LINE__,
  309. RMON_RESTYPE_BAD_TABLE,
  310. sizeof(Reason),
  311. &Reason,
  312. DllName,
  313. ResourceType);
  314. goto ErrorExit;
  315. }
  316. if ( FunctionTable->Version != CLRES_VERSION_V1_00 ) {
  317. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, Invalid Version Number!\n");
  318. Reason = 1;
  319. ClusterLogEvent2(LOG_CRITICAL,
  320. LOG_CURRENT_MODULE,
  321. __FILE__,
  322. __LINE__,
  323. RMON_RESTYPE_BAD_TABLE,
  324. sizeof(Reason),
  325. &Reason,
  326. DllName,
  327. ResourceType);
  328. goto ErrorExit;
  329. }
  330. if ( FunctionTable->TableSize != CLRES_V1_FUNCTION_SIZE ) {
  331. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, Invalid function table size!\n");
  332. Reason = 2;
  333. ClusterLogEvent2(LOG_CRITICAL,
  334. LOG_CURRENT_MODULE,
  335. __FILE__,
  336. __LINE__,
  337. RMON_RESTYPE_BAD_TABLE,
  338. sizeof(Reason),
  339. &Reason,
  340. DllName,
  341. ResourceType);
  342. goto ErrorExit;
  343. }
  344. #ifdef COMRES
  345. Resource->pOpen = FunctionTable->V1Functions.Open;
  346. Resource->pClose = FunctionTable->V1Functions.Close;
  347. Resource->pOnline = FunctionTable->V1Functions.Online;
  348. Resource->pOffline = FunctionTable->V1Functions.Offline;
  349. Resource->pTerminate = FunctionTable->V1Functions.Terminate;
  350. Resource->pLooksAlive = FunctionTable->V1Functions.LooksAlive;
  351. Resource->pIsAlive = FunctionTable->V1Functions.IsAlive;
  352. Resource->pArbitrate = FunctionTable->V1Functions.Arbitrate;
  353. Resource->pRelease = FunctionTable->V1Functions.Release;
  354. Resource->pResourceControl = FunctionTable->V1Functions.ResourceControl;
  355. Resource->pResourceTypeControl = FunctionTable->V1Functions.ResourceTypeControl;
  356. Error = ERROR_INVALID_DATA;
  357. if ( Resource->pOpen == NULL ) {
  358. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Open routine for resource dll %1!ws!\n",
  359. DllName);
  360. goto ErrorExit;
  361. }
  362. if ( Resource->pClose == NULL ) {
  363. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Close routine for resource dll %1!ws!\n",
  364. DllName);
  365. goto ErrorExit;
  366. }
  367. if ( Resource->pOnline == NULL ) {
  368. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Online routine for resource dll %1!ws!\n",
  369. DllName);
  370. goto ErrorExit;
  371. }
  372. if ( Resource->pOffline == NULL ) {
  373. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Offline routine for resource dll %1!ws!\n",
  374. DllName);
  375. goto ErrorExit;
  376. }
  377. if ( Resource->pTerminate == NULL ) {
  378. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Terminate routine for resource dll %1!ws!\n",
  379. DllName);
  380. goto ErrorExit;
  381. }
  382. if ( Resource->pLooksAlive == NULL ) {
  383. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null LooksAlive routine for resource dll %1!ws!\n",
  384. DllName);
  385. goto ErrorExit;
  386. }
  387. if ( Resource->pIsAlive == NULL ) {
  388. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null IsAlive routine for resource dll %1!ws!\n",
  389. DllName);
  390. goto ErrorExit;
  391. }
  392. } else {
  393. ClRtlLogPrint(LOG_CRITICAL, "[RM] Could not find startup routine in resource DLL %1!ws!.\n",
  394. DllName);
  395. Error = ERROR_INVALID_DATA;
  396. goto ErrorExit;
  397. }
  398. if ( (Resource->pArbitrate) &&
  399. (Resource->pRelease) ) {
  400. quorumCapable = 1;
  401. } else {
  402. quorumCapable = 0;
  403. }
  404. }
  405. #else // COMRES
  406. Resource->Open = FunctionTable->V1Functions.Open;
  407. Resource->Close = FunctionTable->V1Functions.Close;
  408. Resource->Online = FunctionTable->V1Functions.Online;
  409. Resource->Offline = FunctionTable->V1Functions.Offline;
  410. Resource->Terminate = FunctionTable->V1Functions.Terminate;
  411. Resource->LooksAlive = FunctionTable->V1Functions.LooksAlive;
  412. Resource->IsAlive = FunctionTable->V1Functions.IsAlive;
  413. Resource->Arbitrate = FunctionTable->V1Functions.Arbitrate;
  414. Resource->Release = FunctionTable->V1Functions.Release;
  415. Resource->ResourceControl = FunctionTable->V1Functions.ResourceControl;
  416. Resource->ResourceTypeControl = FunctionTable->V1Functions.ResourceTypeControl;
  417. Error = ERROR_INVALID_DATA;
  418. if ( Resource->Open == NULL ) {
  419. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Open routine for resource dll %1!ws!\n",
  420. pszDllName);
  421. goto ErrorExit;
  422. }
  423. if ( Resource->Close == NULL ) {
  424. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Close routine for resource dll %1!ws!\n",
  425. pszDllName);
  426. goto ErrorExit;
  427. }
  428. if ( Resource->Online == NULL ) {
  429. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Online routine for resource dll %1!ws!\n",
  430. pszDllName);
  431. goto ErrorExit;
  432. }
  433. if ( Resource->Offline == NULL ) {
  434. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Offline routine for resource dll %1!ws!\n",
  435. pszDllName);
  436. goto ErrorExit;
  437. }
  438. if ( Resource->Terminate == NULL ) {
  439. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Terminate routine for resource dll %1!ws!\n",
  440. pszDllName);
  441. goto ErrorExit;
  442. }
  443. if ( Resource->LooksAlive == NULL ) {
  444. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null LooksAlive routine for resource dll %1!ws!\n",
  445. pszDllName);
  446. goto ErrorExit;
  447. }
  448. if ( Resource->IsAlive == NULL ) {
  449. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null IsAlive routine for resource dll %1!ws!\n",
  450. pszDllName);
  451. goto ErrorExit;
  452. }
  453. } else {
  454. ClRtlLogPrint(LOG_CRITICAL, "[RM] Could not find startup routine in resource DLL %1!ws!.\n",
  455. pszDllName);
  456. Error = ERROR_INVALID_DATA;
  457. goto ErrorExit;
  458. }
  459. if ( (Resource->Arbitrate) &&
  460. (Resource->Release) ) {
  461. quorumCapable = 1;
  462. } else {
  463. quorumCapable = 0;
  464. }
  465. #endif // COMRES
  466. Resource->State = ClusterResourceOffline;
  467. //
  468. // Open the resource's cluster registry key so that it can
  469. // be easily accessed from the Create entrypoint.
  470. //
  471. Error = ClusterRegOpenKey(RmpResourcesKey,
  472. ResourceId,
  473. KEY_READ,
  474. &ResKey);
  475. if (Error != ERROR_SUCCESS) {
  476. CL_LOGFAILURE(Error);
  477. goto ErrorExit;
  478. }
  479. //
  480. // Get the resource name.
  481. //
  482. Resource->ResourceName = GetParameter( ResKey, CLUSREG_NAME_RES_NAME );
  483. if ( Resource->ResourceName == NULL ) {
  484. Error = GetLastError();
  485. ClusterRegCloseKey(ResKey);
  486. ClRtlLogPrint(LOG_UNUSUAL, "[RM] Error reading resource name for %1!ws!, error %2!u!.\n",
  487. Resource->ResourceId, Error);
  488. CL_LOGFAILURE(Error);
  489. goto ErrorExit;
  490. }
  491. //
  492. // Call Open entrypoint.
  493. // This is done with the lock held to serialize calls to the
  494. // resource DLL and serialize access to the shared memory region.
  495. //
  496. AcquireListLock();
  497. RmpSetMonitorState(RmonInitializingResource, Resource);
  498. //
  499. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  500. // you remove the entry after you finish the entry point call, else you will kill
  501. // this process on a FALSE deadlock positive.
  502. //
  503. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  504. Resource->ResourceType,
  505. Resource->ResourceName,
  506. L"Open" );
  507. //
  508. // N.B. This is the only call that we make without locking the
  509. // eventlist lock! We can't, because we don't know that the event
  510. // list is yet.
  511. //
  512. try {
  513. #ifdef COMRES
  514. Resource->Id = RESMON_OPEN (Resource, ResKey) ;
  515. #else
  516. Resource->Id = (Resource->Open)(Resource->ResourceName,
  517. ResKey,
  518. Resource );
  519. #endif
  520. } except (EXCEPTION_EXECUTE_HANDLER) {
  521. SetLastError(GetExceptionCode());
  522. Resource->Id = 0;
  523. }
  524. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  525. if (Resource->Id == 0) {
  526. Error = GetLastError();
  527. } else {
  528. Error = RmpInsertResourceList(Resource, NULL);
  529. }
  530. //set the monitor state and close the key
  531. RmpSetMonitorState(RmonIdle, NULL);
  532. ClusterRegCloseKey(ResKey);
  533. if (Error != ERROR_SUCCESS)
  534. {
  535. //CL_LOGFAILURE(Error);
  536. ClRtlLogPrint(LOG_UNUSUAL, "[RM] RmpInsertResourceList failed, returned %1!u!\n",
  537. Error);
  538. ReleaseListLock();
  539. goto ErrorExit;
  540. }
  541. ReleaseListLock();
  542. if (Resource->Id == 0) {
  543. ClRtlLogPrint(LOG_CRITICAL, "[RM] Open of resource %1!ws! returned null!\n",
  544. Resource->ResourceName);
  545. if ( Error == ERROR_SUCCESS ) {
  546. Error = ERROR_RESOURCE_NOT_FOUND;
  547. }
  548. //CL_LOGFAILURE(Error);
  549. goto ErrorExit;
  550. }
  551. *Status = ERROR_SUCCESS;
  552. if ( pszDllName != DllName ) {
  553. LocalFree( pszDllName );
  554. }
  555. //
  556. // Resource object has been successfully loaded into memory and
  557. // its entrypoints determined. We now have a valid RESID that
  558. // can be used in subsequent calls.
  559. //
  560. return((RESID)Resource);
  561. ErrorExit:
  562. if (Resource != NULL) {
  563. if (Resource->Dll != NULL) {
  564. FreeLibrary(Resource->Dll);
  565. }
  566. #ifdef COMRES
  567. if (Resource->pClusterResource)
  568. IClusterResource_Release (Resource->pClusterResource) ;
  569. if (Resource->pClusterQuorumResource)
  570. IClusterQuorumResource_Release (Resource->pClusterQuorumResource) ;
  571. if (Resource->pClusterResControl)
  572. IClusterResControl_Release (
  573. Resource->pClusterResControl
  574. ) ;
  575. #endif
  576. RmpFree(Resource->DllName);
  577. RmpFree(Resource->ResourceType);
  578. RmpFree(Resource->ResourceName);
  579. RmpFree(Resource->ResourceId);
  580. RmpFree(Resource);
  581. }
  582. if ( pszDllName != DllName ) {
  583. LocalFree( pszDllName );
  584. }
  585. ClRtlLogPrint(LOG_CRITICAL, "[RM] Failed creating resource %1!ws!, error %2!u!.\n",
  586. ResourceId, Error);
  587. *Status = Error;
  588. return(0);
  589. } // RmCreateResource
  590. VOID
  591. s_RmCloseResource(
  592. IN OUT RESID *ResourceId
  593. )
  594. /*++
  595. Routine Description:
  596. Closes the specified resource. This includes removing it from the poll list,
  597. freeing any associated memory, and unloading its DLL.
  598. Arguments:
  599. ResourceId - Supplies a pointer to the resource ID. This will be set to
  600. NULL after cleanup is complete to indicate to RPC that the
  601. client side context can be destroyed.
  602. Return Value:
  603. None.
  604. --*/
  605. {
  606. PRESOURCE Resource;
  607. BOOL Closed;
  608. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  609. Resource = (PRESOURCE)*ResourceId;
  610. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  611. CL_ASSERT(Resource->Flags & RESOURCE_INSERTED);
  612. AcquireListLock();
  613. if (Resource->ListEntry.Flink != NULL) {
  614. RmpRemoveResourceList(Resource);
  615. Closed = FALSE;
  616. } else {
  617. Closed = TRUE;
  618. }
  619. ReleaseListLock();
  620. if (!Closed) {
  621. //
  622. // Call the DLL to close the resource.
  623. //
  624. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  625. //
  626. // If the Online Thread is still pending, wait a little bit for it.
  627. //
  628. if ( Resource->TimerEvent ) {
  629. SetEvent( Resource->TimerEvent );
  630. Resource->TimerEvent = NULL;
  631. }
  632. Resource->dwEntryPoint = RESDLL_ENTRY_CLOSE;
  633. RmpSetMonitorState(RmonDeletingResource, Resource);
  634. //
  635. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  636. // you remove the entry after you finish the entry point call, else you will kill
  637. // this process on a FALSE deadlock positive.
  638. //
  639. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  640. Resource->ResourceType,
  641. Resource->ResourceName,
  642. L"Close" );
  643. try {
  644. #ifdef COMRES
  645. RESMON_CLOSE (Resource) ;
  646. #else
  647. (Resource->Close)(Resource->Id);
  648. #endif
  649. } except (EXCEPTION_EXECUTE_HANDLER) {
  650. }
  651. Resource->dwEntryPoint = 0;
  652. RmpSetMonitorState(RmonIdle, Resource);
  653. RmpRemoveDeadlockMonitorList ( pDueTimeEntry );
  654. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  655. }
  656. Resource->Signature = 0;
  657. if ( Resource->OnlineEvent ) {
  658. SetEvent( Resource->OnlineEvent );
  659. CloseHandle( Resource->OnlineEvent );
  660. Resource->OnlineEvent = NULL;
  661. }
  662. //
  663. // Free the resource dll.
  664. //
  665. #ifdef COMRES
  666. if (Resource->dwType == RESMON_TYPE_DLL)
  667. {
  668. FreeLibrary(Resource->Dll);
  669. }
  670. else
  671. {
  672. IClusterResource_Release (Resource->pClusterResource) ;
  673. if (Resource->pClusterQuorumResource)
  674. IClusterQuorumResource_Release (Resource->pClusterQuorumResource) ;
  675. if (Resource->pClusterResControl)
  676. IClusterResControl_Release (
  677. Resource->pClusterResControl
  678. ) ;
  679. }
  680. #else
  681. FreeLibrary(Resource->Dll);
  682. #endif
  683. RmpFree(Resource->DllName);
  684. RmpFree(Resource->ResourceType);
  685. RmpFree(Resource->ResourceName);
  686. RmpFree(Resource->ResourceId);
  687. RmpFree(Resource);
  688. *ResourceId = NULL;
  689. } // RmCloseResource
  690. VOID
  691. RPC_RESID_rundown(
  692. IN RESID Resource
  693. )
  694. /*++
  695. Routine Description:
  696. RPC rundown procedure for a RESID. Just closes the handle.
  697. Arguments:
  698. Resource - supplies the RESID that is to be rundown.
  699. Return Value:
  700. None.
  701. --*/
  702. {
  703. //
  704. // Chittur Subbaraman (chitturs) - 5/10/2001
  705. //
  706. // Don't do anything on RPC rundown. If clussvc dies, then resmon main thread detects it and
  707. // runs down (close, terminate) resources. Merely, closing the resource here may cause
  708. // it to be delivered when resource dlls don't expect it.
  709. //
  710. #if 0
  711. s_RmCloseResource(&Resource);
  712. #endif
  713. } // RESID_rundown
  714. error_status_t
  715. s_RmChangeResourceParams(
  716. IN RESID ResourceId,
  717. IN DWORD LooksAlivePoll,
  718. IN DWORD IsAlivePoll,
  719. IN DWORD PendingTimeout
  720. )
  721. /*++
  722. Routine Description:
  723. Changes the poll intervals defined for a resource.
  724. Arguments:
  725. ResourceId - Supplies the resource ID.
  726. LooksAlivePoll - Supplies the new LooksAlive poll in ms units
  727. IsAlivePoll - Supplies the new IsAlive poll in ms units
  728. Return Value:
  729. ERROR_SUCCESS if successful
  730. Win32 error otherwise
  731. --*/
  732. {
  733. PRESOURCE Resource;
  734. BOOL Inserted;
  735. //
  736. // If the resmon is shutting down, just return since you can't trust any resource structures
  737. // accessed below.
  738. //
  739. if ( RmpShutdown ) return ( ERROR_SUCCESS );
  740. Resource = (PRESOURCE)ResourceId;
  741. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  742. AcquireListLock();
  743. Inserted = (Resource->Flags & RESOURCE_INSERTED);
  744. if (Inserted) {
  745. //
  746. // Remove the resource from the list, update its properties,
  747. // and reinsert it. The reinsertion will put it back in the
  748. // right spot to reflect the new poll intervals.
  749. //
  750. RmpRemoveResourceList(Resource);
  751. }
  752. Resource->LooksAlivePollInterval = LooksAlivePoll;
  753. Resource->IsAlivePollInterval = IsAlivePoll;
  754. Resource->PendingTimeout = PendingTimeout;
  755. if (Inserted) {
  756. RmpInsertResourceList( Resource,
  757. (PPOLL_EVENT_LIST) Resource->EventList);
  758. }
  759. ReleaseListLock();
  760. return(ERROR_SUCCESS);
  761. } // RmChangeResourcePoll
  762. error_status_t
  763. s_RmArbitrateResource(
  764. IN RESID ResourceId
  765. )
  766. /*++
  767. Routine Description:
  768. Arbitrate for the resource.
  769. Arguments:
  770. ResourceId - Supplies the resource to be arbitrated.
  771. Return Value:
  772. ERROR_SUCCESS if successful.
  773. A Win32 error code on failure.
  774. --*/
  775. {
  776. PRESOURCE Resource;
  777. DWORD status;
  778. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  779. Resource = (PRESOURCE)ResourceId;
  780. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  781. #ifdef COMRES
  782. if (Resource->dwType == RESMON_TYPE_DLL)
  783. {
  784. if ( (Resource->pArbitrate == NULL) ||
  785. (Resource->pRelease == NULL) ) {
  786. return(ERROR_NOT_QUORUM_CAPABLE);
  787. }
  788. }
  789. else
  790. {
  791. if (!Resource->pClusterQuorumResource)
  792. return(ERROR_NOT_QUORUM_CAPABLE);
  793. }
  794. #else
  795. if ( (Resource->Arbitrate == NULL) ||
  796. (Resource->Release == NULL) ) {
  797. return(ERROR_NOT_QUORUM_CAPABLE);
  798. }
  799. #endif
  800. //
  801. // Chittur Subbaraman (chitturs) - 10/15/99
  802. //
  803. // Commenting out lock acquisition - This is done so that the
  804. // arbitration request can proceed into the disk resource without
  805. // any blockage. There have been cases where either some resource
  806. // gets blocked in its "IsAlive" with this lock held or the resmon
  807. // itself calling into clussvc to set a property (for instance) and
  808. // this call gets blocked there. This results in an arbitration stall
  809. // and the clussvc on this node dies. Note that arbitrate only needs to
  810. // be serialized with release and the disk resource is supposed
  811. // to take care of that.
  812. //
  813. #if 0
  814. //
  815. // Lock the resource list and attempt to bring the resource on-line.
  816. // The lock is required to synchronize access to the resource list and
  817. // to serialize any calls to resource DLLs. Only one thread may be
  818. // calling a resource DLL at any time. This prevents resource DLLs
  819. // from having to worry about being thread-safe.
  820. //
  821. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  822. #else
  823. //
  824. // Try to acquire spin lock for synchronizing with resource rundown.
  825. // Return failure if you cannot get the lock.
  826. //
  827. if ( !RmpAcquireSpinLock( Resource, FALSE ) ) return ( ERROR_BUSY );
  828. #endif
  829. //
  830. // Update shared state to indicate we are arbitrating a resource
  831. //
  832. RmpSetMonitorState(RmonArbitrateResource, Resource);
  833. //
  834. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  835. // you remove the entry after you finish the entry point call, else you will kill
  836. // this process on a FALSE deadlock positive.
  837. //
  838. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  839. Resource->ResourceType,
  840. Resource->ResourceName,
  841. L"Arbitrate" );
  842. #ifdef COMRES
  843. status = RESMON_ARBITRATE (Resource, RmpLostQuorumResource) ;
  844. #else
  845. status = (Resource->Arbitrate)(Resource->Id,
  846. RmpLostQuorumResource);
  847. #endif
  848. if (status == ERROR_SUCCESS) {
  849. Resource->IsArbitrated = TRUE;
  850. }
  851. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  852. RmpSetMonitorState(RmonIdle, NULL);
  853. #if 0
  854. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  855. #else
  856. RmpReleaseSpinLock( Resource );
  857. #endif
  858. return(status);
  859. } // s_RmArbitrateResource(
  860. error_status_t
  861. s_RmReleaseResource(
  862. IN RESID ResourceId
  863. )
  864. /*++
  865. Routine Description:
  866. Release the resource.
  867. Arguments:
  868. ResourceId - Supplies the resource to be released.
  869. Return Value:
  870. ERROR_SUCCESS if successful.
  871. A Win32 error code on failure.
  872. --*/
  873. {
  874. PRESOURCE Resource;
  875. DWORD status;
  876. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  877. Resource = (PRESOURCE)ResourceId;
  878. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  879. #ifdef COMRES
  880. if (Resource->dwType == RESMON_TYPE_DLL)
  881. {
  882. if (Resource->pRelease == NULL) {
  883. return(ERROR_NOT_QUORUM_CAPABLE);
  884. }
  885. }
  886. else
  887. {
  888. if (!Resource->pClusterQuorumResource)
  889. return(ERROR_NOT_QUORUM_CAPABLE);
  890. }
  891. #else
  892. if ( Resource->Release == NULL ) {
  893. return(ERROR_NOT_QUORUM_CAPABLE);
  894. }
  895. #endif
  896. //
  897. // Lock the resource list and attempt to bring the resource on-line.
  898. // The lock is required to synchronize access to the resource list and
  899. // to serialize any calls to resource DLLs. Only one thread may be
  900. // calling a resource DLL at any time. This prevents resource DLLs
  901. // from having to worry about being thread-safe.
  902. //
  903. #if 0 // Not needed right now
  904. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  905. #endif
  906. //
  907. // Update shared state to indicate we ar arbitrating a resource
  908. //
  909. RmpSetMonitorState(RmonReleaseResource, Resource);
  910. //
  911. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  912. // you remove the entry after you finish the entry point call, else you will kill
  913. // this process on a FALSE deadlock positive.
  914. //
  915. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  916. Resource->ResourceType,
  917. Resource->ResourceName,
  918. L"Release" );
  919. #ifdef COMRES
  920. status = RESMON_RELEASE (Resource) ;
  921. #else
  922. status = (Resource->Release)(Resource->Id);
  923. #endif
  924. Resource->IsArbitrated = FALSE;
  925. RmpSetMonitorState(RmonIdle, NULL);
  926. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  927. #if 0 // Not needed right now
  928. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  929. #endif
  930. return(status);
  931. } // s_RmReleaseResource(
  932. error_status_t
  933. s_RmOnlineResource(
  934. IN RESID ResourceId,
  935. OUT LPDWORD pdwState
  936. )
  937. /*++
  938. Routine Description:
  939. Brings the specified resource into the online state.
  940. Arguments:
  941. ResourceId - Supplies the resource to be brought online.
  942. pdwState - The new state of the resource is returned.
  943. Return Value:
  944. --*/
  945. {
  946. PRESOURCE Resource;
  947. DWORD status;
  948. HANDLE timerThread;
  949. HANDLE eventHandle = NULL;
  950. DWORD threadId;
  951. BOOL fAddPollEvent = FALSE;
  952. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  953. Resource = (PRESOURCE)ResourceId;
  954. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  955. CL_ASSERT(Resource->EventHandle == NULL );
  956. *pdwState = ClusterResourceFailed;
  957. if ( Resource->State > ClusterResourcePending ) {
  958. return(ERROR_INVALID_STATE);
  959. }
  960. //
  961. // Create an event to allow the SetResourceStatus callback to synchronize
  962. // execution with this thread.
  963. //
  964. if ( Resource->OnlineEvent ) {
  965. return(ERROR_NOT_READY);
  966. }
  967. Resource->OnlineEvent = CreateEvent( NULL,
  968. FALSE,
  969. FALSE,
  970. NULL );
  971. if ( Resource->OnlineEvent == NULL ) {
  972. return(GetLastError());
  973. }
  974. //
  975. // Lock the resource list and attempt to bring the resource on-line.
  976. // The lock is required to synchronize access to the resource list and
  977. // to serialize any calls to resource DLLs. Only one thread may be
  978. // calling a resource DLL at any time. This prevents resource DLLs
  979. // from having to worry about being thread-safe.
  980. //
  981. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  982. //
  983. // Update shared state to indicate we are bringing a resource online
  984. //
  985. RmpSetMonitorState(RmonOnlineResource, Resource);
  986. //
  987. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  988. // you remove the entry after you finish the entry point call, else you will kill
  989. // this process on a FALSE deadlock positive.
  990. //
  991. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  992. Resource->ResourceType,
  993. Resource->ResourceName,
  994. L"Online" );
  995. //
  996. // Call Online entrypoint. Regardless of whether this succeeds or
  997. // not, the resource has been successfully added to the list. If the
  998. // online call fails, the resource immediately enters the failed state.
  999. //
  1000. Resource->CheckPoint = 0;
  1001. try {
  1002. #ifdef COMRES
  1003. status = RESMON_ONLINE (Resource, &eventHandle) ;
  1004. #else
  1005. status = (Resource->Online)(Resource->Id, &eventHandle);
  1006. #endif
  1007. } except (EXCEPTION_EXECUTE_HANDLER) {
  1008. status = GetExceptionCode();
  1009. }
  1010. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  1011. if (status == ERROR_SUCCESS) {
  1012. SetEvent( Resource->OnlineEvent );
  1013. CloseHandle( Resource->OnlineEvent );
  1014. Resource->OnlineEvent = NULL;
  1015. Resource->State = ClusterResourceOnline;
  1016. if ( eventHandle ) {
  1017. fAddPollEvent = TRUE;
  1018. }
  1019. } else if ( status == ERROR_IO_PENDING ) {
  1020. status = ERROR_SUCCESS;
  1021. //
  1022. // If the Resource DLL returns pending, then start a timer.
  1023. //
  1024. CL_ASSERT(Resource->TimerEvent == NULL );
  1025. Resource->TimerEvent = CreateEvent( NULL,
  1026. FALSE,
  1027. FALSE,
  1028. NULL );
  1029. if ( Resource->TimerEvent == NULL ) {
  1030. CL_UNEXPECTED_ERROR(status = GetLastError());
  1031. } else {
  1032. timerThread = CreateThread( NULL,
  1033. 0,
  1034. RmpTimerThread,
  1035. Resource,
  1036. 0,
  1037. &threadId );
  1038. if ( timerThread == NULL ) {
  1039. CL_UNEXPECTED_ERROR(status = GetLastError());
  1040. } else {
  1041. //
  1042. // Chittur Subbaraman (chitturs) - 1/12/99
  1043. //
  1044. // Raise the timer thread priority to highest. This
  1045. // is necessary to avoid certain cases in which the
  1046. // timer thread is sluggish to close out the timer event
  1047. // handle before a second online. Note that there are
  1048. // no major performance implications by doing this since
  1049. // the timer thread is in a wait state most of the time.
  1050. //
  1051. if ( !SetThreadPriority( timerThread, THREAD_PRIORITY_HIGHEST ) )
  1052. {
  1053. ClRtlLogPrint(LOG_UNUSUAL,
  1054. "[RM] s_RmOnlineResource: Error setting priority of timer "
  1055. "thread for resource %1!ws!\n",
  1056. Resource->ResourceName);
  1057. CL_LOGFAILURE( GetLastError() );
  1058. }
  1059. CloseHandle( timerThread );
  1060. Resource->State = ClusterResourceOnlinePending;
  1061. //
  1062. // If we have an event handle, then add it to our list.
  1063. //
  1064. if ( eventHandle ) {
  1065. fAddPollEvent = TRUE;
  1066. }
  1067. }
  1068. }
  1069. SetEvent( Resource->OnlineEvent );
  1070. } else {
  1071. CloseHandle( Resource->OnlineEvent );
  1072. Resource->OnlineEvent = NULL;
  1073. ClRtlLogPrint(LOG_CRITICAL, "[RM] OnlineResource failed, resource %1!ws!, status = %2!u!.\n",
  1074. Resource->ResourceName,
  1075. status);
  1076. ClusterLogEvent1(LOG_CRITICAL,
  1077. LOG_CURRENT_MODULE,
  1078. __FILE__,
  1079. __LINE__,
  1080. RMON_ONLINE_FAILED,
  1081. sizeof(status),
  1082. &status,
  1083. Resource->ResourceName);
  1084. Resource->State = ClusterResourceFailed;
  1085. }
  1086. *pdwState = Resource->State;
  1087. RmpSetMonitorState(RmonIdle, NULL);
  1088. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  1089. //
  1090. // Notify poller thread that the list has changed
  1091. //
  1092. if ( fAddPollEvent )
  1093. {
  1094. ClRtlLogPrint(LOG_NOISE,
  1095. "[RM] s_RmOnlineResource: Adding event 0x%1!08lx! for resource %2!ws!\n",
  1096. eventHandle,
  1097. Resource->ResourceName);
  1098. status = RmpAddPollEvent( (PPOLL_EVENT_LIST)Resource->EventList,
  1099. eventHandle,
  1100. Resource );
  1101. if ( status != ERROR_SUCCESS ) {
  1102. ClRtlLogPrint(LOG_CRITICAL,
  1103. "[RM] s_RmOnlineResource: Failed to add event 0x%1!08lx! for resource %2!ws!, error %3!u!.\n",
  1104. eventHandle,
  1105. Resource->ResourceName,
  1106. status );
  1107. CL_LOGFAILURE(status);
  1108. Resource->State = ClusterResourceFailed;
  1109. }
  1110. }
  1111. RmpSignalPoller((PPOLL_EVENT_LIST)Resource->EventList);
  1112. return(status);
  1113. } // RmOnlineResource
  1114. VOID
  1115. s_RmTerminateResource(
  1116. IN RESID ResourceId
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. Brings the specified resource into the offline state immediately.
  1121. Arguments:
  1122. ResourceId - Supplies the resource to be brought online.
  1123. Return Value:
  1124. The new state of the resource.
  1125. --*/
  1126. {
  1127. DWORD State;
  1128. RmpOfflineResource(ResourceId, FALSE, &State);
  1129. return;
  1130. } // RmTerminateResource
  1131. error_status_t
  1132. s_RmOfflineResource(
  1133. IN RESID ResourceId,
  1134. OUT LPDWORD pdwState
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. Brings the specified resource into the offline state by shutting it
  1139. down gracefully.
  1140. Arguments:
  1141. ResourceId - Supplies the resource to be brought online.
  1142. pdwState - Returns the new state of the resource.
  1143. Return Value:
  1144. ERROR_SUCCESS if successful, else returns code.
  1145. --*/
  1146. {
  1147. return(RmpOfflineResource(ResourceId, TRUE, pdwState));
  1148. } // RmOfflineResource
  1149. error_status_t
  1150. s_RmFailResource(
  1151. IN RESID ResourceId
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. Fail the given resource.
  1156. Arguments:
  1157. ResourceId - Supplies the resource ID.
  1158. Return Value:
  1159. ERROR_SUCCESS if successful
  1160. Win32 error otherwise
  1161. --*/
  1162. {
  1163. PRESOURCE Resource;
  1164. Resource = (PRESOURCE)ResourceId;
  1165. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  1166. if ( Resource->State == ClusterResourceOnline ) {
  1167. Resource->State = ClusterResourceFailed;
  1168. RmpPostNotify(Resource, NotifyResourceStateChange);
  1169. return(ERROR_SUCCESS);
  1170. } else {
  1171. return(ERROR_RESMON_INVALID_STATE);
  1172. }
  1173. } // RmChangeResourcePoll
  1174. error_status_t
  1175. s_RmShutdownProcess(
  1176. IN handle_t IDL_handle
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. Set the shutdown flag and trigger a poller thread to exit.
  1181. The termination of any poller thread will notify the main
  1182. thread to clean up and shutdown.
  1183. Arguments:
  1184. IDL_handle - Supplies RPC binding handle, currently unused
  1185. Return Value:
  1186. ERROR_SUCCESS
  1187. --*/
  1188. {
  1189. //
  1190. // Check if we've already been called here before. This can happen
  1191. // as a result of the Failover Manager calling us to perform a clean
  1192. // shutdown. The main thread also will call here, in case it is shutting
  1193. // down because of a failure of one of the threads.
  1194. //
  1195. if ( !RmpShutdown ) {
  1196. RmpShutdown = TRUE;
  1197. //
  1198. // Wake up the main thread so that it can cleanup.
  1199. //
  1200. SetEvent( RmpRewaitEvent );
  1201. }
  1202. return(ERROR_SUCCESS);
  1203. } // RmShutdownProcess
  1204. error_status_t
  1205. s_RmResourceControl(
  1206. IN RESID ResourceId,
  1207. IN DWORD ControlCode,
  1208. IN PUCHAR InBuffer,
  1209. IN DWORD InBufferSize,
  1210. OUT PUCHAR OutBuffer,
  1211. IN DWORD OutBufferSize,
  1212. OUT LPDWORD BytesReturned,
  1213. OUT LPDWORD Required
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. Process a resource control request.
  1218. Arguments:
  1219. ResourceId - the resource that is being controlled.
  1220. ControlCode - the control request, reduced to just the function code.
  1221. InBuffer - the input buffer for this control request.
  1222. InBufferSize - the size of the input buffer.
  1223. OutBuffer - the output buffer.
  1224. OutBufferSize - the size of the output buffer.
  1225. BytesReturned - the number of bytes returned.
  1226. Required - the number of bytes required if OutBuffer is not big enough.
  1227. Return Value:
  1228. ERROR_SUCCESS if successful
  1229. A Win32 error code on failure
  1230. --*/
  1231. {
  1232. PRESOURCE Resource;
  1233. DWORD status = ERROR_INVALID_FUNCTION;
  1234. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  1235. Resource = (PRESOURCE)ResourceId;
  1236. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  1237. // Inbuffer is [unique].
  1238. if ( InBuffer == NULL )
  1239. InBufferSize = 0;
  1240. else if ( InBufferSize == 0 )
  1241. InBuffer = NULL;
  1242. //
  1243. // Lock the resource list and send down the control request.
  1244. // The lock is required to synchronize access to the resource list and
  1245. // to serialize any calls to resource DLLs. Only one thread may be
  1246. // calling a resource DLL at any time. This prevents resource DLLs
  1247. // from having to worry about being thread-safe.
  1248. //
  1249. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  1250. //
  1251. // If the control code is a notification for resource name change, modify the resource
  1252. // name field in the resource structure to reflect that.
  1253. //
  1254. if ( ControlCode == CLUSCTL_RESOURCE_SET_NAME )
  1255. {
  1256. LPWSTR lpszNewBuffer, lpszOldBuffer;
  1257. lpszNewBuffer = LocalAlloc ( LPTR, InBufferSize );
  1258. if ( lpszNewBuffer != NULL )
  1259. {
  1260. lstrcpyW ( lpszNewBuffer, ( LPWSTR ) InBuffer );
  1261. lpszOldBuffer = InterlockedExchangePointer ( &Resource->ResourceName, lpszNewBuffer );
  1262. LocalFree ( lpszOldBuffer );
  1263. }
  1264. }
  1265. //
  1266. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  1267. // you remove the entry after you finish the entry point call, else you will kill
  1268. // this process on a FALSE deadlock positive.
  1269. //
  1270. pDueTimeEntry = RmpInsertDeadlockMonitorList ( Resource->DllName,
  1271. Resource->ResourceType,
  1272. Resource->ResourceName,
  1273. L"Resource control" );
  1274. #ifdef COMRES
  1275. if (Resource->pResourceControl || Resource->pClusterResControl) {
  1276. RmpSetMonitorState(RmonResourceControl, Resource);
  1277. status = RESMON_RESOURCECONTROL( Resource,
  1278. ControlCode,
  1279. InBuffer,
  1280. InBufferSize,
  1281. OutBuffer,
  1282. OutBufferSize,
  1283. BytesReturned );
  1284. RmpSetMonitorState(RmonIdle, NULL);
  1285. }
  1286. #else
  1287. if ( Resource->ResourceControl ) {
  1288. RmpSetMonitorState(RmonResourceControl, Resource);
  1289. status = (Resource->ResourceControl)( Resource->Id,
  1290. ControlCode,
  1291. InBuffer,
  1292. InBufferSize,
  1293. OutBuffer,
  1294. OutBufferSize,
  1295. BytesReturned );
  1296. RmpSetMonitorState(RmonIdle, NULL);
  1297. }
  1298. #endif
  1299. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  1300. if ( status == ERROR_INVALID_FUNCTION ) {
  1301. DWORD characteristics = CLUS_CHAR_UNKNOWN;
  1302. switch ( ControlCode ) {
  1303. case CLUSCTL_RESOURCE_GET_COMMON_PROPERTY_FMTS:
  1304. status = ResUtilGetPropertyFormats( RmpResourceCommonProperties,
  1305. OutBuffer,
  1306. OutBufferSize,
  1307. BytesReturned,
  1308. Required );
  1309. break;
  1310. case CLUSCTL_RESOURCE_GET_CLASS_INFO:
  1311. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  1312. *BytesReturned = 0;
  1313. *Required = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1314. if ( OutBuffer == NULL ) {
  1315. status = ERROR_SUCCESS;
  1316. } else {
  1317. status = ERROR_MORE_DATA;
  1318. }
  1319. } else {
  1320. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  1321. ptrResClassInfo->rc = CLUS_RESCLASS_UNKNOWN;
  1322. ptrResClassInfo->SubClass = 0;
  1323. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1324. status = ERROR_SUCCESS;
  1325. }
  1326. break;
  1327. case CLUSCTL_RESOURCE_GET_CHARACTERISTICS:
  1328. #ifdef COMRES
  1329. if (Resource->dwType == RESMON_TYPE_DLL)
  1330. {
  1331. if ( (Resource->pArbitrate != NULL) &&
  1332. (Resource->pRelease != NULL) ) {
  1333. characteristics = CLUS_CHAR_QUORUM;
  1334. }
  1335. }
  1336. else
  1337. {
  1338. if (!Resource->pClusterQuorumResource)
  1339. characteristics = CLUS_CHAR_QUORUM;
  1340. }
  1341. #else
  1342. if ( (Resource->Arbitrate != NULL) &&
  1343. (Resource->Release != NULL) ) {
  1344. characteristics = CLUS_CHAR_QUORUM;
  1345. }
  1346. #endif
  1347. if ( OutBufferSize < sizeof(DWORD) ) {
  1348. *BytesReturned = 0;
  1349. *Required = sizeof(DWORD);
  1350. if ( OutBuffer == NULL ) {
  1351. status = ERROR_SUCCESS;
  1352. } else {
  1353. status = ERROR_MORE_DATA;
  1354. }
  1355. } else {
  1356. *BytesReturned = sizeof(DWORD);
  1357. *(LPDWORD)OutBuffer = characteristics;
  1358. status = ERROR_SUCCESS;
  1359. }
  1360. break;
  1361. case CLUSCTL_RESOURCE_GET_FLAGS:
  1362. status = RmpResourceGetFlags( Resource,
  1363. OutBuffer,
  1364. OutBufferSize,
  1365. BytesReturned,
  1366. Required );
  1367. break;
  1368. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  1369. *BytesReturned = 0;
  1370. status = ERROR_SUCCESS;
  1371. break;
  1372. case CLUSCTL_RESOURCE_ENUM_COMMON_PROPERTIES:
  1373. status = RmpResourceEnumCommonProperties( OutBuffer,
  1374. OutBufferSize,
  1375. BytesReturned,
  1376. Required );
  1377. break;
  1378. case CLUSCTL_RESOURCE_GET_RO_COMMON_PROPERTIES:
  1379. status = RmpResourceGetCommonProperties( Resource,
  1380. TRUE,
  1381. OutBuffer,
  1382. OutBufferSize,
  1383. BytesReturned,
  1384. Required );
  1385. break;
  1386. case CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES:
  1387. status = RmpResourceGetCommonProperties( Resource,
  1388. FALSE,
  1389. OutBuffer,
  1390. OutBufferSize,
  1391. BytesReturned,
  1392. Required );
  1393. break;
  1394. case CLUSCTL_RESOURCE_VALIDATE_COMMON_PROPERTIES:
  1395. status = RmpResourceValidateCommonProperties( Resource,
  1396. InBuffer,
  1397. InBufferSize );
  1398. break;
  1399. case CLUSCTL_RESOURCE_SET_COMMON_PROPERTIES:
  1400. status = RmpResourceSetCommonProperties( Resource,
  1401. InBuffer,
  1402. InBufferSize );
  1403. break;
  1404. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  1405. status = RmpResourceEnumPrivateProperties( Resource,
  1406. OutBuffer,
  1407. OutBufferSize,
  1408. BytesReturned,
  1409. Required );
  1410. break;
  1411. case CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES:
  1412. if ( OutBufferSize < sizeof(DWORD) ) {
  1413. *BytesReturned = 0;
  1414. *Required = sizeof(DWORD);
  1415. if ( OutBuffer == NULL ) {
  1416. status = ERROR_SUCCESS;
  1417. } else {
  1418. status = ERROR_MORE_DATA;
  1419. }
  1420. } else {
  1421. LPDWORD ptrDword = (LPDWORD) OutBuffer;
  1422. *ptrDword = 0;
  1423. *BytesReturned = sizeof(DWORD);
  1424. status = ERROR_SUCCESS;
  1425. }
  1426. break;
  1427. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1428. status = RmpResourceGetPrivateProperties( Resource,
  1429. OutBuffer,
  1430. OutBufferSize,
  1431. BytesReturned,
  1432. Required );
  1433. break;
  1434. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1435. status = RmpResourceValidatePrivateProperties( Resource,
  1436. InBuffer,
  1437. InBufferSize );
  1438. break;
  1439. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1440. status = RmpResourceSetPrivateProperties( Resource,
  1441. InBuffer,
  1442. InBufferSize );
  1443. break;
  1444. case CLUSCTL_RESOURCE_SET_NAME:
  1445. //
  1446. // Chittur Subbaraman (chitturs) - 6/28/99
  1447. //
  1448. // The setting of the name in the cluster registry is done
  1449. // in NT5 by clussvc. So, resmon does not have to do any work
  1450. // except return a success code in case a resource DLL returns
  1451. // ERROR_INVALID_FUNCTION.
  1452. //
  1453. status = ERROR_SUCCESS;
  1454. break;
  1455. default:
  1456. break;
  1457. }
  1458. } else {
  1459. // If the function is returning a buffer size without
  1460. // copying data, move this info around to satisfy RPC.
  1461. if ( *BytesReturned > OutBufferSize ) {
  1462. *Required = *BytesReturned;
  1463. *BytesReturned = 0;
  1464. status = ERROR_MORE_DATA;
  1465. }
  1466. }
  1467. if ( ( status != ERROR_SUCCESS ) &&
  1468. ( status != ERROR_MORE_DATA ) &&
  1469. ( status != ERROR_INVALID_FUNCTION ) )
  1470. {
  1471. ClRtlLogPrint(LOG_UNUSUAL,
  1472. "[RM] s_RmResourceControl: Resource <%1!ws!> control operation "
  1473. "0x%2!08lx! gives status=%3!u!...\n",
  1474. Resource->ResourceName,
  1475. ControlCode,
  1476. status);
  1477. }
  1478. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  1479. return(status);
  1480. } // RmResourceControl
  1481. error_status_t
  1482. s_RmResourceTypeControl(
  1483. IN handle_t IDL_handle,
  1484. IN LPCWSTR ResourceTypeName,
  1485. IN LPCWSTR DllName,
  1486. IN DWORD ControlCode,
  1487. IN PUCHAR InBuffer,
  1488. IN DWORD InBufferSize,
  1489. OUT PUCHAR OutBuffer,
  1490. IN DWORD OutBufferSize,
  1491. OUT LPDWORD BytesReturned,
  1492. OUT LPDWORD Required
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. Process a resource type control request.
  1497. Arguments:
  1498. IDL_handle - not used.
  1499. ResourceTypeName - the resource type name that is being controlled.
  1500. DllName - the name of the dll.
  1501. ControlCode - the control request, reduced to just the function code.
  1502. InBuffer - the input buffer for this control request.
  1503. InBufferSize - the size of the input buffer.
  1504. OutBuffer - the output buffer.
  1505. OutBufferSize - the size of the output buffer.
  1506. BytesReturned - the number of bytes returned.
  1507. Required - the number of bytes required if OutBuffer is not big enough.
  1508. Return Value:
  1509. ERROR_SUCCESS if successful
  1510. A Win32 error code on failure
  1511. --*/
  1512. {
  1513. RESDLL_FNINFO ResDllFnInfo;
  1514. #ifdef COMRES
  1515. RESDLL_INTERFACES ResDllInterfaces;
  1516. #endif
  1517. DWORD status = ERROR_INVALID_FUNCTION;
  1518. DWORD characteristics = CLUS_CHAR_UNKNOWN;
  1519. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  1520. // InBuffer is [unique].
  1521. if ( InBuffer == NULL )
  1522. InBufferSize = 0;
  1523. else if ( InBufferSize == 0 )
  1524. InBuffer = NULL;
  1525. status = RmpLoadResType(ResourceTypeName, DllName, &ResDllFnInfo,
  1526. #ifdef COMRES
  1527. &ResDllInterfaces,
  1528. #endif
  1529. &characteristics);
  1530. if (status != ERROR_SUCCESS)
  1531. {
  1532. return(status);
  1533. }
  1534. status = ERROR_INVALID_FUNCTION;
  1535. if (ResDllFnInfo.hDll && ResDllFnInfo.pResFnTable)
  1536. {
  1537. PRESOURCE_TYPE_CONTROL_ROUTINE resourceTypeControl = NULL ;
  1538. resourceTypeControl = ResDllFnInfo.pResFnTable->V1Functions.ResourceTypeControl;
  1539. if (resourceTypeControl)
  1540. {
  1541. RmpSetMonitorState(RmonResourceTypeControl, NULL);
  1542. //
  1543. // Insert the DLL & entry point info into the deadlock monitoring list. Make sure
  1544. // you remove the entry after you finish the entry point call, else you will kill
  1545. // this process on a FALSE deadlock positive.
  1546. //
  1547. pDueTimeEntry = RmpInsertDeadlockMonitorList ( DllName,
  1548. ResourceTypeName,
  1549. NULL,
  1550. L"Resource type control" );
  1551. status = (resourceTypeControl)( ResourceTypeName,
  1552. ControlCode,
  1553. InBuffer,
  1554. InBufferSize,
  1555. OutBuffer,
  1556. OutBufferSize,
  1557. BytesReturned );
  1558. RmpSetMonitorState(RmonIdle, NULL);
  1559. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  1560. }
  1561. }
  1562. #ifdef COMRES
  1563. else if (ResDllInterfaces.pClusterResControl)
  1564. {
  1565. HRESULT hr ;
  1566. VARIANT vtIn, vtOut ;
  1567. SAFEARRAY sfIn = {1, 0, 1, 0, InBuffer, {InBufferSize, 0} } ;
  1568. SAFEARRAY sfOut = {1, FADF_FIXEDSIZE, 1, 0, OutBuffer, {OutBufferSize, 0} } ;
  1569. SAFEARRAY *psfOut = &sfOut ;
  1570. BSTR pbResourceTypeName ;
  1571. vtIn.vt = VT_ARRAY | VT_UI1 ;
  1572. vtOut.vt = VT_ARRAY | VT_UI1 | VT_BYREF ;
  1573. vtIn.parray = &sfIn ;
  1574. vtOut.pparray = &psfOut ;
  1575. pbResourceTypeName = SysAllocString (ResourceTypeName) ;
  1576. if (pbResourceTypeName == NULL)
  1577. {
  1578. CL_LOGFAILURE( ERROR_NOT_ENOUGH_MEMORY) ;
  1579. goto FnExit ; // Use the default processing
  1580. }
  1581. RmpSetMonitorState(RmonResourceTypeControl, NULL);
  1582. pDueTimeEntry = RmpInsertDeadlockMonitorList ( DllName,
  1583. ResourceTypeName,
  1584. NULL,
  1585. L"Resource Type Control" );
  1586. hr = IClusterResControl_ResourceTypeControl (
  1587. ResDllInterfaces.pClusterResControl,
  1588. pbResourceTypeName,
  1589. ControlCode,
  1590. &vtIn,
  1591. &vtOut,
  1592. BytesReturned,
  1593. &status);
  1594. RmpSetMonitorState(RmonIdle, NULL);
  1595. RmpRemoveDeadlockMonitorList( pDueTimeEntry );
  1596. SysFreeString (pbResourceTypeName) ;
  1597. if (FAILED(hr))
  1598. {
  1599. CL_LOGFAILURE(hr); // Use the default processing
  1600. status = ERROR_INVALID_FUNCTION;
  1601. }
  1602. }
  1603. #endif
  1604. if ( status == ERROR_INVALID_FUNCTION ) {
  1605. switch ( ControlCode ) {
  1606. case CLUSCTL_RESOURCE_TYPE_GET_COMMON_RESOURCE_PROPERTY_FMTS:
  1607. status = ResUtilGetPropertyFormats( RmpResourceTypeCommonProperties,
  1608. OutBuffer,
  1609. OutBufferSize,
  1610. BytesReturned,
  1611. Required );
  1612. break;
  1613. case CLUSCTL_RESOURCE_TYPE_GET_CLASS_INFO:
  1614. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  1615. *BytesReturned = 0;
  1616. *Required = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1617. if ( OutBuffer == NULL ) {
  1618. status = ERROR_SUCCESS;
  1619. } else {
  1620. status = ERROR_MORE_DATA;
  1621. }
  1622. } else {
  1623. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  1624. ptrResClassInfo->rc = CLUS_RESCLASS_UNKNOWN;
  1625. ptrResClassInfo->SubClass = 0;
  1626. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1627. status = ERROR_SUCCESS;
  1628. }
  1629. break;
  1630. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  1631. *BytesReturned = 0;
  1632. status = ERROR_SUCCESS;
  1633. break;
  1634. case CLUSCTL_RESOURCE_TYPE_GET_CHARACTERISTICS:
  1635. if ( OutBufferSize < sizeof(DWORD) ) {
  1636. *BytesReturned = 0;
  1637. *Required = sizeof(DWORD);
  1638. if ( OutBuffer == NULL ) {
  1639. status = ERROR_SUCCESS;
  1640. } else {
  1641. status = ERROR_MORE_DATA;
  1642. }
  1643. } else {
  1644. *BytesReturned = sizeof(DWORD);
  1645. *(LPDWORD)OutBuffer = characteristics;
  1646. status = ERROR_SUCCESS;
  1647. }
  1648. break;
  1649. case CLUSCTL_RESOURCE_TYPE_GET_FLAGS:
  1650. status = RmpResourceTypeGetFlags( ResourceTypeName,
  1651. OutBuffer,
  1652. OutBufferSize,
  1653. BytesReturned,
  1654. Required );
  1655. break;
  1656. case CLUSCTL_RESOURCE_TYPE_GET_REGISTRY_CHECKPOINTS:
  1657. *BytesReturned = 0;
  1658. *Required = 0;
  1659. status = ERROR_SUCCESS;
  1660. break;
  1661. case CLUSCTL_RESOURCE_TYPE_ENUM_COMMON_PROPERTIES:
  1662. status = RmpResourceTypeEnumCommonProperties( ResourceTypeName,
  1663. OutBuffer,
  1664. OutBufferSize,
  1665. BytesReturned,
  1666. Required );
  1667. break;
  1668. case CLUSCTL_RESOURCE_TYPE_GET_RO_COMMON_PROPERTIES:
  1669. status = RmpResourceTypeGetCommonProperties( ResourceTypeName,
  1670. TRUE,
  1671. OutBuffer,
  1672. OutBufferSize,
  1673. BytesReturned,
  1674. Required );
  1675. break;
  1676. case CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES:
  1677. status = RmpResourceTypeGetCommonProperties( ResourceTypeName,
  1678. FALSE,
  1679. OutBuffer,
  1680. OutBufferSize,
  1681. BytesReturned,
  1682. Required );
  1683. break;
  1684. case CLUSCTL_RESOURCE_TYPE_VALIDATE_COMMON_PROPERTIES:
  1685. status = RmpResourceTypeValidateCommonProperties( ResourceTypeName,
  1686. InBuffer,
  1687. InBufferSize );
  1688. break;
  1689. case CLUSCTL_RESOURCE_TYPE_SET_COMMON_PROPERTIES:
  1690. status = RmpResourceTypeSetCommonProperties( ResourceTypeName,
  1691. InBuffer,
  1692. InBufferSize );
  1693. break;
  1694. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1695. status = RmpResourceTypeEnumPrivateProperties( ResourceTypeName,
  1696. OutBuffer,
  1697. OutBufferSize,
  1698. BytesReturned,
  1699. Required );
  1700. break;
  1701. case CLUSCTL_RESOURCE_TYPE_GET_RO_PRIVATE_PROPERTIES:
  1702. if ( OutBufferSize < sizeof(DWORD) ) {
  1703. *BytesReturned = 0;
  1704. *Required = sizeof(DWORD);
  1705. if ( OutBuffer == NULL ) {
  1706. status = ERROR_SUCCESS;
  1707. } else {
  1708. status = ERROR_MORE_DATA;
  1709. }
  1710. } else {
  1711. LPDWORD ptrDword = (LPDWORD) OutBuffer;
  1712. *ptrDword = 0;
  1713. *BytesReturned = sizeof(DWORD);
  1714. status = ERROR_SUCCESS;
  1715. }
  1716. break;
  1717. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_PROPERTIES:
  1718. status = RmpResourceTypeGetPrivateProperties( ResourceTypeName,
  1719. OutBuffer,
  1720. OutBufferSize,
  1721. BytesReturned,
  1722. Required );
  1723. break;
  1724. case CLUSCTL_RESOURCE_TYPE_VALIDATE_PRIVATE_PROPERTIES:
  1725. status = RmpResourceTypeValidatePrivateProperties( ResourceTypeName,
  1726. InBuffer,
  1727. InBufferSize );
  1728. break;
  1729. case CLUSCTL_RESOURCE_TYPE_SET_PRIVATE_PROPERTIES:
  1730. status = RmpResourceTypeSetPrivateProperties( ResourceTypeName,
  1731. InBuffer,
  1732. InBufferSize );
  1733. break;
  1734. default:
  1735. break;
  1736. }
  1737. } else {
  1738. // If the function is returning a buffer size without
  1739. // copying data, move this info around to satisfy RPC.
  1740. if ( *BytesReturned > OutBufferSize ) {
  1741. *Required = *BytesReturned;
  1742. *BytesReturned = 0;
  1743. }
  1744. if ( (status == ERROR_MORE_DATA) &&
  1745. (OutBuffer == NULL) ) {
  1746. status = ERROR_SUCCESS;
  1747. }
  1748. }
  1749. FnExit:
  1750. if (ResDllFnInfo.hDll)
  1751. FreeLibrary(ResDllFnInfo.hDll);
  1752. #ifdef COMRES
  1753. if (ResDllInterfaces.pClusterResource)
  1754. IClusterResource_Release (ResDllInterfaces.pClusterResource) ;
  1755. if (ResDllInterfaces.pClusterQuorumResource)
  1756. IClusterQuorumResource_Release (ResDllInterfaces.pClusterQuorumResource) ;
  1757. if (ResDllInterfaces.pClusterResControl)
  1758. IClusterResControl_Release (
  1759. ResDllInterfaces.pClusterResControl
  1760. ) ;
  1761. #endif
  1762. return(status);
  1763. } // RmResourceTypeControl
  1764. LPWSTR
  1765. GetParameter(
  1766. IN HKEY ClusterKey,
  1767. IN LPCWSTR ValueName
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. Reads a REG_SZ parameter from the cluster regitry, and allocates the
  1772. necessary storage for it.
  1773. Arguments:
  1774. ClusterKey - supplies the cluster key where the parameter is stored.
  1775. ValueName - supplies the name of the value.
  1776. Return Value:
  1777. A pointer to a buffer containing the parameter value on success.
  1778. NULL on failure.
  1779. --*/
  1780. {
  1781. LPWSTR value;
  1782. DWORD valueLength;
  1783. DWORD valueType;
  1784. DWORD status;
  1785. valueLength = 0;
  1786. status = ClusterRegQueryValue( ClusterKey,
  1787. ValueName,
  1788. &valueType,
  1789. NULL,
  1790. &valueLength );
  1791. if ( (status != ERROR_SUCCESS) &&
  1792. (status != ERROR_MORE_DATA) ) {
  1793. SetLastError(status);
  1794. return(NULL);
  1795. }
  1796. if ( valueType == REG_SZ ) {
  1797. valueLength += sizeof(UNICODE_NULL);
  1798. }
  1799. value = LocalAlloc(LMEM_FIXED, valueLength);
  1800. if ( value == NULL ) {
  1801. return(NULL);
  1802. }
  1803. status = ClusterRegQueryValue(ClusterKey,
  1804. ValueName,
  1805. &valueType,
  1806. (LPBYTE)value,
  1807. &valueLength);
  1808. if ( status != ERROR_SUCCESS) {
  1809. LocalFree(value);
  1810. SetLastError(status);
  1811. value = NULL;
  1812. }
  1813. return(value);
  1814. } // GetParameter
  1815. error_status_t
  1816. s_RmUpdateDeadlockDetectionParams(
  1817. IN handle_t IDL_handle,
  1818. IN DWORD dwDeadlockDetectionTimeout
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. Changes the poll intervals defined for a resource.
  1823. Arguments:
  1824. IDL_handle - Unused.
  1825. dwDeadlockDetectionTimeout - Deadlock detection timeout.
  1826. Return Value:
  1827. ERROR_SUCCESS if successful
  1828. Win32 error otherwise
  1829. --*/
  1830. {
  1831. DWORD dwStatus = ERROR_SUCCESS;
  1832. //
  1833. // Use the default for deadlock timeout if 0 is passed in.
  1834. //
  1835. dwDeadlockDetectionTimeout =
  1836. ( dwDeadlockDetectionTimeout == 0 ) ?
  1837. CLUSTER_RESOURCE_DLL_DEFAULT_DEADLOCK_TIMEOUT_SECS :
  1838. dwDeadlockDetectionTimeout;
  1839. //
  1840. // Initialize the deadlock monitoring subsystem if it is not already initialized.
  1841. //
  1842. dwStatus = RmpDeadlockMonitorInitialize ( dwDeadlockDetectionTimeout );
  1843. if ( dwStatus != ERROR_SUCCESS )
  1844. {
  1845. ClRtlLogPrint(LOG_CRITICAL, "[RM] s_RmUpdateDeadlockDetectionParams: Unable to initialize the deadlock monitor, error %1!u!.\n",
  1846. dwStatus);
  1847. goto FnExit;
  1848. }
  1849. dwStatus = RmpUpdateDeadlockDetectionParams ( dwDeadlockDetectionTimeout );
  1850. if ( dwStatus != ERROR_SUCCESS )
  1851. {
  1852. ClRtlLogPrint(LOG_CRITICAL, "[RM] s_RmUpdateDeadlockDetectionParams: Unable to update the parameters for deadlock monitor, error %1!u!.\n",
  1853. dwStatus);
  1854. goto FnExit;
  1855. }
  1856. FnExit:
  1857. return ( dwStatus );
  1858. } // s_RmUpdateDeadlockDetectionParams
  1859. #ifdef COMRES
  1860. RESID
  1861. Resmon_Open (
  1862. IN PRESOURCE Resource,
  1863. IN HKEY ResourceKey
  1864. )
  1865. {
  1866. if (Resource->dwType == RESMON_TYPE_DLL)
  1867. {
  1868. return (Resource->pOpen) (Resource->ResourceName, ResourceKey, Resource) ;
  1869. }
  1870. else
  1871. {
  1872. HRESULT hr ;
  1873. OLERESID ResId = 0 ;
  1874. BSTR pbResourceName = SysAllocString (Resource->ResourceName) ;
  1875. if (pbResourceName == NULL)
  1876. {
  1877. SetLastError ( ERROR_NOT_ENOUGH_MEMORY) ;
  1878. CL_LOGFAILURE( ERROR_NOT_ENOUGH_MEMORY) ;
  1879. goto ErrorExit ;
  1880. }
  1881. hr = IClusterResource_Open(Resource->pClusterResource, pbResourceName, (OLEHKEY)ResourceKey,
  1882. (OLERESOURCE_HANDLE)Resource, &ResId);
  1883. SysFreeString (pbResourceName) ;
  1884. if (FAILED(hr))
  1885. {
  1886. SetLastError (hr) ;
  1887. CL_LOGFAILURE(hr);
  1888. }
  1889. ErrorExit:
  1890. return (RESID) ResId ;
  1891. }
  1892. }
  1893. VOID
  1894. Resmon_Close (
  1895. IN PRESOURCE Resource
  1896. )
  1897. {
  1898. if (Resource->dwType == RESMON_TYPE_DLL)
  1899. {
  1900. (Resource->pClose) (Resource->Id) ;
  1901. }
  1902. else
  1903. {
  1904. HRESULT hr ;
  1905. hr = IClusterResource_Close (Resource->pClusterResource, (OLERESID)Resource->Id);
  1906. if (FAILED(hr))
  1907. {
  1908. SetLastError (hr) ;
  1909. CL_LOGFAILURE(hr);
  1910. }
  1911. }
  1912. }
  1913. DWORD
  1914. Resmon_Online (
  1915. IN PRESOURCE Resource,
  1916. IN OUT LPHANDLE EventHandle
  1917. )
  1918. {
  1919. if (Resource->dwType == RESMON_TYPE_DLL)
  1920. {
  1921. return (Resource->pOnline) (Resource->Id, EventHandle) ;
  1922. }
  1923. else
  1924. {
  1925. HRESULT hr ;
  1926. long lRet ;
  1927. hr = IClusterResource_Online(Resource->pClusterResource, (OLERESID)Resource->Id, (LPOLEHANDLE)EventHandle, &lRet);
  1928. if (FAILED(hr))
  1929. {
  1930. SetLastError (lRet = hr) ; // Return a error
  1931. CL_LOGFAILURE(hr);
  1932. }
  1933. return lRet ;
  1934. }
  1935. }
  1936. DWORD
  1937. Resmon_Offline (
  1938. IN PRESOURCE Resource
  1939. )
  1940. {
  1941. if (Resource->dwType == RESMON_TYPE_DLL)
  1942. {
  1943. return (Resource->pOffline) (Resource->Id) ;
  1944. }
  1945. else
  1946. {
  1947. HRESULT hr ;
  1948. long lRet ;
  1949. hr = IClusterResource_Offline(Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
  1950. if (FAILED(hr))
  1951. {
  1952. SetLastError (lRet = hr) ; // Return a error
  1953. CL_LOGFAILURE(hr);
  1954. }
  1955. return lRet ;
  1956. }
  1957. }
  1958. VOID
  1959. Resmon_Terminate (
  1960. IN PRESOURCE Resource
  1961. )
  1962. {
  1963. if (Resource->dwType == RESMON_TYPE_DLL)
  1964. {
  1965. (Resource->pTerminate) (Resource->Id) ;
  1966. }
  1967. else
  1968. {
  1969. HRESULT hr ;
  1970. hr = IClusterResource_Terminate (Resource->pClusterResource, (OLERESID)Resource->Id);
  1971. if (FAILED(hr))
  1972. {
  1973. SetLastError (hr) ;
  1974. CL_LOGFAILURE(hr);
  1975. }
  1976. }
  1977. }
  1978. BOOL
  1979. Resmon_LooksAlive (
  1980. IN PRESOURCE Resource
  1981. )
  1982. {
  1983. if (Resource->dwType == RESMON_TYPE_DLL)
  1984. {
  1985. return (Resource->pLooksAlive) (Resource->Id) ;
  1986. }
  1987. else
  1988. {
  1989. HRESULT hr ;
  1990. long lRet ;
  1991. hr = IClusterResource_LooksAlive (Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
  1992. if (FAILED(hr))
  1993. {
  1994. SetLastError (hr) ;
  1995. CL_LOGFAILURE(hr);
  1996. lRet = 0 ; // Incase of failure return 0 to indicate LooksAlive is failed.
  1997. }
  1998. return lRet ;
  1999. }
  2000. }
  2001. BOOL
  2002. Resmon_IsAlive (
  2003. IN PRESOURCE Resource
  2004. )
  2005. {
  2006. if (Resource->dwType == RESMON_TYPE_DLL)
  2007. {
  2008. return (Resource->pIsAlive) (Resource->Id) ;
  2009. }
  2010. else
  2011. {
  2012. HRESULT hr ;
  2013. long lRet ;
  2014. hr = IClusterResource_IsAlive (Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
  2015. if (FAILED(hr))
  2016. {
  2017. SetLastError (hr) ;
  2018. CL_LOGFAILURE(hr);
  2019. lRet = 0 ; // Incase of failure return 0 to indicate IsAlive is failed.
  2020. }
  2021. return lRet ;
  2022. }
  2023. }
  2024. DWORD
  2025. Resmon_Arbitrate (
  2026. IN PRESOURCE Resource,
  2027. IN PQUORUM_RESOURCE_LOST LostQuorumResource
  2028. )
  2029. {
  2030. if (Resource->dwType == RESMON_TYPE_DLL)
  2031. {
  2032. return (Resource->pArbitrate) (Resource->Id, LostQuorumResource) ;
  2033. }
  2034. else
  2035. {
  2036. HRESULT hr ;
  2037. long lRet ;
  2038. hr = IClusterQuorumResource_QuorumArbitrate(Resource->pClusterQuorumResource, (OLERESID)Resource->Id, (POLEQUORUM_RESOURCE_LOST)LostQuorumResource, &lRet);
  2039. if (FAILED(hr))
  2040. {
  2041. SetLastError (lRet = hr) ;
  2042. CL_LOGFAILURE(hr);
  2043. }
  2044. return lRet ;
  2045. }
  2046. }
  2047. DWORD
  2048. Resmon_Release (
  2049. IN PRESOURCE Resource
  2050. )
  2051. {
  2052. if (Resource->dwType == RESMON_TYPE_DLL)
  2053. {
  2054. return (Resource->pRelease) (Resource->Id) ;
  2055. }
  2056. else
  2057. {
  2058. HRESULT hr ;
  2059. long lRet ;
  2060. hr = IClusterQuorumResource_QuorumRelease(Resource->pClusterQuorumResource, (OLERESID)Resource->Id, &lRet);
  2061. if (FAILED(hr))
  2062. {
  2063. SetLastError (lRet = hr) ;
  2064. CL_LOGFAILURE(hr);
  2065. }
  2066. return lRet ;
  2067. }
  2068. }
  2069. DWORD
  2070. Resmon_ResourceControl (
  2071. IN PRESOURCE Resource,
  2072. IN DWORD ControlCode,
  2073. IN PVOID InBuffer,
  2074. IN DWORD InBufferSize,
  2075. OUT PVOID OutBuffer,
  2076. IN DWORD OutBufferSize,
  2077. OUT LPDWORD BytesReturned
  2078. )
  2079. {
  2080. if (Resource->dwType == RESMON_TYPE_DLL)
  2081. {
  2082. return (Resource->pResourceControl)( Resource->Id,
  2083. ControlCode,
  2084. InBuffer,
  2085. InBufferSize,
  2086. OutBuffer,
  2087. OutBufferSize,
  2088. BytesReturned );
  2089. }
  2090. else
  2091. {
  2092. long status ;
  2093. HRESULT hr ;
  2094. VARIANT vtIn, vtOut ;
  2095. SAFEARRAY sfIn = {1, 0, 1, 0, InBuffer, {InBufferSize, 0} } ;
  2096. SAFEARRAY sfOut = {1, FADF_FIXEDSIZE, 1, 0, OutBuffer, {OutBufferSize, 0} } ;
  2097. SAFEARRAY *psfOut = &sfOut ;
  2098. vtIn.vt = VT_ARRAY | VT_UI1 ;
  2099. vtOut.vt = VT_ARRAY | VT_UI1 | VT_BYREF ;
  2100. vtIn.parray = &sfIn ;
  2101. vtOut.pparray = &psfOut ;
  2102. hr = IClusterResControl_ResourceControl (
  2103. Resource->pClusterResControl,
  2104. (OLERESID)Resource->Id,
  2105. (long)ControlCode,
  2106. &vtIn,
  2107. &vtOut,
  2108. (long *)BytesReturned,
  2109. &status);
  2110. if (FAILED(hr))
  2111. {
  2112. CL_LOGFAILURE(hr); // Use the default processing
  2113. status = ERROR_INVALID_FUNCTION;
  2114. }
  2115. return (DWORD)status ;
  2116. }
  2117. }
  2118. #endif // COMRES