Source code of Windows XP (NT5)
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.

2190 lines
58 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This module provides the main cluster initialization.
  7. Author:
  8. John Vert (jvert) 6/5/1996
  9. Revision History:
  10. --*/
  11. extern "C"
  12. {
  13. #include "initp.h"
  14. #include <objbase.h>
  15. RPC_STATUS ApipConnectCallback(
  16. IN RPC_IF_ID * Interface,
  17. IN void * Context
  18. );
  19. }
  20. #define CLUSTER_PRIORITY_CLASS HIGH_PRIORITY_CLASS
  21. #include "CVssCluster.h"
  22. //
  23. // Global Data
  24. //
  25. RPC_BINDING_VECTOR *CsRpcBindingVector = NULL;
  26. LPTOP_LEVEL_EXCEPTION_FILTER lpfnOriginalExceptionFilter = NULL;
  27. BOOLEAN bFormCluster = TRUE;
  28. //
  29. // LocalData
  30. //
  31. BOOLEAN CspIntraclusterRpcServerStarted = FALSE;
  32. HANDLE CspMutex = NULL;
  33. PCLRTL_WORK_QUEUE CspEventReportingWorkQueue = NULL;
  34. //
  35. // Prototypes
  36. //
  37. LONG
  38. CspExceptionFilter(
  39. IN PEXCEPTION_POINTERS ExceptionInfo
  40. );
  41. //
  42. // Routines.
  43. //
  44. DWORD
  45. CsGetServiceAccountInfo(
  46. VOID
  47. )
  48. {
  49. DWORD status = ERROR_SUCCESS;
  50. SC_HANDLE schSCManager;
  51. SC_HANDLE serviceHandle = NULL;
  52. LPQUERY_SERVICE_CONFIG scConfigData = NULL;
  53. ULONG bytesNeeded;
  54. BOOL success;
  55. //
  56. // open a handle to the service controller manager to query the account
  57. // under which the cluster service was started
  58. //
  59. schSCManager = OpenSCManager(NULL, // machine (NULL == local)
  60. NULL, // database (NULL == default)
  61. SC_MANAGER_ALL_ACCESS); // access required
  62. if ( schSCManager == NULL ) {
  63. status = GetLastError();
  64. goto error_exit;
  65. }
  66. serviceHandle = OpenService(schSCManager,
  67. CLUSTER_SERVICE_NAME,
  68. SERVICE_ALL_ACCESS);
  69. if ( serviceHandle == NULL ) {
  70. status = GetLastError();
  71. goto error_exit;
  72. }
  73. success = QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded);
  74. if ( !success ) {
  75. status = GetLastError();
  76. if ( status != ERROR_INSUFFICIENT_BUFFER ) {
  77. goto error_exit;
  78. } else {
  79. status = ERROR_SUCCESS;
  80. }
  81. }
  82. scConfigData = static_cast<LPQUERY_SERVICE_CONFIG>(LocalAlloc( LMEM_FIXED, bytesNeeded ));
  83. if ( scConfigData == NULL ) {
  84. status = GetLastError();
  85. goto error_exit;
  86. }
  87. success = QueryServiceConfig(serviceHandle,
  88. scConfigData,
  89. bytesNeeded,
  90. &bytesNeeded);
  91. if ( !success ) {
  92. status = GetLastError();
  93. goto error_exit;
  94. }
  95. CsServiceDomainAccount = static_cast<LPWSTR>( LocalAlloc(LMEM_FIXED,
  96. (wcslen( scConfigData->lpServiceStartName ) + 1 ) * sizeof(WCHAR)) );
  97. if ( CsServiceDomainAccount == NULL ) {
  98. status = GetLastError();
  99. goto error_exit;
  100. }
  101. wcscpy( CsServiceDomainAccount, scConfigData->lpServiceStartName );
  102. error_exit:
  103. if ( serviceHandle != NULL ) {
  104. CloseServiceHandle( serviceHandle );
  105. }
  106. if ( schSCManager != NULL ) {
  107. CloseServiceHandle( schSCManager );
  108. }
  109. if ( scConfigData != NULL ) {
  110. LocalFree( scConfigData );
  111. }
  112. return status;
  113. } // CsGetServiceAccountInfo
  114. DWORD
  115. EnableProcessPrivilege(
  116. LPWSTR PrivilegeName
  117. )
  118. /*++
  119. Routine Description:
  120. Enable the specified privilege for the process
  121. Arguments:
  122. PrivilegeName - UNICODE name of privilege to enable
  123. Return Value:
  124. ERROR_SUCCESS if successful
  125. Win32 error code otherwise.
  126. --*/
  127. {
  128. DWORD status = ERROR_SUCCESS;
  129. HANDLE hAccessToken;
  130. LUID luidPrivilegeLUID;
  131. TOKEN_PRIVILEGES tpTokenPrivilege;
  132. if (!OpenProcessToken(GetCurrentProcess(),
  133. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  134. &hAccessToken))
  135. {
  136. status = GetLastError();
  137. ClRtlLogPrint(LOG_CRITICAL,
  138. "[INIT] Failed to get process token, Status %1!u!.\n",
  139. status);
  140. return status;
  141. }
  142. //
  143. // Get LUID of SeSecurityPrivilege privilege
  144. //
  145. if (!LookupPrivilegeValue(NULL,
  146. PrivilegeName,
  147. &luidPrivilegeLUID))
  148. {
  149. status = GetLastError();
  150. ClRtlLogPrint(LOG_CRITICAL,
  151. "[INIT] Failed to get LUID for privilege %1!ws!, Status %2!u!.\n",
  152. PrivilegeName,
  153. status);
  154. return status;
  155. }
  156. //
  157. // Enable the supplied privilege using the LUID just obtained
  158. //
  159. tpTokenPrivilege.PrivilegeCount = 1;
  160. tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID;
  161. tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  162. if (!AdjustTokenPrivileges(hAccessToken,
  163. FALSE, // Do not disable all
  164. &tpTokenPrivilege,
  165. sizeof(TOKEN_PRIVILEGES),
  166. NULL,
  167. NULL))
  168. {
  169. status = GetLastError();
  170. ClRtlLogPrint(LOG_CRITICAL,
  171. "[INIT] Failed to adjust process token for privilege %1!ws!, Status %2!u!.\n",
  172. PrivilegeName,
  173. status);
  174. }
  175. return status;
  176. } // EnableProcessPrivilege
  177. VOID CspLogStartEvent(
  178. IN BOOL bJoin)
  179. {
  180. LPWSTR pszClusterName = NULL;
  181. LPWSTR pszName = NULL;
  182. DWORD dwClusterNameSize;
  183. DWORD dwSize;
  184. DWORD dwStatus;
  185. WCHAR szUnknownClusterName[]=L"Unknown";
  186. pszClusterName = NULL;
  187. dwClusterNameSize = 0;
  188. dwStatus = DmQueryString(DmClusterParametersKey,
  189. CLUSREG_NAME_CLUS_NAME,
  190. REG_SZ,
  191. &pszClusterName,
  192. &dwClusterNameSize,
  193. &dwSize);
  194. if (dwStatus != ERROR_SUCCESS)
  195. {
  196. //we dont treat this error as fatal, since
  197. //the cluster did start, but we really shouldnt get this
  198. ClRtlLogPrint(LOG_UNUSUAL,
  199. "[INIT] Couldnt get the cluster name, status=%1!u!\n",
  200. dwStatus);
  201. pszName = szUnknownClusterName;
  202. }
  203. else
  204. pszName = pszClusterName;
  205. //log events in the cluster log to mark the start of the cluster server
  206. if (bJoin)
  207. CsLogEvent1(LOG_NOISE, SERVICE_SUCCESSFUL_JOIN, pszName);
  208. else
  209. CsLogEvent1(LOG_NOISE, SERVICE_SUCCESSFUL_FORM, pszName);
  210. if (pszClusterName)
  211. LocalFree(pszClusterName);
  212. }
  213. DWORD
  214. ClusterInitialize(
  215. VOID
  216. )
  217. /*++
  218. Routine Description:
  219. This is the main cluster initialization path. It calls the
  220. initialization routines of all the other components. It then
  221. attempts to join an existing cluster. If the existing cluster
  222. cannot be found, it forms a new cluster.
  223. Arguments:
  224. None.
  225. Return Value:
  226. ERROR_SUCCESS if successful
  227. Win32 error code otherwise.
  228. --*/
  229. {
  230. DWORD Status;
  231. DWORD JoinStatus;
  232. DWORD StringBufferSize = 0, StringSize = 0;
  233. SIZE_T minWorkingSetSize;
  234. SIZE_T maxWorkingSetSize;
  235. BOOL bJoin;
  236. BOOL bEvicted;
  237. PNM_NODE_ENUM2 pNodeEnum = NULL;
  238. HRESULT hr = S_OK;
  239. ClRtlLogPrint(LOG_NOISE, "[INIT] ClusterInitialize called to start cluster.\n");
  240. //
  241. // give us a fighting chance on loaded server
  242. //
  243. #if CLUSTER_PRIORITY_CLASS
  244. if ( !SetPriorityClass( GetCurrentProcess(), CLUSTER_PRIORITY_CLASS ) ) {
  245. ClRtlLogPrint(LOG_UNUSUAL,
  246. "[INIT] Failed to set cluster service priority class, Status %1!lx!.\n",
  247. GetLastError() );
  248. }
  249. #endif
  250. // initialize our product suite
  251. CsMyProductSuite = (SUITE_TYPE)ClRtlGetSuiteType();
  252. CL_ASSERT(CsMyProductSuite != 0);
  253. //
  254. // First check our OS to make sure it is ok to run.
  255. //
  256. if (!ClRtlIsOSValid() ||
  257. !ClRtlIsOSTypeValid()) {
  258. //
  259. // Bail out, machine is running something odd.
  260. //
  261. CsLogEvent(LOG_CRITICAL, SERVICE_FAILED_INVALID_OS);
  262. return(ERROR_REVISION_MISMATCH);
  263. }
  264. Status = ClRtlHasNodeBeenEvicted( &bEvicted );
  265. if ( Status != ERROR_SUCCESS )
  266. {
  267. ClRtlLogPrint(LOG_CRITICAL,
  268. "[CS] Unable to determine if this node was previously evicted or not, status %1!u!\n",
  269. Status);
  270. return Status;
  271. }
  272. if ( bEvicted != FALSE )
  273. {
  274. // This node has been evicted previously, but cleanup could not complete.
  275. ClRtlLogPrint(LOG_UNUSUAL,
  276. "[CS] This node has been evicted from the cluster, but cleanup was not completed. Restarting cleanup\n"
  277. );
  278. // Reinitiate cleanup
  279. hr = ClRtlCleanupNode(
  280. NULL, // Name of the node to be cleaned up (NULL means this node)
  281. 60000, // Amount of time (in milliseconds) to wait before starting cleanup
  282. 0 // timeout interval in milliseconds
  283. );
  284. if ( FAILED( hr ) && ( hr != RPC_S_CALLPENDING ) )
  285. {
  286. Status = HRESULT_CODE( hr );
  287. ClRtlLogPrint(LOG_CRITICAL,
  288. "[CS] Unable to reinitiate cleanup, status 0x%1!x!\n",
  289. hr);
  290. }
  291. else
  292. {
  293. Status = ERROR_SUCCESS;
  294. }
  295. return Status;
  296. }
  297. //
  298. // Acquire our named mutex in order to prevent multiple copies
  299. // of the cluster service from accidentally getting started.
  300. //
  301. CspMutex = CreateMutexW(
  302. NULL,
  303. FALSE,
  304. L"ClusterServer_Running"
  305. );
  306. if (CspMutex==NULL) {
  307. Status = GetLastError();
  308. ClRtlLogPrint(LOG_CRITICAL,
  309. "[CS] Unable to create cluster mutex, status %1!u!\n",
  310. Status);
  311. return Status;
  312. }
  313. if (WaitForSingleObject(CspMutex, 30000) == WAIT_TIMEOUT) {
  314. //
  315. // Somebody already has this mutex, exit immediately.
  316. //
  317. ClRtlLogPrint(LOG_CRITICAL,
  318. "[CS] The Cluster Service is already running.\n");
  319. return(ERROR_SERVICE_ALREADY_RUNNING);
  320. }
  321. //
  322. // Set our unhandled exception filter so that if anything horrible
  323. // goes wrong, we can exit immediately.
  324. //
  325. lpfnOriginalExceptionFilter = SetUnhandledExceptionFilter(CspExceptionFilter);
  326. //
  327. // enabled the TCB privilege for the entire process
  328. //
  329. Status = EnableProcessPrivilege( SE_TCB_NAME );
  330. if ( Status != ERROR_SUCCESS ) {
  331. ClRtlLogPrint(LOG_CRITICAL,
  332. "[CS] Unable to set privilege %1!ws! for process, %2!u!\n",
  333. SE_TCB_NAME,
  334. Status);
  335. return(Status);
  336. }
  337. //
  338. // Next initialize the testpoint code
  339. //
  340. TestpointInit();
  341. g_pCVssWriterCluster = new CVssWriterCluster;
  342. if ( g_pCVssWriterCluster == NULL ) {
  343. Status = ERROR_NOT_ENOUGH_MEMORY;
  344. ClRtlLogPrint(LOG_CRITICAL,
  345. "[CS] VSS: Unable to allocate VssWriter, %1!u!\n", Status);
  346. return(Status);
  347. }
  348. //
  349. // Create the global work queues.
  350. //
  351. CsDelayedWorkQueue = ClRtlCreateWorkQueue(CS_MAX_DELAYED_WORK_THREADS,
  352. THREAD_PRIORITY_NORMAL);
  353. if (CsDelayedWorkQueue == NULL) {
  354. Status = GetLastError();
  355. ClRtlLogPrint(LOG_CRITICAL,
  356. "[CS] Unable to create delayed work queue, %1!u!\n",
  357. Status);
  358. return(Status);
  359. }
  360. CsCriticalWorkQueue = ClRtlCreateWorkQueue(CS_MAX_CRITICAL_WORK_THREADS,
  361. THREAD_PRIORITY_ABOVE_NORMAL);
  362. if (CsCriticalWorkQueue == NULL) {
  363. Status = GetLastError();
  364. ClRtlLogPrint(LOG_CRITICAL,
  365. "[CS] Unable to create critical work queue, %1!u!\n",
  366. Status);
  367. return(Status);
  368. }
  369. #if 0
  370. CspEventReportingWorkQueue = ClRtlCreateWorkQueue(1, THREAD_PRIORITY_NORMAL);
  371. if (CspEventReportingWorkQueue == NULL) {
  372. Status = GetLastError();
  373. ClRtlLogPrint(LOG_CRITICAL,
  374. "[CS] Unable to create event reporting work queue, %1!u!\n",
  375. Status);
  376. return(Status);
  377. }
  378. ClRtlEventLogSetWorkQueue( CspEventReportingWorkQueue );
  379. #endif
  380. //
  381. // Init COM
  382. //
  383. Status = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
  384. if ( !SUCCEEDED( Status )) {
  385. ClRtlLogPrint(LOG_CRITICAL, "[CS] Couldn't init COM %1!08X!\n", Status );
  386. return Status;
  387. }
  388. //
  389. // Initialize Object Manager
  390. //
  391. Status = OmInitialize();
  392. #ifdef CLUSTER_TESTPOINT
  393. TESTPT( TpFailOmInit ) {
  394. Status = 99999;
  395. }
  396. #endif
  397. if (Status != ERROR_SUCCESS) {
  398. return(Status);
  399. }
  400. //
  401. // Initialize Event Processor
  402. //
  403. Status = EpInitialize();
  404. #ifdef CLUSTER_TESTPOINT
  405. TESTPT( TpFailEpInit ) {
  406. Status = 99999;
  407. }
  408. #endif
  409. if (Status != ERROR_SUCCESS) {
  410. return(Status);
  411. }
  412. //
  413. // Chittur Subbaraman (chitturs) - 12/4/99
  414. //
  415. // Initialize the restore database manager. This function is a NOOP
  416. // if restore database is not being done. This function MUST be called
  417. // before the DM is initialized.
  418. //
  419. Status = RdbInitialize();
  420. if (Status != ERROR_SUCCESS) {
  421. return(Status);
  422. }
  423. //
  424. // Initialize Database Manager
  425. //
  426. Status = DmInitialize();
  427. #ifdef CLUSTER_TESTPOINT
  428. TESTPT( TpFailDmInit ) {
  429. Status = 99999;
  430. }
  431. #endif
  432. if (Status != ERROR_SUCCESS) {
  433. return(Status);
  434. }
  435. //
  436. // Initialize Node Manager
  437. //
  438. Status = NmInitialize();
  439. #ifdef CLUSTER_TESTPOINT
  440. TESTPT( TpFailNmInit ) {
  441. Status = 99999;
  442. }
  443. #endif
  444. if (Status != ERROR_SUCCESS) {
  445. return(Status);
  446. }
  447. //
  448. // Initialize Global Update Manager
  449. //
  450. Status = GumInitialize();
  451. #ifdef CLUSTER_TESTPOINT
  452. TESTPT( TpFailGumInit ) {
  453. Status = 99999;
  454. }
  455. #endif
  456. if (Status != ERROR_SUCCESS) {
  457. return(Status);
  458. }
  459. //
  460. // Initialize the cluster wide event logging
  461. //
  462. if (!CsNoRepEvtLogging) {
  463. Status = EvInitialize();
  464. //if this fails, we still start the cluster service
  465. if ( Status != ERROR_SUCCESS ) {
  466. ClRtlLogPrint(LOG_CRITICAL,
  467. "[INIT] Error calling EvInitialize, Status = %1!u!\n",
  468. Status
  469. );
  470. }
  471. }
  472. //
  473. // Initialize Failover Manager component
  474. //
  475. Status = FmInitialize();
  476. #ifdef CLUSTER_TESTPOINT
  477. TESTPT( TpFailFmInit ) {
  478. Status = 99999;
  479. }
  480. #endif
  481. if (Status != ERROR_SUCCESS) {
  482. return(Status);
  483. }
  484. //
  485. // Initialize API
  486. //
  487. Status = ApiInitialize();
  488. if (Status != ERROR_SUCCESS) {
  489. return(Status);
  490. }
  491. //
  492. // Initialize Log Manager component
  493. //
  494. Status = LmInitialize();
  495. #ifdef CLUSTER_TESTPOINT
  496. TESTPT( TpFailLmInit ) {
  497. Status = 99999;
  498. }
  499. #endif
  500. if (Status != ERROR_SUCCESS) {
  501. return(Status);
  502. }
  503. //
  504. // Initialize the Checkpoint Manager component
  505. //
  506. Status = CpInitialize();
  507. #ifdef CLUSTER_TESTPOINT
  508. TESTPT( TpFailCpInit ) {
  509. Status = 99999;
  510. }
  511. #endif
  512. if (Status != ERROR_SUCCESS) {
  513. return(Status);
  514. }
  515. //
  516. // find out what domain account we're running under. This is needed by
  517. // some packages
  518. //
  519. Status = ClRtlGetRunningAccountInfo( &CsServiceDomainAccount );
  520. if ( Status != ERROR_SUCCESS ) {
  521. ClRtlLogPrint(LOG_CRITICAL, "[CS] Couldn't determine Service Domain Account. status %1!u!\n",
  522. Status);
  523. return Status;
  524. }
  525. ClRtlLogPrint(LOG_NOISE, "[CS] Service Domain Account = %1!ws!\n",
  526. CsServiceDomainAccount);
  527. //
  528. // Prepare the RPC server. This does not enable us to receive any calls.
  529. //
  530. Status = ClusterInitializeRpcServer();
  531. if (Status != ERROR_SUCCESS) {
  532. return(Status);
  533. }
  534. //
  535. // Read the cluster name from the database.
  536. //
  537. Status = DmQuerySz(
  538. DmClusterParametersKey,
  539. CLUSREG_NAME_CLUS_NAME,
  540. &CsClusterName,
  541. &StringBufferSize,
  542. &StringSize
  543. );
  544. if (Status != ERROR_SUCCESS) {
  545. ClRtlLogPrint(LOG_UNUSUAL,
  546. "[CS] Unable to read cluster name from database. Service initialization failed.\n"
  547. );
  548. return(Status);
  549. }
  550. //
  551. // First, attempt to join the cluster.
  552. //
  553. ClRtlLogPrint(LOG_NOISE,
  554. "[INIT] Attempting to join cluster %1!ws!\n",
  555. CsClusterName
  556. );
  557. bFormCluster = TRUE;
  558. JoinStatus = ClusterJoin();
  559. //
  560. // If this node was evicted when it was down, this error code is returned by the
  561. // sponsor when it tries to rejoin the cluster. In this case, initiate a cleanup
  562. // of this node and exit.
  563. //
  564. if ( JoinStatus == ERROR_CLUSTER_NODE_NOT_MEMBER )
  565. {
  566. DWORD CleanupStatus;
  567. ClRtlLogPrint(LOG_UNUSUAL,
  568. "[INIT] This node has been evicted from the cluster when it was unavailable. Initiating cleanup.\n"
  569. );
  570. // Initiate cleanup of this node.
  571. hr = ClRtlCleanupNode(
  572. NULL, // Name of the node to be cleaned up (NULL means this node)
  573. 60000, // Amount of time (in milliseconds) to wait before starting cleanup
  574. 0 // timeout interval in milliseconds
  575. );
  576. if ( FAILED( hr ) && ( hr != RPC_S_CALLPENDING ) )
  577. {
  578. CleanupStatus = HRESULT_CODE( hr );
  579. ClRtlLogPrint(LOG_CRITICAL,
  580. "[INIT] Failed to initiate cleanup of this node, status 0x%1!x!\n",
  581. hr
  582. );
  583. }
  584. else
  585. {
  586. CleanupStatus = ERROR_SUCCESS;
  587. }
  588. return(CleanupStatus);
  589. }
  590. //
  591. // Chittur Subbaraman (chitturs) - 10/27/98
  592. //
  593. // If a database restore operation is requested, check whether
  594. // you succeeded in establishing a connection. If so, check
  595. // whether you are forced to restore the DB. If not, abort the
  596. // whole operation and return. If you are forced to restore,
  597. // you will first stop the service in other nodes and then
  598. // try to form a cluster.
  599. //
  600. if ( CsDatabaseRestore == TRUE ) {
  601. if ( JoinStatus == ERROR_CLUSTER_NODE_UP ) {
  602. if ( CsForceDatabaseRestore == FALSE ) {
  603. ClRtlLogPrint(LOG_UNUSUAL,
  604. "[INIT] Cannot restore DB while the cluster is up, service init failed\n"
  605. );
  606. ClRtlLogPrint(LOG_UNUSUAL,
  607. "[INIT] You may try to restart the service with the forcerestore option\n"
  608. );
  609. RpcBindingFree(&CsJoinSponsorBinding);
  610. return(JoinStatus);
  611. }
  612. //
  613. // At this point, a restore database operation is forced by
  614. // the user. So, enumerate the cluster nodes with the help
  615. // of the sponsor and then stop the services on all the
  616. // cluster nodes.
  617. //
  618. Status = NmRpcEnumNodeDefinitions2(
  619. CsJoinSponsorBinding,
  620. 0,
  621. L"0",
  622. &pNodeEnum
  623. );
  624. RpcBindingFree(&CsJoinSponsorBinding);
  625. if ( Status != ERROR_SUCCESS ) {
  626. ClRtlLogPrint(LOG_UNUSUAL,
  627. "[INIT] Cannot force a restore DB: Unable to enumerate cluster nodes\n"
  628. );
  629. LocalFree( pNodeEnum );
  630. return (Status);
  631. }
  632. //
  633. // Attempt to stop the clussvc on all nodes, except of course
  634. // this node
  635. //
  636. Status = RdbStopSvcOnNodes (
  637. pNodeEnum,
  638. L"clussvc"
  639. );
  640. LocalFree( pNodeEnum );
  641. if ( Status != ERROR_SUCCESS ) {
  642. ClRtlLogPrint(LOG_UNUSUAL,
  643. "[INIT] Cannot force a restore DB: Unable to stop cluster nodes\n"
  644. );
  645. return(Status);
  646. } else {
  647. CL_LOGCLUSWARNING( CS_STOPPING_SVC_ON_REMOTE_NODES );
  648. }
  649. }
  650. }
  651. if (JoinStatus != ERROR_SUCCESS) {
  652. ClRtlLogPrint(LOG_UNUSUAL,
  653. "[INIT] Failed to join cluster, status %1!u!\n",
  654. JoinStatus
  655. );
  656. //
  657. // Forming a cluster will also attempt to arbitrate the quorum
  658. // resource.
  659. //
  660. bJoin = FALSE;
  661. //
  662. // If we failed join and found a sponsor, skip clusterform
  663. //
  664. if (bFormCluster == FALSE) {
  665. return (JoinStatus);
  666. }
  667. ClRtlLogPrint(LOG_NOISE,
  668. "[INIT] Attempting to form cluster %1!ws!\n",
  669. CsClusterName
  670. );
  671. Status = ClusterForm();
  672. if (Status != ERROR_SUCCESS) {
  673. ClRtlLogPrint(LOG_CRITICAL,
  674. "[INIT] Failed to form cluster, status %1!u!.\n",
  675. Status
  676. );
  677. if (Status == ERROR_BUSY) {
  678. //
  679. // Couldn't arbitrate for the quorum disk. Return
  680. // the join status, since that is the real failure.
  681. //
  682. Status = JoinStatus;
  683. }
  684. CsLogEventData(
  685. LOG_CRITICAL,
  686. SERVICE_FAILED_JOIN_OR_FORM,
  687. sizeof(Status),
  688. &Status
  689. );
  690. return(Status);
  691. }
  692. }
  693. else {
  694. bJoin = TRUE;
  695. }
  696. //
  697. // We are now a full cluster member.
  698. //
  699. //
  700. // Register the ExtroCluster (join) RPC interface so we can sponsor a
  701. // joining node.
  702. //
  703. Status = ClusterRegisterExtroclusterRpcInterface();
  704. if (Status != RPC_S_OK) {
  705. return(Status);
  706. }
  707. //
  708. // Register the Join Version RPC interface so we can determine
  709. // the version of a joining node.
  710. //
  711. Status = ClusterRegisterJoinVersionRpcInterface();
  712. if (Status != RPC_S_OK) {
  713. return(Status);
  714. }
  715. //
  716. // Enable this node to participate in regroups.
  717. //
  718. MmSetRegroupAllowed(TRUE);
  719. //
  720. // Advertise that the node is fully up now
  721. //
  722. Status = NmSetExtendedNodeState( ClusterNodeUp );
  723. if (Status != ERROR_SUCCESS) {
  724. // NmSetExtendedNodeState logs an error //
  725. return(Status);
  726. }
  727. //
  728. // Node is UP, initialize and start listening for backup stuff.
  729. ClRtlLogPrint( LOG_NOISE, "[INIT] VSS: Initializing\n" );
  730. hr = g_pCVssWriterCluster->Initialize( g_VssIdCluster, // VSS_ID WriterId;
  731. L"Cluster Service Writer", // LPCWSTR WriterName;
  732. VSS_UT_SYSTEMSERVICE, // VSS_USAGE_TYPE UsageType;
  733. VSS_ST_OTHER // VSS_SOURCE_TYPE SourceType;
  734. // <default> VSS_APPLICATION_LEVEL AppLevel;
  735. // <default> DWORD dwTimeoutFreeze
  736. );
  737. if ( FAILED( hr )) {
  738. ClRtlLogPrint( LOG_CRITICAL, "[INIT] VSS: Failed to initialize VSS, status 0x%1!x!\n", hr );
  739. Status = HRESULT_CODE( hr );
  740. return Status;
  741. }
  742. // Now we need to subscibe so that we get the events for backup.
  743. //
  744. ClRtlLogPrint( LOG_NOISE, "[INIT] VSS: Calling subscribe to register for backup events.\n" );
  745. hr = g_pCVssWriterCluster->Subscribe( );
  746. if ( FAILED( hr )) {
  747. ClRtlLogPrint( LOG_CRITICAL, "[INIT] VSS: Failed to subscribe to VSS, status 0x%1!x!\n", hr );
  748. Status = HRESULT_CODE( hr );
  749. return Status;
  750. } else {
  751. g_bCVssWriterClusterSubscribed = TRUE;
  752. }
  753. //
  754. // Chittur Subbaraman (chitturs) - 10/28/99
  755. //
  756. // Process FM join events that must be done AFTER this cluster
  757. // node is declared as fully UP.
  758. //
  759. if ( bJoin ) {
  760. FmJoinPhase3();
  761. }
  762. //
  763. // We are now going to attempt to increase our working set size. This,
  764. // plus the priority class boost, should allow the cluster service
  765. // to run a little better and be more responsive to cluster events.
  766. //
  767. if ( GetProcessWorkingSetSize( GetCurrentProcess(),
  768. &minWorkingSetSize,
  769. &maxWorkingSetSize ) )
  770. {
  771. if ( minWorkingSetSize < MIN_WORKING_SET_SIZE ) {
  772. minWorkingSetSize = MIN_WORKING_SET_SIZE;
  773. }
  774. if ( maxWorkingSetSize < MAX_WORKING_SET_SIZE ) {
  775. maxWorkingSetSize = MAX_WORKING_SET_SIZE;
  776. }
  777. if ( SetProcessWorkingSetSize( GetCurrentProcess(),
  778. minWorkingSetSize,
  779. maxWorkingSetSize ) )
  780. {
  781. //
  782. // now report what we set it to
  783. //
  784. if ( GetProcessWorkingSetSize( GetCurrentProcess(),
  785. &minWorkingSetSize,
  786. &maxWorkingSetSize ) )
  787. {
  788. ClRtlLogPrint(LOG_NOISE,
  789. "[INIT] Working Set changed to [%1!u!, %2!u!].\n",
  790. minWorkingSetSize,
  791. maxWorkingSetSize);
  792. } else {
  793. ClRtlLogPrint(LOG_UNUSUAL,
  794. "[INIT] Failed to re-read our working set size, Status %1!u!.\n",
  795. GetLastError());
  796. }
  797. } else {
  798. ClRtlLogPrint(LOG_UNUSUAL,
  799. "[INIT] Failed to set our Min WS to %1!u!, Max WS to %2!u!, Status %3!u!.\n",
  800. minWorkingSetSize,
  801. maxWorkingSetSize,
  802. GetLastError());
  803. }
  804. } else {
  805. ClRtlLogPrint(LOG_UNUSUAL,
  806. "[INIT] Failed to get our working set size, Status %1!u!.\n",
  807. GetLastError()
  808. );
  809. }
  810. CspLogStartEvent(bJoin);
  811. #if 0
  812. //
  813. // Chittur Subbaraman (chitturs) - 11/4/98
  814. //
  815. if ( CsForceDatabaseRestore == TRUE )
  816. {
  817. //
  818. // If you stopped the service on any nodes for database restoration
  819. // purposes, then start them now
  820. //
  821. RdbStartSvcOnNodes ( L"clussvc" );
  822. }
  823. #endif
  824. {
  825. //
  826. // Vij Vasu (Vvasu) 24-AUG-2000
  827. //
  828. // Initiate the process that notifies interested listeners that the cluster
  829. // service has started up.
  830. HRESULT hr = ClRtlInitiateStartupNotification();
  831. if ( FAILED( hr ) ) {
  832. // If the process of notifying listeners could not be initiated, just log
  833. // the return code as a warning.
  834. ClRtlLogPrint(LOG_UNUSUAL,
  835. "[INIT] Error 0x%1!08lx! occurred trying to initiate cluster startup notifications.\n",
  836. hr);
  837. }
  838. }
  839. ClRtlLogPrint(LOG_NOISE, "[INIT] Cluster started.\n");
  840. return(ERROR_SUCCESS);
  841. }
  842. VOID
  843. ClusterShutdown(
  844. DWORD ExitCode
  845. )
  846. /*++
  847. Routine Description:
  848. Shuts down the cluster in reverse order than it was brought up.
  849. Arguments:
  850. None.
  851. Return Value:
  852. ERROR_SUCCESS if successful
  853. Win32 error code otherwise.
  854. --*/
  855. {
  856. HRESULT hr = S_OK;
  857. //
  858. // Shutdown all components of the Cluster Service in approximately
  859. // the reverse order they we brought up.
  860. //
  861. ClRtlLogPrint(LOG_UNUSUAL,
  862. "[INIT] The cluster service is shutting down.\n");
  863. //
  864. // Enable this when we support ClusterShuttingDown state
  865. //
  866. // NmSetExtendedNodeState( ClusterNodeDown );
  867. #ifdef CLUSTER_TESTPOINT
  868. TESTPT(TpFailClusterShutdown) {
  869. return;
  870. }
  871. #endif
  872. MmSetRegroupAllowed(FALSE);
  873. // if replicated event logging was initialized, shut it down
  874. if (!CsNoRepEvtLogging)
  875. {
  876. //
  877. // Shutdown the cluster eventlog manager- this deregisters with the
  878. // eventlog server.
  879. EvShutdown();
  880. }
  881. CsServiceStatus.dwCheckPoint++;
  882. CsAnnounceServiceStatus();
  883. #if 0
  884. //
  885. // Chittur Subbaraman (chitturs) - 5/8/2000
  886. //
  887. // Don't shutdown DM updates for now so as to avoid spurious node shoot downs due to the locker
  888. // node shutting down and hence the DM update succeeding when in fact it should fail.
  889. //
  890. DmShutdownUpdates();
  891. #endif
  892. //
  893. // Move or offline all groups owned by this node. This will destroy
  894. // the resource monitors and the in-memory resource and group objects.
  895. //
  896. FmShutdownGroups();
  897. CsServiceStatus.dwCheckPoint++;
  898. CsAnnounceServiceStatus();
  899. // Shutdown the dm- this flushes the log file and releases the dm hooks.
  900. DmShutdown();
  901. CsServiceStatus.dwCheckPoint++;
  902. CsAnnounceServiceStatus();
  903. // Unsubscribe from Vss
  904. //
  905. if ( g_bCVssWriterClusterSubscribed ) {
  906. ClRtlLogPrint( LOG_NOISE, "[INIT] VSS: Unsubscribing\n" );
  907. hr = g_pCVssWriterCluster->Unsubscribe( );
  908. if ( FAILED( hr ) ) {
  909. ClRtlLogPrint( LOG_CRITICAL, "[INIT] VSS: Failed to Unsubscribe from VSS, status 0x%1!x!\n", hr );
  910. } else {
  911. g_bCVssWriterClusterSubscribed = FALSE;
  912. }
  913. }
  914. // Delete our Vss instance if we have one (and if we are subscribed).
  915. //
  916. if (g_pCVssWriterCluster && (g_bCVssWriterClusterSubscribed == FALSE) ) {
  917. delete g_pCVssWriterCluster;
  918. }
  919. TestpointDeInit();
  920. CsServiceStatus.dwCheckPoint++;
  921. CsAnnounceServiceStatus();
  922. NmCloseConnectoidAdviseSink();
  923. CoUninitialize();
  924. //
  925. // Triger banishing regroup incident prompting
  926. // other nodes in the cluster to regroup this node out
  927. //
  928. MMLeave();
  929. //
  930. // Exit the process now... there are a number of circular dependencies
  931. // that have been built up during the 'life of the cluster'. There
  932. // is no easy way to unwind from here... so just exit out.
  933. //
  934. //
  935. // Announce that we are stopped only if we were successful in
  936. // initializing. The SC will not restart the service if we report that
  937. // we've stopped. Make sure the service status announcement is the last
  938. // thing done since there is a race between this thread and the main
  939. // thread that will prevent code after the announcement from being
  940. // executed.
  941. //
  942. ClRtlLogPrint(( ExitCode == ERROR_SUCCESS ) ? LOG_NOISE : LOG_CRITICAL,
  943. "[CS] Service Stopped. exit code = %1!u!\n\n", ExitCode);
  944. if ( ExitCode == ERROR_SUCCESS ) {
  945. CsLogEvent(LOG_NOISE, SERVICE_SUCCESSFUL_TERMINATION);
  946. CsServiceStatus.dwCurrentState = SERVICE_STOPPED;
  947. CsServiceStatus.dwControlsAccepted = 0;
  948. CsServiceStatus.dwCheckPoint = 0;
  949. CsServiceStatus.dwWaitHint = 0;
  950. CspSetErrorCode( ExitCode, &CsServiceStatus );
  951. CsAnnounceServiceStatus();
  952. } else {
  953. ExitCode = CspSetErrorCode( ExitCode, &CsServiceStatus );
  954. }
  955. //release the mutex so that the next one can acquire the mutex immediately
  956. ReleaseMutex(CspMutex);
  957. ExitProcess(ExitCode);
  958. #if 0
  959. //
  960. // Everything after this point is what should happen in a clean shutdown.
  961. //
  962. // Shutdown the Failover Manager.
  963. FmShutdown();
  964. CsServiceStatus.dwCheckPoint++;
  965. CsAnnounceServiceStatus();
  966. //
  967. // Shutdown the Cluster Api.
  968. //
  969. ApiShutdown();
  970. CsServiceStatus.dwCheckPoint++;
  971. CsAnnounceServiceStatus();
  972. //
  973. // Stop the RPC server and deregister our endpoints & interfaces.
  974. //
  975. ClusterShutdownRpcServer();
  976. CsServiceStatus.dwCheckPoint++;
  977. CsAnnounceServiceStatus();
  978. //
  979. // At this point, all calls on the Intracluster and Extrocluster
  980. // RPC interfaces are complete and no more will be received.
  981. //
  982. // Note - Calls on the Clusapi interface are still possible.
  983. //
  984. //
  985. // Shutdown the Node Manager.
  986. //
  987. NmShutdown();
  988. CsServiceStatus.dwCheckPoint++;
  989. CsAnnounceServiceStatus();
  990. // Shutdown the Event Processor.
  991. EpShutdown();
  992. CsServiceStatus.dwCheckPoint++;
  993. CsAnnounceServiceStatus();
  994. LmShutdown();
  995. CsServiceStatus.dwCheckPoint++;
  996. CsAnnounceServiceStatus();
  997. CpShutdown();
  998. CsServiceStatus.dwCheckPoint++;
  999. CsAnnounceServiceStatus();
  1000. //shutdown gum
  1001. GumShutdown();
  1002. CsServiceStatus.dwCheckPoint++;
  1003. CsAnnounceServiceStatus();
  1004. // Shutdown the Object Manager.
  1005. OmShutdown();
  1006. CsServiceStatus.dwCheckPoint++;
  1007. CsAnnounceServiceStatus();
  1008. //
  1009. // Destroy the global work queues
  1010. //
  1011. if (CsDelayedWorkQueue != NULL) {
  1012. IF_DEBUG(CLEANUP) {
  1013. ClRtlLogPrint(LOG_NOISE,"[CS] Destroying delayed work queue...\n");
  1014. }
  1015. ClRtlDestroyWorkQueue(CsDelayedWorkQueue);
  1016. CsDelayedWorkQueue = NULL;
  1017. }
  1018. CsServiceStatus.dwCheckPoint++;
  1019. CsAnnounceServiceStatus();
  1020. if (CsCriticalWorkQueue != NULL) {
  1021. IF_DEBUG(CLEANUP) {
  1022. ClRtlLogPrint(LOG_NOISE,"[CS] Destroying critical work queue...\n");
  1023. }
  1024. ClRtlDestroyWorkQueue(CsCriticalWorkQueue);
  1025. CsDelayedWorkQueue = NULL;
  1026. }
  1027. ClRtlEventLogSetWorkQueue( NULL );
  1028. if (CspEventReportingWorkQueue != NULL) {
  1029. IF_DEBUG(CLEANUP) {
  1030. ClRtlLogPrint(LOG_NOISE,"[CS] Destroying event reporing work queue...\n");
  1031. }
  1032. ClRtlDestroyWorkQueue(CspEventReportingWorkQueue);
  1033. CspEventReportingWorkQueue = NULL;
  1034. }
  1035. //
  1036. // Free global data
  1037. //
  1038. LocalFree(CsClusterName);
  1039. if (CspMutex != NULL) {
  1040. CloseHandle(CspMutex);
  1041. CspMutex = NULL;
  1042. }
  1043. CsServiceStatus.dwCheckPoint++;
  1044. CsAnnounceServiceStatus();
  1045. CsLogEvent(LOG_NOISE, SERVICE_SUCCESSFUL_TERMINATION);
  1046. #endif // 0
  1047. return;
  1048. }
  1049. DWORD
  1050. ClusterForm(
  1051. VOID
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Code path for initializing a new instance of the cluster. This
  1056. is taken when there are no nodes active in the cluster.
  1057. Arguments:
  1058. None
  1059. Return Value:
  1060. ERROR_SUCCESS if successful.
  1061. Win32 error code otherwise.
  1062. --*/
  1063. {
  1064. DWORD Status;
  1065. PFM_GROUP pQuoGroup;
  1066. DWORD dwError;
  1067. DWORD dwQuorumDiskSignature = 0;
  1068. //
  1069. // Initialize the event handler.
  1070. //
  1071. Status = EpInitPhase1();
  1072. if ( Status != ERROR_SUCCESS) {
  1073. ClRtlLogPrint(LOG_CRITICAL,
  1074. "[CS] EpInitPhase1 failed, Status = %1!u!\n",
  1075. Status);
  1076. return(Status);
  1077. }
  1078. //
  1079. // The API server is required by FM, since it starts the resource monitor.
  1080. //
  1081. Status = ApiOnlineReadOnly();
  1082. if ( Status != ERROR_SUCCESS) {
  1083. ClRtlLogPrint(LOG_CRITICAL,
  1084. "[CS] ApiInitPhase1 failed, Status = %1!u!\n",
  1085. Status);
  1086. goto partial_form_exit;
  1087. }
  1088. //
  1089. // Arbitrate for the quorum resource.
  1090. //
  1091. Status = FmGetQuorumResource(&pQuoGroup, &dwQuorumDiskSignature);
  1092. if ( Status != ERROR_SUCCESS ) {
  1093. if ( ( Status == ERROR_FILE_NOT_FOUND ) &&
  1094. ( CsForceDatabaseRestore == TRUE ) ) {
  1095. //
  1096. // Chittur Subbaraman (chitturs) - 10/30/98
  1097. //
  1098. // Try to fix up the quorum disk signature and if successful
  1099. // try to get the quorum resource again. Note that the following
  1100. // function will attempt a fix up only if the CsForceDatabaseRestore
  1101. // flag is set.
  1102. //
  1103. if ( RdbFixupQuorumDiskSignature( dwQuorumDiskSignature ) ) {
  1104. Status = FmGetQuorumResource( &pQuoGroup, NULL );
  1105. if ( Status != ERROR_SUCCESS ) {
  1106. Status = ERROR_QUORUM_DISK_NOT_FOUND;
  1107. ClRtlLogPrint(LOG_CRITICAL,
  1108. "[INIT] Could not get quorum resource even after fix up, Status = %1!u!\n",
  1109. Status);
  1110. goto partial_form_exit;
  1111. }
  1112. } else {
  1113. Status = ERROR_QUORUM_DISK_NOT_FOUND;
  1114. ClRtlLogPrint(LOG_CRITICAL,
  1115. "[INIT] ClusterForm: Could not get quorum resource, Status = %1!u!\n",
  1116. Status);
  1117. goto partial_form_exit;
  1118. }
  1119. } else {
  1120. Status = ERROR_QUORUM_DISK_NOT_FOUND;
  1121. ClRtlLogPrint(LOG_CRITICAL,
  1122. "[INIT] ClusterForm: Could not get quorum resource. No fixup attempted. Status = %1!u!\n",
  1123. Status);
  1124. goto partial_form_exit;
  1125. }
  1126. }
  1127. //
  1128. // Call the Database Manager to update the cluster registry.
  1129. //
  1130. Status = DmFormNewCluster();
  1131. if ( Status != ERROR_SUCCESS ) {
  1132. ClRtlLogPrint(LOG_CRITICAL,
  1133. "[CS] Error calling DmUpdateFormNewCluster, Status = %1!u!\n",
  1134. Status);
  1135. goto partial_form_exit;
  1136. }
  1137. if (FmDoesQuorumAllowLogging() != ERROR_SUCCESS)
  1138. CsNoQuorumLogging = TRUE;
  1139. if (!CsNoQuorum)
  1140. {
  1141. // Bring the quorum resource online
  1142. dwError = FmBringQuorumOnline();
  1143. if ((dwError == ERROR_IO_PENDING) || (dwError == ERROR_SUCCESS))
  1144. {
  1145. //this waits on an event for the quorum resorce to come online
  1146. //when the quorum resource comes online, the log file is opened
  1147. //if noquorumlogging flag is not specified
  1148. if ((dwError = DmWaitQuorumResOnline()) != ERROR_SUCCESS)
  1149. {
  1150. ClRtlLogPrint(LOG_NOISE,
  1151. "[CS] Wait for quorum resource to come online failed, error=%1!u!\r\n",
  1152. dwError);
  1153. Status = ERROR_QUORUM_RESOURCE_ONLINE_FAILED;
  1154. goto partial_form_exit;
  1155. }
  1156. }
  1157. else
  1158. {
  1159. ClRtlLogPrint(LOG_UNUSUAL,
  1160. "[CS] couldnt bring quorum resource online, Error =%1!u!\n",
  1161. dwError);
  1162. CL_LOGFAILURE(dwError);
  1163. Status = ERROR_QUORUM_RESOURCE_ONLINE_FAILED;
  1164. goto partial_form_exit;
  1165. }
  1166. }
  1167. //update status with scm, the quorum resource may take a while to come online
  1168. CsServiceStatus.dwCheckPoint++;
  1169. CsAnnounceServiceStatus();
  1170. if (!CsNoQuorumLogging)
  1171. {
  1172. //roll the Cluster Log File
  1173. if ((Status = DmRollChanges()) != ERROR_SUCCESS)
  1174. {
  1175. ClRtlLogPrint(LOG_CRITICAL,
  1176. "[CS] Error calling DmRollChanges, Status = %1!u!\n",
  1177. Status);
  1178. goto partial_form_exit;
  1179. }
  1180. }
  1181. //
  1182. // Close the groups/resources created by fm except for the quorum
  1183. // resource. The in memory data base needs to be created again with
  1184. // the new rolled changes
  1185. //
  1186. Status = FmFormNewClusterPhase1(pQuoGroup);
  1187. if ( Status != ERROR_SUCCESS ) {
  1188. ClRtlLogPrint(LOG_CRITICAL,
  1189. "[CS] Error calling FmOnline, Status = %1!u!\n",
  1190. Status);
  1191. goto partial_form_exit;
  1192. }
  1193. #ifdef CLUSTER_TESTPOINT
  1194. TESTPT(TpFailFormNewCluster) {
  1195. Status = 999999;
  1196. goto partial_form_exit;
  1197. }
  1198. #endif
  1199. //
  1200. // Start up the Node Manager. This will form a cluster at the membership
  1201. // level.
  1202. //
  1203. Status = NmFormNewCluster();
  1204. if ( Status != ERROR_SUCCESS ) {
  1205. ClRtlLogPrint(LOG_CRITICAL,
  1206. "[CS] Error calling NmOnline, Status = %1!u!\n",
  1207. Status);
  1208. goto partial_form_exit;
  1209. }
  1210. //
  1211. //call any registry fixup callbacks, if they are registered.
  1212. //This is useful for upgrades/uninstalls if you want to clean up
  1213. //the registry
  1214. Status = NmPerformFixups(NM_FORM_FIXUP);
  1215. if ( Status != ERROR_SUCCESS ) {
  1216. ClRtlLogPrint(LOG_CRITICAL,
  1217. "[CS] Error calling NmPerformFixups, Status = %1!u!\n",
  1218. Status);
  1219. goto partial_form_exit;
  1220. }
  1221. //
  1222. // The API server can now be brought fully online. This enables us
  1223. // to receive calls.
  1224. //
  1225. Status = ApiOnline();
  1226. if ( Status != ERROR_SUCCESS) {
  1227. ClRtlLogPrint(LOG_CRITICAL,
  1228. "[CS] ApiInitPhase2 failed, Status = %1!u!\n",
  1229. Status);
  1230. goto partial_form_exit;
  1231. }
  1232. //update status for scm
  1233. CsServiceStatus.dwCheckPoint++;
  1234. CsAnnounceServiceStatus();
  1235. //
  1236. // Call the Failover Manager Phase 2 routine next.
  1237. // Create the groups and resources.
  1238. //
  1239. Status = FmFormNewClusterPhase2();
  1240. if ( Status != ERROR_SUCCESS ) {
  1241. ClRtlLogPrint(LOG_CRITICAL,
  1242. "[CS] Error calling FmOnline, Status = %1!u!\n",
  1243. Status);
  1244. goto partial_form_exit;
  1245. }
  1246. //
  1247. // Fire up the intracluster RPC server so we can receive calls.
  1248. //
  1249. Status = ClusterRegisterIntraclusterRpcInterface();
  1250. if ( Status != ERROR_SUCCESS ) {
  1251. goto partial_form_exit;
  1252. }
  1253. //
  1254. // Finish initializing the cluster wide event logging
  1255. //
  1256. // ASSUMPTION: this is called after the NM has established cluster
  1257. // membership.
  1258. //
  1259. if (!CsNoRepEvtLogging)
  1260. {
  1261. //is replicated logging is not disabled
  1262. Status = EvOnline();
  1263. if ( Status != ERROR_SUCCESS ) {
  1264. ClRtlLogPrint(LOG_CRITICAL,
  1265. "[CS] Error calling EvOnline, Status = %1!u!\n",
  1266. Status);
  1267. }
  1268. }
  1269. if (!CsNoQuorumLogging)
  1270. {
  1271. //check if all nodes are up, if not take a checkpoint and
  1272. //turn quorum logging on
  1273. Status = DmUpdateFormNewCluster();
  1274. if ( Status != ERROR_SUCCESS ) {
  1275. ClRtlLogPrint(LOG_CRITICAL,
  1276. "[CS] Error calling DmCompleteFormNewCluster, Status = %1!u!\n",
  1277. Status);
  1278. }
  1279. }
  1280. ClRtlLogPrint(LOG_NOISE, "[INIT] Successfully formed a cluster.\n");
  1281. return(ERROR_SUCCESS);
  1282. partial_form_exit:
  1283. ClRtlLogPrint(LOG_NOISE, "[INIT] Cleaning up failed form attempt.\n");
  1284. return(Status);
  1285. }
  1286. VOID
  1287. ClusterLeave(
  1288. VOID
  1289. )
  1290. /*++
  1291. Routine Description:
  1292. Removes the local node from an active cluster or cleans up after
  1293. a failed attempt to join or form a cluster.
  1294. Arguments:
  1295. None
  1296. Return Value:
  1297. ERROR_SUCCESS if successful.
  1298. Win32 error code otherwise.
  1299. --*/
  1300. {
  1301. ClRtlLogPrint(LOG_NOISE, "[INIT] Leaving cluster\n");
  1302. //
  1303. // Turn off the cluster API
  1304. //
  1305. ApiOffline();
  1306. //
  1307. // If we are a cluster member, leave now.
  1308. //
  1309. NmLeaveCluster();
  1310. ClusterDeregisterRpcInterfaces();
  1311. return;
  1312. } // Cluster Leave
  1313. //
  1314. // RPC Server Control routines
  1315. //
  1316. RPC_STATUS
  1317. ClusterInitializeRpcServer(
  1318. VOID
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. Initializes the RPC server for the cluster service.
  1323. Arguments:
  1324. None.
  1325. Return Value:
  1326. RPC_S_OK if the routine succeeds. An RPC error code if it fails.
  1327. --*/
  1328. {
  1329. RPC_STATUS Status;
  1330. SECURITY_DESCRIPTOR SecDescriptor;
  1331. DWORD i;
  1332. DWORD retry;
  1333. DWORD packagesRegistered = 0;
  1334. ClRtlLogPrint(LOG_NOISE, "[CS] Initializing RPC server.\n");
  1335. //
  1336. // Enable authentication of calls to our RPC interfaces. For NTLM,
  1337. // the PrincipleName is ignored, but we'll need to supply one if we
  1338. // switch authentication services later on. Note that it is not
  1339. // necessary to specify an authentication service for each interface.
  1340. //
  1341. for ( i = 0; i < CsNumberOfRPCSecurityPackages; ++i ) {
  1342. Status = RpcServerRegisterAuthInfo(NULL,
  1343. CsRPCSecurityPackage[ i ],
  1344. NULL,
  1345. NULL);
  1346. if (Status == RPC_S_OK) {
  1347. ++packagesRegistered;
  1348. } else {
  1349. ClRtlLogPrint(LOG_CRITICAL,
  1350. "[CS] Unable to register %1!ws! authentication for RPC, status %2!u!.\n",
  1351. CsRPCSecurityPackageName[ i ],
  1352. Status);
  1353. }
  1354. }
  1355. if ( packagesRegistered == 0 ) {
  1356. return ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED;
  1357. }
  1358. //
  1359. // Bind to UDP. This transport will be used by remote clients to
  1360. // access the clusapi interface and by cluster nodes to
  1361. // access the extrocluster (join) interface. This uses a dynamic
  1362. // endpoint.
  1363. //
  1364. Status = RpcServerUseProtseq(
  1365. TEXT("ncadg_ip_udp"),
  1366. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  1367. NULL);
  1368. if (Status != RPC_S_OK) {
  1369. ClRtlLogPrint(LOG_CRITICAL,
  1370. "[INIT] Unable to bind RPC to UDP, status %1!u!.\n",
  1371. Status);
  1372. return(Status);
  1373. }
  1374. //
  1375. // Figure out which UDP endpoint we got so we can register it with
  1376. // the endpoint mapper later. We must do this before we register any
  1377. // other protocol sequences, or they will show up in the vector.
  1378. // Groveling the binding vector for a specific transport is no fun.
  1379. //
  1380. CL_ASSERT( CsRpcBindingVector == NULL);
  1381. Status = RpcServerInqBindings(&CsRpcBindingVector);
  1382. if (Status != RPC_S_OK) {
  1383. ClRtlLogPrint(LOG_CRITICAL,
  1384. "[INIT] Unable to obtain RPC binding vector, status %1!u!.\n",
  1385. Status);
  1386. return(Status);
  1387. }
  1388. // ncalrpc needs a security descriptor.
  1389. InitializeSecurityDescriptor(
  1390. &SecDescriptor,
  1391. SECURITY_DESCRIPTOR_REVISION
  1392. );
  1393. //get a null dacl
  1394. if (!SetSecurityDescriptorDacl(&SecDescriptor, TRUE, NULL,FALSE)) // Not defaulted
  1395. {
  1396. Status = GetLastError();
  1397. ClRtlLogPrint(LOG_CRITICAL,
  1398. "[INIT] Unable to obtain a NULL dacl %1!u!.\n",
  1399. Status);
  1400. return(Status);
  1401. }
  1402. //
  1403. // Bind to LPC. This transport will be used by clients running on this
  1404. // system to access the clusapi interface. This uses a well-known
  1405. // endpoint.
  1406. //
  1407. Status = RpcServerUseProtseqEp(
  1408. TEXT("ncalrpc"),
  1409. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  1410. TEXT("clusapi"),
  1411. &SecDescriptor);
  1412. if (Status != RPC_S_OK) {
  1413. ClRtlLogPrint(LOG_CRITICAL,
  1414. "[INIT] Unable to bind RPC to LPC, status %1!u!.\n",
  1415. Status);
  1416. return(Status);
  1417. }
  1418. //
  1419. // Bind to CDP (Cluster Datagram Protocol). This transport will be used
  1420. // for the intracluster interface. This uses a well-known endpoint.
  1421. //
  1422. // GN: Sometimes it takes a couple of seconds for resrcmon to go away after
  1423. // a clean shutdown. When SCM tries to restart the service the following call will fail.
  1424. // In order to overcome this we will give up only if we couldn't bind RPC to CDP
  1425. // 10 times with 1 second in between the calls
  1426. //
  1427. retry = 10;
  1428. for (;;) {
  1429. Status = RpcServerUseProtseqEp(
  1430. CLUSTER_RPC_PROTSEQ,
  1431. 1, // Max calls
  1432. CLUSTER_RPC_PORT,
  1433. NULL);
  1434. if (Status != RPC_S_DUPLICATE_ENDPOINT || retry == 0) {
  1435. break;
  1436. }
  1437. ClRtlLogPrint(LOG_UNUSUAL,
  1438. "[INIT] Unable to bind RPC to CDP, status %1!u!. Retrying...\n",
  1439. Status);
  1440. Sleep(1000);
  1441. --retry;
  1442. }
  1443. if (Status != RPC_S_OK) {
  1444. ClRtlLogPrint(LOG_CRITICAL,
  1445. "[INIT] Unable to bind RPC to CDP, status %1!u!.\n",
  1446. Status);
  1447. return(Status);
  1448. }
  1449. //
  1450. // Start our RPC server. Note that we will not get any calls until
  1451. // we register our interfaces.
  1452. //
  1453. Status = RpcServerListen(
  1454. CS_CONCURRENT_RPC_CALLS,
  1455. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  1456. TRUE);
  1457. if ((Status != RPC_S_OK) && (Status != RPC_S_ALREADY_LISTENING)) {
  1458. ClRtlLogPrint(LOG_CRITICAL,
  1459. "[CS] Unable to start RPC server, status %1!u!.\n",
  1460. Status
  1461. );
  1462. return(Status);
  1463. }
  1464. RpcSsDontSerializeContext();
  1465. return(RPC_S_OK);
  1466. }
  1467. DWORD
  1468. ClusterRegisterIntraclusterRpcInterface(
  1469. VOID
  1470. )
  1471. {
  1472. DWORD Status;
  1473. Status = RpcServerRegisterIfEx(
  1474. s_IntraCluster_v2_0_s_ifspec,
  1475. NULL,
  1476. NULL,
  1477. 0,
  1478. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  1479. CsUseAuthenticatedRPC ? reinterpret_cast<RPC_IF_CALLBACK_FN(__stdcall *)>( ApipConnectCallback ) : NULL
  1480. // CsUseAuthenticatedRPC ? ApipConnectCallback : NULL
  1481. );
  1482. if (Status != RPC_S_OK) {
  1483. ClRtlLogPrint(LOG_CRITICAL,
  1484. "[INIT] Unable to register the IntraCluster interface, Status %1!u!.\n",
  1485. Status
  1486. );
  1487. return(Status);
  1488. }
  1489. CspIntraclusterRpcServerStarted = TRUE;
  1490. return(ERROR_SUCCESS);
  1491. } // ClusterRegisterIntraclusterRpcInterface
  1492. DWORD
  1493. ClusterRegisterExtroclusterRpcInterface(
  1494. VOID
  1495. )
  1496. {
  1497. DWORD Status;
  1498. Status = RpcServerRegisterIfEx(
  1499. s_ExtroCluster_v2_0_s_ifspec,
  1500. NULL,
  1501. NULL,
  1502. 0,
  1503. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  1504. CsUseAuthenticatedRPC ? reinterpret_cast<RPC_IF_CALLBACK_FN( __stdcall *)>( ApipConnectCallback ) : NULL
  1505. // CsUseAuthenticatedRPC ? ApipConnectCallback : NULL
  1506. );
  1507. if (Status != RPC_S_OK) {
  1508. ClRtlLogPrint(LOG_CRITICAL,
  1509. "[INIT] Unable to register the ExtroCluster interface, status %1!u!.\n",
  1510. Status
  1511. );
  1512. return(Status);
  1513. }
  1514. CL_ASSERT( CsRpcBindingVector != NULL);
  1515. Status = RpcEpRegister(
  1516. s_ExtroCluster_v2_0_s_ifspec,
  1517. CsRpcBindingVector,
  1518. NULL,
  1519. L"Microsoft Extrocluster Interface"
  1520. );
  1521. if (Status != RPC_S_OK) {
  1522. ClRtlLogPrint(LOG_CRITICAL,
  1523. "[INIT] Unable to register the ExtroCluster interface endpoint, status %1!u!.\n",
  1524. Status
  1525. );
  1526. NmDumpRpcExtErrorInfo(Status);
  1527. return(Status);
  1528. }
  1529. return(ERROR_SUCCESS);
  1530. } // ClusterRegisterExtroclusterRpcInterface
  1531. DWORD
  1532. ClusterRegisterJoinVersionRpcInterface(
  1533. VOID
  1534. )
  1535. {
  1536. DWORD Status;
  1537. Status = RpcServerRegisterIfEx(
  1538. s_JoinVersion_v2_0_s_ifspec,
  1539. NULL,
  1540. NULL,
  1541. 0,
  1542. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  1543. CsUseAuthenticatedRPC ? reinterpret_cast<RPC_IF_CALLBACK_FN *>( ApipConnectCallback ) : NULL
  1544. // CsUseAuthenticatedRPC ? ApipConnectCallback : NULL
  1545. );
  1546. if (Status != RPC_S_OK) {
  1547. ClRtlLogPrint(LOG_CRITICAL,
  1548. "[INIT] Unable to register the JoinVersion interface, status %1!u!.\n",
  1549. Status
  1550. );
  1551. return(Status);
  1552. }
  1553. CL_ASSERT( CsRpcBindingVector != NULL);
  1554. Status = RpcEpRegister(
  1555. s_JoinVersion_v2_0_s_ifspec,
  1556. CsRpcBindingVector,
  1557. NULL,
  1558. L"Microsoft JoinVersion Interface"
  1559. );
  1560. if (Status != RPC_S_OK) {
  1561. ClRtlLogPrint(LOG_CRITICAL,
  1562. "[INIT] Unable to register the JoinVersion interface endpoint, status %1!u!.\n",
  1563. Status
  1564. );
  1565. NmDumpRpcExtErrorInfo(Status);
  1566. return(Status);
  1567. }
  1568. return(ERROR_SUCCESS);
  1569. } // ClusterRegisterJoinVersionRpcInterface
  1570. VOID
  1571. ClusterDeregisterRpcInterfaces(
  1572. VOID
  1573. )
  1574. {
  1575. RPC_STATUS Status;
  1576. ClRtlLogPrint(LOG_NOISE,
  1577. "[INIT] Deregistering RPC endpoints & interfaces.\n"
  1578. );
  1579. //
  1580. // Deregister the Extrocluster and JoinVersion interface endpoints.
  1581. // There is no endpoint for the Intracluster interface.
  1582. //
  1583. if (CsRpcBindingVector != NULL) {
  1584. Status = RpcEpUnregister(
  1585. s_ExtroCluster_v2_0_s_ifspec,
  1586. CsRpcBindingVector,
  1587. NULL
  1588. );
  1589. if ((Status != RPC_S_OK) && (Status != EPT_S_NOT_REGISTERED)) {
  1590. ClRtlLogPrint(LOG_UNUSUAL,
  1591. "[INIT] Failed to deregister endpoint for ExtroCluster interface, status %1!u!.\n",
  1592. Status
  1593. );
  1594. }
  1595. Status = RpcEpUnregister(
  1596. s_JoinVersion_v2_0_s_ifspec,
  1597. CsRpcBindingVector,
  1598. NULL
  1599. );
  1600. if ((Status != RPC_S_OK) && (Status != EPT_S_NOT_REGISTERED)) {
  1601. ClRtlLogPrint(LOG_UNUSUAL,
  1602. "[INIT] Failed to deregister endpoint for JoinVersion interface, status %1!u!.\n",
  1603. Status
  1604. );
  1605. }
  1606. }
  1607. //
  1608. // Deregister the interfaces
  1609. //
  1610. Status = RpcServerUnregisterIf(
  1611. s_ExtroCluster_v2_0_s_ifspec,
  1612. NULL,
  1613. 1 // Wait for outstanding calls to complete
  1614. );
  1615. if ((Status != RPC_S_OK) && (Status != RPC_S_UNKNOWN_IF)) {
  1616. ClRtlLogPrint(LOG_UNUSUAL,
  1617. "[INIT] Unable to deregister the ExtroCluster interface, Status %1!u!.\n",
  1618. Status
  1619. );
  1620. }
  1621. Status = RpcServerUnregisterIf(
  1622. s_JoinVersion_v2_0_s_ifspec,
  1623. NULL,
  1624. 1 // Wait for outstanding calls to complete
  1625. );
  1626. if ((Status != RPC_S_OK) && (Status != RPC_S_UNKNOWN_IF)) {
  1627. ClRtlLogPrint(LOG_UNUSUAL,
  1628. "[INIT] Unable to deregister the JoinVersion interface, Status %1!u!.\n",
  1629. Status
  1630. );
  1631. }
  1632. Status = RpcServerUnregisterIf(
  1633. s_IntraCluster_v2_0_s_ifspec,
  1634. NULL,
  1635. 1 // Wait for outstanding calls to complete
  1636. );
  1637. if ((Status != RPC_S_OK) && (Status != RPC_S_UNKNOWN_IF)) {
  1638. ClRtlLogPrint(LOG_UNUSUAL,
  1639. "[INIT] Unable to deregister the IntraCluster interface, Status %1!u!.\n",
  1640. Status
  1641. );
  1642. }
  1643. return;
  1644. } // ClusterDeregisterRpcInterfaces
  1645. VOID
  1646. ClusterShutdownRpcServer(
  1647. VOID
  1648. )
  1649. {
  1650. RPC_STATUS Status;
  1651. ClRtlLogPrint(LOG_NOISE, "[INIT] Shutting down RPC server.\n");
  1652. ClusterDeregisterRpcInterfaces();
  1653. Status = RpcMgmtStopServerListening(NULL);
  1654. if ((Status != RPC_S_OK) && (Status != RPC_S_NOT_LISTENING)) {
  1655. ClRtlLogPrint(LOG_UNUSUAL,
  1656. "[INIT] Failed to shutdown RPC server, status %1!u!.\n",
  1657. Status
  1658. );
  1659. }
  1660. #if 0
  1661. //
  1662. // Note - We really should wait for all outstanding calls to complete,
  1663. // but we can't because there is no way to shutdown any
  1664. // pending API GetNotify calls.
  1665. //
  1666. Status = RpcMgmtWaitServerListen();
  1667. if ((Status != RPC_S_OK) && (Status != RPC_S_NOT_LISTENING)) {
  1668. ClRtlLogPrint(LOG_UNUSUAL,
  1669. "[INIT] Failed to wait for all RPC calls to complete, status %1!u!.\n",
  1670. Status
  1671. );
  1672. }
  1673. #endif // 0
  1674. if (CsRpcBindingVector != NULL) {
  1675. RpcBindingVectorFree(&CsRpcBindingVector);
  1676. CsRpcBindingVector = NULL;
  1677. }
  1678. return;
  1679. } // ClusterShutdownRpcServer
  1680. LONG
  1681. CspExceptionFilter(
  1682. IN PEXCEPTION_POINTERS ExceptionInfo
  1683. )
  1684. /*++
  1685. Routine Description:
  1686. Top level exception handler for the cluster service process.
  1687. Currently this just exits immediately and assumes that the
  1688. cluster proxy will notice and restart us as appropriate.
  1689. Arguments:
  1690. ExceptionInfo - Supplies the exception information
  1691. Return Value:
  1692. None.
  1693. --*/
  1694. {
  1695. ClRtlLogPrint(LOG_CRITICAL,
  1696. "[CS] Exception. Code = 0x%1!lx!, Address = 0x%2!lx!\n",
  1697. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1698. ExceptionInfo->ExceptionRecord->ExceptionAddress);
  1699. ClRtlLogPrint(LOG_CRITICAL,
  1700. "[CS] Exception parameters: %1!lx!, %2!lx!, %3!lx!, %4!lx!\n",
  1701. ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
  1702. ExceptionInfo->ExceptionRecord->ExceptionInformation[1],
  1703. ExceptionInfo->ExceptionRecord->ExceptionInformation[2],
  1704. ExceptionInfo->ExceptionRecord->ExceptionInformation[3]);
  1705. GenerateExceptionReport(ExceptionInfo);
  1706. if (lpfnOriginalExceptionFilter)
  1707. lpfnOriginalExceptionFilter(ExceptionInfo);
  1708. // the system level handler will be invoked if we return
  1709. // EXCEPTION_CONTINUE_SEARCH - for debug dont terminate the process
  1710. if ( IsDebuggerPresent()) {
  1711. return(EXCEPTION_CONTINUE_SEARCH);
  1712. } else {
  1713. #if !CLUSTER_BETA
  1714. TerminateProcess( GetCurrentProcess(),
  1715. ExceptionInfo->ExceptionRecord->ExceptionCode );
  1716. #endif
  1717. return(EXCEPTION_CONTINUE_SEARCH);
  1718. }
  1719. }
  1720. VOID
  1721. CsInconsistencyHalt(
  1722. IN DWORD Status
  1723. )
  1724. {
  1725. WCHAR string[16];
  1726. DWORD status;
  1727. //
  1728. // Chittur Subbaraman (chitturs) - 12/17/99
  1729. //
  1730. // Announce your status to the SCM as SERVICE_STOP_PENDING so that
  1731. // it does not affect restart. Also, it could let clients learn
  1732. // of the error status.
  1733. //
  1734. CsServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1735. CsServiceStatus.dwControlsAccepted = 0;
  1736. CsServiceStatus.dwCheckPoint = 0;
  1737. CsServiceStatus.dwWaitHint = 0;
  1738. status = CspSetErrorCode( Status, &CsServiceStatus );
  1739. CsAnnounceServiceStatus();
  1740. wsprintfW(&(string[0]), L"%u", Status);
  1741. ClRtlLogPrint(LOG_CRITICAL,
  1742. "[CS] Halting this node to prevent an inconsistency within the cluster. Error status = %1!u!\n",
  1743. Status
  1744. );
  1745. CsLogEvent1(
  1746. LOG_CRITICAL,
  1747. CS_EVENT_INCONSISTENCY_HALT,
  1748. string
  1749. );
  1750. //release the mutex so that the service when it starts can acqire the same
  1751. //without a delay
  1752. ReleaseMutex(CspMutex);
  1753. ExitProcess(status); // return the fake error code
  1754. }
  1755. PVOID
  1756. CsAlloc(
  1757. DWORD Size
  1758. )
  1759. {
  1760. PVOID p;
  1761. p = LocalAlloc(LMEM_FIXED, Size);
  1762. if (p == NULL) {
  1763. CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
  1764. }
  1765. return(p);
  1766. }
  1767. LPWSTR
  1768. CsStrDup(
  1769. LPCWSTR String
  1770. )
  1771. {
  1772. LPWSTR p;
  1773. DWORD Len;
  1774. Len = (lstrlenW(String)+1)*sizeof(WCHAR);
  1775. p=static_cast<LPWSTR>(LocalAlloc(LMEM_FIXED, Len));
  1776. if (p==NULL) {
  1777. CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
  1778. }
  1779. CopyMemory(p,String,Len);
  1780. return(p);
  1781. }