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.

5737 lines
162 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. nminit.c
  5. Abstract:
  6. Initialization, cluster join, and cluster form routines for the
  7. Node Manager.
  8. Author:
  9. Mike Massa (mikemas)
  10. Revision History:
  11. 6/03/96 Created.
  12. --*/
  13. /*
  14. General Implementation Notes:
  15. The functions DmBeginLocalUpdate, DmCommitLocalUpdate, and
  16. DmAbortLocalUpdate cannot be called while holding the NM lock, or
  17. a deadlock with the NmTimer thread may result during regroup when
  18. disk writes are stalled. These functions attempt to write to the
  19. quorum disk.
  20. */
  21. #include "nmp.h"
  22. #include <ntmsv1_0.h>
  23. #define CLUSREG_NAME_DISABLE_TRY_CACHE_FIRST L"DisableLsaTryCacheFirst"
  24. #define NM_TIMER_THREAD_PRIORITY 15 // same as MM timer thread
  25. //
  26. // External Data
  27. //
  28. extern BOOL CsNoQuorum;
  29. //
  30. // Public Data
  31. //
  32. HANDLE NmClusnetHandle = NULL;
  33. HCRYPTPROV NmCryptServiceProvider = 0;
  34. //
  35. // Private Data
  36. //
  37. CRITICAL_SECTION NmpLock;
  38. NM_STATE NmpState = NmStateOffline;
  39. DWORD NmpActiveThreadCount = 0;
  40. HANDLE NmpShutdownEvent = NULL;
  41. CL_NODE_ID NmpJoinerNodeId = ClusterInvalidNodeId;
  42. CL_NODE_ID NmpSponsorNodeId = ClusterInvalidNodeId;
  43. DWORD NmpJoinTimer = 0;
  44. BOOLEAN NmpJoinAbortPending = FALSE;
  45. DWORD NmpJoinSequence = 0;
  46. BOOLEAN NmpJoinerUp = FALSE;
  47. BOOLEAN NmpJoinBeginInProgress = FALSE;
  48. BOOLEAN NmpJoinerOutOfSynch = FALSE;
  49. LPWSTR NmpClusnetEndpoint = NULL;
  50. WCHAR NmpInvalidJoinerIdString[] = L"0";
  51. CL_NODE_ID NmpLeaderNodeId = ClusterInvalidNodeId;
  52. BOOL NmpCleanupIfJoinAborted = FALSE;
  53. BOOL NmpSuccessfulMMJoin = FALSE;
  54. DWORD NmpAddNodeId = ClusterInvalidNodeId;
  55. LPWSTR NmpClusterInstanceId = NULL;
  56. BOOLEAN NmpGumUpdateHandlerRegistered = FALSE;
  57. HANDLE NmpNetworkTimerThreadHandle = NULL;
  58. HANDLE NmpNetworkTimerThreadStopEvent = NULL;
  59. //externs
  60. extern DWORD CsMyHighestVersion;
  61. extern DWORD CsMyLowestVersion;
  62. extern DWORD CsClusterHighestVersion;
  63. extern DWORD CsClusterLowestVersion;
  64. GUM_DISPATCH_ENTRY NmGumDispatchTable[] = {
  65. {1, NmpUpdateCreateNode},
  66. {1, NmpUpdatePauseNode},
  67. {1, NmpUpdateResumeNode},
  68. {1, NmpUpdateEvictNode},
  69. {4, (PGUM_DISPATCH_ROUTINE1) NmpUpdateCreateNetwork},
  70. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkName},
  71. {1, NmpUpdateSetNetworkPriorityOrder},
  72. {3, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkCommonProperties},
  73. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateCreateInterface},
  74. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetInterfaceInfo},
  75. {3, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetInterfaceCommonProperties},
  76. {1, NmpUpdateDeleteInterface},
  77. {3, (PGUM_DISPATCH_ROUTINE1) NmpUpdateJoinBegin},
  78. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateJoinAbort},
  79. //
  80. // Version 2 (NT 5.0) extensions that are understood by NT4 SP4
  81. //
  82. {5, (PGUM_DISPATCH_ROUTINE1) NmpUpdateJoinBegin2},
  83. {4, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkAndInterfaceStates},
  84. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdatePerformFixups},
  85. {5, (PGUM_DISPATCH_ROUTINE1) NmpUpdatePerformFixups2},
  86. //
  87. // Version 2 (NT 5.0) extensions that are not understood by NT4 SP4
  88. // These may not be called in a mixed NT4/NT5 cluster.
  89. //
  90. {5, (PGUM_DISPATCH_ROUTINE1) NmpUpdateAddNode},
  91. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateExtendedNodeState},
  92. //
  93. // NT 5.1 extensions that are not understood by NT5 and
  94. // earlier. NT5 nodes will ignore these updates without
  95. // error.
  96. //
  97. {4, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkMulticastConfiguration},
  98. {8, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetServiceAccountPassword},
  99. };
  100. //
  101. // Local prototypes
  102. //
  103. DWORD
  104. NmpCreateRpcBindings(
  105. IN PNM_NODE Node
  106. );
  107. DWORD
  108. NmpCreateClusterInstanceId(
  109. VOID
  110. );
  111. DWORD
  112. NmpStartNetworkTimerThread(
  113. VOID
  114. );
  115. VOID
  116. NmpStopNetworkTimerThread(
  117. VOID
  118. );
  119. //
  120. // Component initialization routines.
  121. //
  122. DWORD
  123. NmInitialize(
  124. VOID
  125. )
  126. /*++
  127. Routine Description:
  128. Initializes the Node Manager component.
  129. Arguments:
  130. None
  131. Return Value:
  132. A Win32 status code.
  133. Notes:
  134. The local node object is created by this routine.
  135. --*/
  136. {
  137. DWORD status;
  138. OM_OBJECT_TYPE_INITIALIZE nodeTypeInitializer;
  139. HDMKEY nodeKey = NULL;
  140. DWORD nameSize = CS_MAX_NODE_NAME_LENGTH + 1;
  141. HKEY serviceKey;
  142. DWORD nodeIdSize = (CS_MAX_NODE_ID_LENGTH + 1) *
  143. sizeof(WCHAR);
  144. LPWSTR nodeIdString = NULL;
  145. WSADATA wsaData;
  146. WORD versionRequested;
  147. int err;
  148. ULONG ndx;
  149. DWORD valueType;
  150. NM_NODE_INFO2 nodeInfo;
  151. WCHAR errorString[12];
  152. DWORD eventCode = 0;
  153. LPWSTR string;
  154. PVOID wTimer;
  155. ULONG lsaProcessOptions;
  156. HDMKEY clusParamKey = NULL;
  157. CL_ASSERT(NmpState == NmStateOffline);
  158. ClRtlLogPrint(LOG_NOISE,"[NM] Initializing...\n");
  159. //
  160. // Initialize globals.
  161. //
  162. InitializeCriticalSection(&NmpLock);
  163. InitializeListHead(&NmpNodeList);
  164. InitializeListHead(&NmpNetworkList);
  165. InitializeListHead(&NmpInternalNetworkList);
  166. InitializeListHead(&NmpDeletedNetworkList);
  167. InitializeListHead(&NmpInterfaceList);
  168. InitializeListHead(&NmpDeletedInterfaceList);
  169. NmMaxNodes = ClusterDefaultMaxNodes;
  170. NmMaxNodeId = ClusterMinNodeId + NmMaxNodes - 1;
  171. //
  172. // Initializing the RPC Recording/cancelling mechanism
  173. // NOTE - This should move if NmMaxNodeId Definition above moves.
  174. //
  175. NmpIntraClusterRpcArr = LocalAlloc(LMEM_FIXED,
  176. sizeof(NM_INTRACLUSTER_RPC_THREAD) * (NmMaxNodeId +1));
  177. if(NmpIntraClusterRpcArr == NULL) {
  178. ClRtlLogPrint(LOG_CRITICAL,
  179. "[NM] Failed to allocate memory for RPC monitoring.\n"
  180. );
  181. status = ERROR_NOT_ENOUGH_MEMORY;
  182. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  183. goto error_exit;
  184. }
  185. else {
  186. ZeroMemory(NmpIntraClusterRpcArr,
  187. sizeof(NM_INTRACLUSTER_RPC_THREAD) * (NmMaxNodeId + 1));
  188. for(ndx = 0;ndx <= NmMaxNodeId;ndx++)
  189. InitializeListHead(&NmpIntraClusterRpcArr[ndx]);
  190. InitializeCriticalSection(&NmpRPCLock);
  191. }
  192. //
  193. // Initialize the network configuration package.
  194. //
  195. ClNetInitialize(
  196. ClNetPrint,
  197. ClNetLogEvent,
  198. ClNetLogEvent1,
  199. ClNetLogEvent2,
  200. ClNetLogEvent3
  201. );
  202. //
  203. // Initialize WinSock
  204. //
  205. versionRequested = MAKEWORD(2,0);
  206. err = WSAStartup(versionRequested, &wsaData);
  207. if (err != 0) {
  208. status = WSAGetLastError();
  209. wsprintfW(&(errorString[0]), L"%u", status);
  210. CsLogEvent1(LOG_CRITICAL, NM_EVENT_WSASTARTUP_FAILED, errorString);
  211. ClRtlLogPrint(LOG_NOISE,"[NM] Failed to initialize Winsock, status %1!u!\n", status);
  212. return(status);
  213. }
  214. if ( (LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 0)) {
  215. status = WSAVERNOTSUPPORTED;
  216. wsprintfW(&(errorString[0]), L"%u", status);
  217. CsLogEvent1(LOG_CRITICAL, NM_EVENT_WSASTARTUP_FAILED, errorString);
  218. ClRtlLogPrint(LOG_CRITICAL,
  219. "[NM] Found unexpected Windows Sockets version %1!u!\n",
  220. wsaData.wVersion
  221. );
  222. WSACleanup();
  223. return(status);
  224. }
  225. NmpShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  226. if (NmpShutdownEvent == NULL) {
  227. status = GetLastError();
  228. wsprintfW(&(errorString[0]), L"%u", status);
  229. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  230. ClRtlLogPrint(LOG_CRITICAL,
  231. "[NM] Failed to create shutdown event, status %1!u!\n",
  232. status
  233. );
  234. WSACleanup();
  235. return(status);
  236. }
  237. NmpState = NmStateOnlinePending;
  238. //
  239. // Get the name of this node.
  240. //
  241. if (!GetComputerName(&(NmLocalNodeName[0]), &nameSize)) {
  242. status = GetLastError();
  243. eventCode = NM_EVENT_GETCOMPUTERNAME_FAILED;
  244. ClRtlLogPrint(LOG_CRITICAL,
  245. "[NM] Unable to get local computername, status %1!u!\n",
  246. status
  247. );
  248. goto error_exit;
  249. }
  250. ClRtlLogPrint(LOG_NOISE,
  251. "[NM] Local node name = %1!ws!.\n",
  252. NmLocalNodeName
  253. );
  254. //
  255. // Open a control channel to the Cluster Network driver
  256. //
  257. NmClusnetHandle = ClusnetOpenControlChannel(0);
  258. if (NmClusnetHandle == NULL) {
  259. status = GetLastError();
  260. eventCode = NM_EVENT_CLUSNET_UNAVAILABLE;
  261. ClRtlLogPrint(LOG_CRITICAL,
  262. "[NM] Unable to open a handle to the Cluster Network driver, status %1!u!\n",
  263. status
  264. );
  265. goto error_exit;
  266. }
  267. //
  268. // Tell the Cluster Network driver to shutdown when our handle is closed
  269. // in case the Cluster Service crashes.
  270. //
  271. status = ClusnetEnableShutdownOnClose(NmClusnetHandle);
  272. if (status != ERROR_SUCCESS) {
  273. eventCode = NM_EVENT_CLUSNET_ENABLE_SHUTDOWN_FAILED;
  274. ClRtlLogPrint(LOG_CRITICAL,
  275. "[NM] Unable to register Cluster Network shutdown trigger, status %1!u!\n",
  276. status
  277. );
  278. goto error_exit;
  279. }
  280. //
  281. // Allocate the node ID array.
  282. //
  283. CL_ASSERT(NmpIdArray == NULL);
  284. NmpIdArray = LocalAlloc(
  285. LMEM_FIXED,
  286. (sizeof(PNM_NODE) * (NmMaxNodeId + 1))
  287. );
  288. if (NmpIdArray == NULL) {
  289. status = ERROR_NOT_ENOUGH_MEMORY;
  290. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  291. goto error_exit;
  292. }
  293. ZeroMemory(NmpIdArray, (sizeof(PNM_NODE) * (NmMaxNodeId + 1)));
  294. //
  295. // Create the node object type
  296. //
  297. ZeroMemory(&nodeTypeInitializer, sizeof(OM_OBJECT_TYPE_INITIALIZE));
  298. nodeTypeInitializer.ObjectSize = sizeof(NM_NODE);
  299. nodeTypeInitializer.Signature = NM_NODE_SIG;
  300. nodeTypeInitializer.Name = L"Node";
  301. nodeTypeInitializer.DeleteObjectMethod = NmpDestroyNodeObject;
  302. status = OmCreateType(ObjectTypeNode, &nodeTypeInitializer);
  303. if (status != ERROR_SUCCESS) {
  304. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  305. ClRtlLogPrint(LOG_CRITICAL,
  306. "[NM] Unable to create node object type, status %1!u!\n",
  307. status
  308. );
  309. goto error_exit;
  310. }
  311. //
  312. // Get the local node ID from the local registry.
  313. //
  314. status = RegCreateKeyW(
  315. HKEY_LOCAL_MACHINE,
  316. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  317. &serviceKey
  318. );
  319. if (status != ERROR_SUCCESS) {
  320. wsprintfW(&(errorString[0]), L"%u", status);
  321. CsLogEvent2(
  322. LOG_CRITICAL,
  323. CS_EVENT_REG_OPEN_FAILED,
  324. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  325. errorString
  326. );
  327. ClRtlLogPrint(LOG_CRITICAL,
  328. "[NM] Failed to open cluster service parameters key, status %1!u!\n",
  329. status
  330. );
  331. goto error_exit;
  332. }
  333. string = L"NodeId";
  334. status = RegQueryValueExW(
  335. serviceKey,
  336. string,
  337. 0,
  338. &valueType,
  339. (LPBYTE) &(NmLocalNodeIdString[0]),
  340. &nodeIdSize
  341. );
  342. RegCloseKey(serviceKey);
  343. if (status != ERROR_SUCCESS) {
  344. wsprintfW(&(errorString[0]), L"%u", status);
  345. CsLogEvent2(
  346. LOG_CRITICAL,
  347. CS_EVENT_REG_QUERY_FAILED,
  348. string,
  349. errorString
  350. );
  351. ClRtlLogPrint(LOG_CRITICAL,
  352. "[NM] Failed to read local node ID from registry, status %1!u!\n",
  353. status
  354. );
  355. goto error_exit;
  356. }
  357. if (valueType != REG_SZ) {
  358. status = ERROR_INVALID_PARAMETER;
  359. wsprintfW(&(errorString[0]), L"%u", status);
  360. CsLogEvent2(
  361. LOG_CRITICAL,
  362. CS_EVENT_REG_QUERY_FAILED,
  363. string,
  364. errorString
  365. );
  366. ClRtlLogPrint(LOG_CRITICAL,
  367. "[NM] Local Node ID registry value is not of type REG_SZ.\n"
  368. );
  369. goto error_exit;
  370. }
  371. ClRtlLogPrint(LOG_NOISE,
  372. "[NM] Local node ID = %1!ws!.\n",
  373. NmLocalNodeIdString
  374. );
  375. NmLocalNodeId = wcstoul(NmLocalNodeIdString, NULL, 10);
  376. //
  377. // Get information about the local node.
  378. //
  379. wcscpy(&(nodeInfo.NodeId[0]), NmLocalNodeIdString);
  380. status = NmpGetNodeDefinition(&nodeInfo);
  381. if (status != ERROR_SUCCESS) {
  382. goto error_exit;
  383. }
  384. //
  385. // Create the local node object. We must do this here because GUM
  386. // requires the local node object to initialize.
  387. //
  388. status = NmpCreateLocalNodeObject(&nodeInfo);
  389. ClNetFreeNodeInfo(&nodeInfo);
  390. if (status != ERROR_SUCCESS) {
  391. goto error_exit;
  392. }
  393. //
  394. // Initialize the network and interface object types
  395. //
  396. status = NmpInitializeNetworks();
  397. if (status != ERROR_SUCCESS) {
  398. goto error_exit;
  399. }
  400. status = NmpInitializeInterfaces();
  401. if (status != ERROR_SUCCESS) {
  402. goto error_exit;
  403. }
  404. //
  405. // Initialize net PnP handling
  406. //
  407. status = NmpInitializePnp();
  408. if (status != ERROR_SUCCESS) {
  409. goto error_exit;
  410. }
  411. //
  412. // init the advise sink that tells when a connection object has been
  413. // renamed
  414. //
  415. // Wrapping this call with watchdog timeout of 3 mins. 411333
  416. wTimer = ClRtlSetWatchdogTimer(180000, L"Calling Initialize Connectoid Advise Sink");
  417. status = NmpInitializeConnectoidAdviseSink();
  418. ClRtlCancelWatchdogTimer(wTimer);
  419. if (status != ERROR_SUCCESS) {
  420. goto error_exit;
  421. }
  422. //
  423. // Set the LSA options for this process.
  424. //
  425. // When authenticating, try cached credentials first.
  426. lsaProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
  427. // Check if a registry parameter commands us to disable the
  428. // try cache first option.
  429. clusParamKey = DmOpenKey(
  430. DmClusterParametersKey,
  431. CLUSREG_KEYNAME_PARAMETERS,
  432. KEY_READ
  433. );
  434. if (clusParamKey != NULL) {
  435. DWORD type = REG_DWORD;
  436. DWORD disabled = 0;
  437. DWORD len = sizeof(disabled);
  438. status = DmQueryValue(
  439. clusParamKey,
  440. CLUSREG_NAME_DISABLE_TRY_CACHE_FIRST,
  441. &type,
  442. (LPBYTE) &disabled,
  443. &len
  444. );
  445. if (status == ERROR_SUCCESS) {
  446. // The value was found. Make sure it is a DWORD.
  447. if (type == REG_DWORD) {
  448. // If disabled, turn off the cache first option.
  449. if (disabled != 0) {
  450. lsaProcessOptions &= ~MSV1_0_OPTION_TRY_CACHE_FIRST;
  451. ClRtlLogPrint(LOG_NOISE,
  452. "[NM] The LSA cache-first process option will "
  453. "not be enabled.\n"
  454. );
  455. }
  456. } else {
  457. // Warn in the cluster log that the type
  458. // is incorrect.
  459. ClRtlLogPrint(LOG_UNUSUAL,
  460. "[NM] Ignoring cluster parameter %1!ws! "
  461. "because it is not of type REG_DWORD (%2!u!).\n",
  462. CLUSREG_NAME_DISABLE_TRY_CACHE_FIRST, type
  463. );
  464. }
  465. }
  466. } else {
  467. status = GetLastError();
  468. ClRtlLogPrint(LOG_UNUSUAL,
  469. "[NM] Failed to open cluster parameters key, "
  470. "status %1!u!.\n",
  471. status
  472. );
  473. // Non-fatal error. Stick with default.
  474. }
  475. // Set password policy
  476. if ( CsRunningAsService) {
  477. // Set password policy to allow RPC authentication to ignore a WRONG_PASSWORD
  478. // message from a domain controller and try authentication against the current
  479. // in-memory credentials.
  480. //
  481. // The password change operation is only valid when running as a service.
  482. lsaProcessOptions |= MSV1_0_OPTION_ALLOW_OLD_PASSWORD;
  483. }
  484. // Call into LSA to set the options.
  485. if (lsaProcessOptions != 0) {
  486. status = NmpSetLsaProcessOptions(lsaProcessOptions);
  487. if (status != ERROR_SUCCESS) {
  488. if (!CsRunningAsService &&
  489. // Not a fatal error if running in debug mode and only trying
  490. // to set cache-first option.
  491. lsaProcessOptions == MSV1_0_OPTION_TRY_CACHE_FIRST) {
  492. ClRtlLogPrint(LOG_UNUSUAL,
  493. "[NM] Failed to enable LSA cache-first process "
  494. "option, status %1!u!.\n",
  495. status
  496. );
  497. status = ERROR_SUCCESS;
  498. } else {
  499. // Fatal error.
  500. ClRtlLogPrint(LOG_CRITICAL,
  501. "[NM] Failed to set LSA process options to %1!x!, "
  502. "status %2!u!.\n",
  503. lsaProcessOptions, status
  504. );
  505. goto error_exit;
  506. }
  507. }
  508. }
  509. //
  510. // Initialize NmCryptServiceProvider
  511. //
  512. status = NmpCreateCSPHandle(&NmCryptServiceProvider);
  513. if (status != ERROR_SUCCESS) {
  514. ClRtlLogPrint(LOG_CRITICAL,
  515. "[NM] Failed to initialize NmCryptServiceProvider, "
  516. "status %1!u!.\n",
  517. status
  518. );
  519. goto error_exit;
  520. }
  521. ClRtlLogPrint(LOG_NOISE,"[NM] Initialization complete.\n");
  522. return(ERROR_SUCCESS);
  523. error_exit:
  524. if (clusParamKey != NULL) {
  525. DmCloseKey(clusParamKey);
  526. clusParamKey = NULL;
  527. }
  528. if (eventCode != 0) {
  529. wsprintfW(&(errorString[0]), L"%u", status);
  530. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  531. }
  532. wsprintfW( &(errorString[0]), L"%u", status );
  533. CsLogEvent1(LOG_CRITICAL, NM_INIT_FAILED, errorString);
  534. ClRtlLogPrint(LOG_CRITICAL,"[NM] Initialization failed %1!d!\n",status);
  535. NmShutdown();
  536. return(status);
  537. } // NmInitialize
  538. VOID
  539. NmShutdown(
  540. VOID
  541. )
  542. /*++
  543. Routine Description:
  544. Terminates all processing - shuts down all sources of work for
  545. worker threads.
  546. Arguments:
  547. Return Value:
  548. --*/
  549. {
  550. DWORD status;
  551. if (NmpState == NmStateOffline) {
  552. return;
  553. }
  554. NmCloseConnectoidAdviseSink();
  555. NmpShutdownPnp();
  556. NmpAcquireLock();
  557. ClRtlLogPrint(LOG_NOISE,"[NM] Shutdown starting...\n");
  558. //
  559. // Release NmCryptServiceProvider.
  560. //
  561. if(NmCryptServiceProvider)
  562. {
  563. if (!CryptReleaseContext(NmCryptServiceProvider,0))
  564. {
  565. ClRtlLogPrint(
  566. LOG_UNUSUAL,
  567. "NM] Failed to release "
  568. "crypto provider, status %1!u!\n",
  569. GetLastError()
  570. );
  571. }
  572. }
  573. NmpState = NmStateOfflinePending;
  574. if (NmpActiveThreadCount > 0) {
  575. ClRtlLogPrint(LOG_NOISE,
  576. "[NM] Waiting for %1!u! active threads to terminate...\n",
  577. NmpActiveThreadCount
  578. );
  579. NmpReleaseLock();
  580. status = WaitForSingleObject(NmpShutdownEvent, INFINITE);
  581. CL_ASSERT(status == WAIT_OBJECT_0);
  582. ClRtlLogPrint(LOG_NOISE,
  583. "[NM] All active threads have completed. Continuing shutdown...\n"
  584. );
  585. }
  586. else {
  587. NmpReleaseLock();
  588. }
  589. NmLeaveCluster();
  590. NmpCleanupPnp();
  591. if (NmLocalNode != NULL) {
  592. NmpDeleteNodeObject(NmLocalNode, FALSE);
  593. NmLocalNode = NULL;
  594. }
  595. if (NmpIdArray != NULL) {
  596. LocalFree(NmpIdArray); NmpIdArray = NULL;
  597. }
  598. NmpFreeClusterKey();
  599. if (NmpClusterInstanceId != NULL) {
  600. MIDL_user_free(NmpClusterInstanceId);
  601. NmpClusterInstanceId = NULL;
  602. }
  603. if (NmClusnetHandle != NULL) {
  604. ClusnetCloseControlChannel(NmClusnetHandle);
  605. NmClusnetHandle = NULL;
  606. }
  607. CloseHandle(NmpShutdownEvent); NmpShutdownEvent = NULL;
  608. WSACleanup();
  609. //
  610. // As long as the GUM and Clusapi RPC interfaces cannot be
  611. // shutdown, it is not safe to delete this critical section.
  612. //
  613. // DeleteCriticalSection(&NmpLock);
  614. NmpState = NmStateOffline;
  615. ClRtlLogPrint(LOG_NOISE,"[NM] Shutdown complete.\n");
  616. return;
  617. } // NmShutdown
  618. VOID
  619. NmLeaveCluster(
  620. VOID
  621. )
  622. /*++
  623. Routine Description:
  624. Arguments:
  625. Return Value:
  626. --*/
  627. {
  628. DWORD status;
  629. if (NmLocalNode != NULL) {
  630. if ( (NmLocalNode->State == ClusterNodeUp) ||
  631. (NmLocalNode->State == ClusterNodePaused) ||
  632. (NmLocalNode->State == ClusterNodeJoining)
  633. )
  634. {
  635. //
  636. // Leave the cluster.
  637. //
  638. ClRtlLogPrint(LOG_NOISE,"[NM] Leaving cluster.\n");
  639. MMLeave();
  640. #ifdef MM_IN_CLUSNET
  641. status = ClusnetLeaveCluster(NmClusnetHandle);
  642. CL_ASSERT(status == ERROR_SUCCESS);
  643. #endif // MM_IN_CLUSNET
  644. }
  645. }
  646. NmpStopNetworkTimerThread();
  647. NmpMembershipShutdown();
  648. NmpCleanupInterfaces();
  649. NmpCleanupNetworks();
  650. NmpCleanupNodes();
  651. //
  652. // Shutdown the Cluster Network driver.
  653. //
  654. if (NmClusnetHandle != NULL) {
  655. status = ClusnetShutdown(NmClusnetHandle);
  656. if (status != ERROR_SUCCESS) {
  657. ClRtlLogPrint(LOG_UNUSUAL,
  658. "[NM] Shutdown of the Cluster Network driver failed, status %1!u!\n",
  659. status
  660. );
  661. }
  662. }
  663. if (NmpClusnetEndpoint != NULL) {
  664. MIDL_user_free(NmpClusnetEndpoint);
  665. NmpClusnetEndpoint = NULL;
  666. }
  667. return;
  668. } // NmLeaveCluster
  669. DWORD
  670. NmpCreateClusterObjects(
  671. IN RPC_BINDING_HANDLE JoinSponsorBinding
  672. )
  673. /*++
  674. Routine Description:
  675. Creates objects to represent the cluster's nodes, networks, and
  676. interfaces.
  677. Arguments:
  678. JoinSponsorBinding - A pointer to an RPC binding handle for the sponsor
  679. node if this node is joining a cluster. NULL if
  680. this node is forming a cluster.
  681. Return Value:
  682. ERROR_SUCCESS if the routine is successful.
  683. A Win32 error code otherwise.
  684. Notes:
  685. This routine MUST NOT be called with the NM lock held.
  686. --*/
  687. {
  688. DWORD status;
  689. PNM_NODE_ENUM2 nodeEnum = NULL;
  690. PNM_NETWORK_ENUM networkEnum = NULL;
  691. PNM_INTERFACE_ENUM2 interfaceEnum = NULL;
  692. PNM_NODE node = NULL;
  693. DWORD matchedNetworkCount = 0;
  694. DWORD newNetworkCount = 0;
  695. DWORD InitRetry = 2;
  696. WCHAR errorString[12];
  697. DWORD eventCode = 0;
  698. BOOL renameConnectoids;
  699. do {
  700. //
  701. // Initialize the Cluster Network driver. This will clean up
  702. // any old state that was left around from the last run of the
  703. // Cluster Service. Note that the local node object is registered in
  704. // this call.
  705. //
  706. status = ClusnetInitialize(
  707. NmClusnetHandle,
  708. NmLocalNodeId,
  709. NmMaxNodes,
  710. NULL,
  711. NULL,
  712. NULL,
  713. NULL,
  714. NULL,
  715. NULL
  716. );
  717. if (status == ERROR_SUCCESS) {
  718. break;
  719. } else {
  720. ClRtlLogPrint(LOG_UNUSUAL,
  721. "[NM] Shutting down Cluster Network driver before retrying Initialization, status %1!u!\n",
  722. status);
  723. ClusnetShutdown( NmClusnetHandle );
  724. }
  725. } while ( InitRetry-- );
  726. if ( status != ERROR_SUCCESS ) {
  727. eventCode = NM_EVENT_CLUSNET_INITIALIZE_FAILED;
  728. ClRtlLogPrint(LOG_CRITICAL,
  729. "[NM] Initialization of the Cluster Network driver failed, status %1!u!\n",
  730. status
  731. );
  732. goto error_exit;
  733. }
  734. //
  735. // Tell the Cluster Network driver to reserve the Cluster Network
  736. // endpoint on this node.
  737. //
  738. status = ClusnetReserveEndpoint(
  739. NmClusnetHandle,
  740. NmpClusnetEndpoint
  741. );
  742. if (status != ERROR_SUCCESS) {
  743. ClRtlLogPrint(LOG_CRITICAL,
  744. "[NM] Unable to reserve Clusnet Network endpoint %1!ws!, "
  745. "status %2!u!\n", NmpClusnetEndpoint, status
  746. );
  747. wsprintfW(&(errorString[0]), L"%u", status);
  748. CsLogEvent2(
  749. LOG_CRITICAL,
  750. NM_EVENT_CLUSNET_RESERVE_ENDPOINT_FAILED,
  751. NmpClusnetEndpoint,
  752. errorString
  753. );
  754. goto error_exit;
  755. }
  756. //
  757. // Obtain the node portion of the cluster database.
  758. //
  759. ClRtlLogPrint(LOG_NOISE,
  760. "[NM] Synchronizing node information.\n"
  761. );
  762. if (JoinSponsorBinding == NULL) {
  763. status = NmpEnumNodeDefinitions(&nodeEnum);
  764. }
  765. else {
  766. status = NmRpcEnumNodeDefinitions2(
  767. JoinSponsorBinding,
  768. NmpJoinSequence,
  769. NmLocalNodeIdString,
  770. &nodeEnum
  771. );
  772. }
  773. if (status != ERROR_SUCCESS) {
  774. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  775. ClRtlLogPrint(LOG_CRITICAL,
  776. "[NM] Unable to synchronize node information, status %1!u!.\n",
  777. status
  778. );
  779. goto error_exit;
  780. }
  781. //
  782. // Create the node objects.
  783. //
  784. ClRtlLogPrint(LOG_NOISE,
  785. "[NM] Creating node objects.\n"
  786. );
  787. status = NmpCreateNodeObjects(nodeEnum);
  788. if (status != ERROR_SUCCESS) {
  789. goto error_exit;
  790. }
  791. //
  792. // Obtain the networks portion of the cluster database.
  793. //
  794. ClRtlLogPrint(LOG_NOISE,
  795. "[NM] Synchronizing network information.\n"
  796. );
  797. if (JoinSponsorBinding == NULL) {
  798. status = NmpEnumNetworkDefinitions(&networkEnum);
  799. }
  800. else {
  801. status = NmRpcEnumNetworkDefinitions(
  802. JoinSponsorBinding,
  803. NmpJoinSequence,
  804. NmLocalNodeIdString,
  805. &networkEnum
  806. );
  807. }
  808. if (status != ERROR_SUCCESS) {
  809. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  810. ClRtlLogPrint(LOG_CRITICAL,
  811. "[NM] Unable to synchronize network information, status %1!u!.\n",
  812. status
  813. );
  814. goto error_exit;
  815. }
  816. //
  817. // Obtain the interfaces portion of the cluster database.
  818. //
  819. ClRtlLogPrint(LOG_NOISE,
  820. "[NM] Synchronizing interface information.\n"
  821. );
  822. if (JoinSponsorBinding == NULL) {
  823. status = NmpEnumInterfaceDefinitions(&interfaceEnum);
  824. }
  825. else {
  826. status = NmRpcEnumInterfaceDefinitions2(
  827. JoinSponsorBinding,
  828. NmpJoinSequence,
  829. NmLocalNodeIdString,
  830. &interfaceEnum
  831. );
  832. }
  833. if (status != ERROR_SUCCESS) {
  834. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  835. ClRtlLogPrint(LOG_CRITICAL,
  836. "[NM] Unable to synchronize interface information, status %1!u!.\n",
  837. status
  838. );
  839. goto error_exit;
  840. }
  841. if ( CsUpgrade ) {
  842. //
  843. // If this is an upgrade from NT4 to Whistler, then fix up the
  844. // connectoid names so they align with the cluster network
  845. // names.
  846. //
  847. // REMOVE THIS PORTION AFTER WHISTLER HAS SHIPPED.
  848. //
  849. if ( CLUSTER_GET_MAJOR_VERSION( NmLocalNode->HighestVersion ) <= NT4SP4_MAJOR_VERSION ) {
  850. renameConnectoids = TRUE;
  851. } else {
  852. //
  853. // upgrade from W2K to Whistler. Nothing should have changed but
  854. // if it did, connectoids should have precedence
  855. //
  856. renameConnectoids = FALSE;
  857. }
  858. } else {
  859. //
  860. // THIS SECTION MUST ALWAYS BE HERE
  861. //
  862. // if forming, cluster network objects are renamed to its
  863. // corresponding connectoid name. During a join, the opposite is true.
  864. //
  865. if ( JoinSponsorBinding ) {
  866. renameConnectoids = TRUE;
  867. } else {
  868. renameConnectoids = FALSE;
  869. }
  870. }
  871. //
  872. // Post a PnP notification ioctl. If we receive a PnP notification
  873. // before we finish initializing, we must restart the process.
  874. //
  875. NmpWatchForPnpEvents();
  876. if (status != ERROR_SUCCESS) {
  877. goto error_exit;
  878. }
  879. //
  880. // Run the network configuration engine. This will update the
  881. // cluster database.
  882. //
  883. status = NmpConfigureNetworks(
  884. JoinSponsorBinding,
  885. NmLocalNodeIdString,
  886. NmLocalNodeName,
  887. &networkEnum,
  888. &interfaceEnum,
  889. NmpClusnetEndpoint,
  890. &matchedNetworkCount,
  891. &newNetworkCount,
  892. renameConnectoids
  893. );
  894. if (status != ERROR_SUCCESS) {
  895. ClRtlLogPrint(LOG_CRITICAL,
  896. "[NM] Failed to configure networks & interfaces, status %1!u!.\n",
  897. status
  898. );
  899. goto error_exit;
  900. }
  901. ClRtlLogPrint(LOG_NOISE,
  902. "[NM] Matched %1!u! networks, created %2!u! new networks.\n",
  903. matchedNetworkCount,
  904. newNetworkCount
  905. );
  906. //
  907. // Get the updated network information from the database.
  908. //
  909. ClRtlLogPrint(LOG_NOISE,
  910. "[NM] Resynchronizing network information.\n"
  911. );
  912. if (JoinSponsorBinding == NULL) {
  913. status = NmpEnumNetworkDefinitions(&networkEnum);
  914. }
  915. else {
  916. status = NmRpcEnumNetworkDefinitions(
  917. JoinSponsorBinding,
  918. NmpJoinSequence,
  919. NmLocalNodeIdString,
  920. &networkEnum
  921. );
  922. }
  923. if (status != ERROR_SUCCESS) {
  924. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  925. ClRtlLogPrint(LOG_CRITICAL,
  926. "[NM] Unable to resynchronize network information, "
  927. "status %1!u!.\n",
  928. status
  929. );
  930. goto error_exit;
  931. }
  932. //
  933. // Get the updated interface information from the database.
  934. //
  935. ClRtlLogPrint(LOG_NOISE,
  936. "[NM] Resynchronizing interface information.\n"
  937. );
  938. if (JoinSponsorBinding == NULL) {
  939. status = NmpEnumInterfaceDefinitions(&interfaceEnum);
  940. }
  941. else {
  942. status = NmRpcEnumInterfaceDefinitions2(
  943. JoinSponsorBinding,
  944. NmpJoinSequence,
  945. NmLocalNodeIdString,
  946. &interfaceEnum
  947. );
  948. }
  949. if (status != ERROR_SUCCESS) {
  950. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  951. ClRtlLogPrint(LOG_CRITICAL,
  952. "[NM] Unable to resynchronize interface information, status %1!u!.\n",
  953. status
  954. );
  955. goto error_exit;
  956. }
  957. //
  958. // Create the network objects.
  959. //
  960. ClRtlLogPrint(LOG_NOISE,
  961. "[NM] Creating network objects.\n"
  962. );
  963. status = NmpCreateNetworkObjects(networkEnum);
  964. if (status != ERROR_SUCCESS) {
  965. ClRtlLogPrint(LOG_CRITICAL,
  966. "[NM] Failed to create network objects, status %1!u!.\n",
  967. status
  968. );
  969. goto error_exit;
  970. }
  971. //
  972. // Fixup the priorities of the internal networks if we are forming
  973. // a cluster.
  974. //
  975. if (JoinSponsorBinding == NULL) {
  976. DWORD networkCount;
  977. PNM_NETWORK * networkList;
  978. status = NmpEnumInternalNetworks(&networkCount, &networkList);
  979. if ((status == ERROR_SUCCESS) && (networkCount > 0)) {
  980. DWORD i;
  981. HLOCALXSACTION xaction;
  982. //
  983. // Begin a transaction - this must not be done while holding
  984. // the NM lock.
  985. //
  986. xaction = DmBeginLocalUpdate();
  987. if (xaction == NULL) {
  988. status = GetLastError();
  989. ClRtlLogPrint(LOG_CRITICAL,
  990. "[NM] Failed to start a transaction, status %1!u!\n",
  991. status
  992. );
  993. goto error_exit;
  994. }
  995. status = NmpSetNetworkPriorityOrder(
  996. networkCount,
  997. networkList,
  998. xaction
  999. );
  1000. if (status == ERROR_SUCCESS) {
  1001. DmCommitLocalUpdate(xaction);
  1002. }
  1003. else {
  1004. DmAbortLocalUpdate(xaction);
  1005. goto error_exit;
  1006. }
  1007. for (i=0; i<networkCount; i++) {
  1008. if (networkList[i] != NULL) {
  1009. OmDereferenceObject(networkList[i]);
  1010. }
  1011. }
  1012. LocalFree(networkList);
  1013. }
  1014. }
  1015. //
  1016. // Create the interface objects.
  1017. //
  1018. ClRtlLogPrint(LOG_NOISE,
  1019. "[NM] Creating interface objects.\n"
  1020. );
  1021. status = NmpCreateInterfaceObjects(interfaceEnum);
  1022. if (status != ERROR_SUCCESS) {
  1023. ClRtlLogPrint(LOG_CRITICAL,
  1024. "[NM] Failed to create interface objects, status %1!u!.\n",
  1025. status
  1026. );
  1027. goto error_exit;
  1028. }
  1029. if (JoinSponsorBinding != NULL) {
  1030. //
  1031. // The node must have connectivity to all active cluster nodes
  1032. // in order to join a cluster.
  1033. //
  1034. PNM_NODE unreachableNode;
  1035. if (!NmpVerifyJoinerConnectivity(NmLocalNode, &unreachableNode)) {
  1036. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  1037. CsLogEvent1(
  1038. LOG_CRITICAL,
  1039. NM_EVENT_NODE_UNREACHABLE,
  1040. OmObjectName(unreachableNode)
  1041. );
  1042. ClRtlLogPrint(LOG_CRITICAL,
  1043. "[NM] Joining node cannot communicate with all other "
  1044. "active nodes.\n"
  1045. );
  1046. goto error_exit;
  1047. }
  1048. }
  1049. status = NmpMembershipInit();
  1050. if (status != ERROR_SUCCESS) {
  1051. goto error_exit;
  1052. }
  1053. status = NmpStartNetworkTimerThread();
  1054. if (status != ERROR_SUCCESS) {
  1055. goto error_exit;
  1056. }
  1057. error_exit:
  1058. if (eventCode != 0) {
  1059. wsprintfW(&(errorString[0]), L"%u", status);
  1060. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  1061. }
  1062. if (nodeEnum != NULL) {
  1063. ClNetFreeNodeEnum(nodeEnum);
  1064. }
  1065. if (networkEnum != NULL) {
  1066. ClNetFreeNetworkEnum(networkEnum);
  1067. }
  1068. if (interfaceEnum != NULL) {
  1069. ClNetFreeInterfaceEnum(interfaceEnum);
  1070. }
  1071. return(status);
  1072. } // NmpCreateClusterObjects
  1073. //
  1074. // Routines common to joining and forming.
  1075. //
  1076. DWORD
  1077. NmpCreateClusterInstanceId(
  1078. VOID
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. Checks the cluster database for the cluster instance id. Creates
  1083. if not present.
  1084. --*/
  1085. {
  1086. DWORD status;
  1087. LPWSTR clusterInstanceId = NULL;
  1088. DWORD clusterInstanceIdBufSize = 0;
  1089. DWORD clusterInstanceIdSize = 0;
  1090. BOOLEAN found = FALSE;
  1091. UUID guid;
  1092. do {
  1093. status = NmpQueryString(
  1094. DmClusterParametersKey,
  1095. L"ClusterInstanceID",
  1096. REG_SZ,
  1097. &clusterInstanceId,
  1098. &clusterInstanceIdBufSize,
  1099. &clusterInstanceIdSize
  1100. );
  1101. if (status == ERROR_SUCCESS) {
  1102. found = TRUE;
  1103. } else {
  1104. ClRtlLogPrint(LOG_UNUSUAL,
  1105. "[NMJOIN] Cluster Instance ID not found in "
  1106. "cluster database, status %1!u!.\n",
  1107. status
  1108. );
  1109. status = UuidCreate(&guid);
  1110. if (status == RPC_S_OK) {
  1111. status = UuidToString(&guid, &clusterInstanceId);
  1112. if (status == RPC_S_OK) {
  1113. status = DmSetValue(
  1114. DmClusterParametersKey,
  1115. L"ClusterInstanceID",
  1116. REG_SZ,
  1117. (PBYTE) clusterInstanceId,
  1118. NM_WCSLEN(clusterInstanceId)
  1119. );
  1120. if (status != ERROR_SUCCESS) {
  1121. ClRtlLogPrint(LOG_UNUSUAL,
  1122. "[NMJOIN] Failed to store Cluster Instance ID "
  1123. "in cluster database, status %1!u!.\n",
  1124. status
  1125. );
  1126. }
  1127. if (clusterInstanceId != NULL) {
  1128. RpcStringFree(&clusterInstanceId);
  1129. clusterInstanceId = NULL;
  1130. }
  1131. } else {
  1132. ClRtlLogPrint(LOG_UNUSUAL,
  1133. "[NMJOIN] Failed to convert Cluster Instance ID "
  1134. "GUID into string, status %1!u!.\n",
  1135. status
  1136. );
  1137. }
  1138. } else {
  1139. ClRtlLogPrint(LOG_UNUSUAL,
  1140. "[NMJOIN] Failed to create Cluster Instance ID GUID, "
  1141. "status %1!u!.\n",
  1142. status
  1143. );
  1144. }
  1145. }
  1146. } while ( !found && (status == ERROR_SUCCESS) );
  1147. if (status == ERROR_SUCCESS) {
  1148. CL_ASSERT(clusterInstanceId != NULL);
  1149. NmpAcquireLock();
  1150. if (NmpClusterInstanceId == NULL) {
  1151. NmpClusterInstanceId = clusterInstanceId;
  1152. clusterInstanceId = NULL;
  1153. }
  1154. NmpReleaseLock();
  1155. }
  1156. if (clusterInstanceId != NULL) {
  1157. midl_user_free(clusterInstanceId);
  1158. clusterInstanceId = NULL;
  1159. }
  1160. return(status);
  1161. } // NmpCreateClusterInstanceId
  1162. //
  1163. // Routines for forming a new cluster.
  1164. //
  1165. DWORD
  1166. NmFormNewCluster(
  1167. VOID
  1168. )
  1169. {
  1170. DWORD status;
  1171. DWORD isPaused = FALSE;
  1172. DWORD pausedDefault = FALSE;
  1173. HDMKEY nodeKey;
  1174. DWORD valueLength, valueSize;
  1175. WCHAR errorString[12], errorString2[12];
  1176. DWORD eventCode = 0;
  1177. PLIST_ENTRY entry;
  1178. PNM_NETWORK network;
  1179. ClRtlLogPrint(LOG_NOISE,
  1180. "[NM] Beginning cluster form process.\n"
  1181. );
  1182. //
  1183. // Since this node is forming the cluster, it is the leader.
  1184. //
  1185. NmpLeaderNodeId = NmLocalNodeId;
  1186. //
  1187. // Read the clusnet endpoint override value from the registry, if it
  1188. // exists.
  1189. //
  1190. if (NmpClusnetEndpoint != NULL) {
  1191. MIDL_user_free(NmpClusnetEndpoint);
  1192. NmpClusnetEndpoint = NULL;
  1193. }
  1194. valueLength = 0;
  1195. status = NmpQueryString(
  1196. DmClusterParametersKey,
  1197. L"ClusnetEndpoint",
  1198. REG_SZ,
  1199. &NmpClusnetEndpoint,
  1200. &valueLength,
  1201. &valueSize
  1202. );
  1203. if (status == ERROR_SUCCESS) {
  1204. USHORT endpoint;
  1205. //
  1206. // Validate the value
  1207. //
  1208. status = ClRtlTcpipStringToEndpoint(
  1209. NmpClusnetEndpoint,
  1210. &endpoint
  1211. );
  1212. if (status != ERROR_SUCCESS) {
  1213. CsLogEvent2(
  1214. LOG_UNUSUAL,
  1215. NM_EVENT_INVALID_CLUSNET_ENDPOINT,
  1216. NmpClusnetEndpoint,
  1217. CLUSNET_DEFAULT_ENDPOINT_STRING
  1218. );
  1219. ClRtlLogPrint(
  1220. LOG_CRITICAL,
  1221. "[NM] '%1!ws!' is not valid endpoint value. Using default value %2!ws!.\n",
  1222. NmpClusnetEndpoint,
  1223. CLUSNET_DEFAULT_ENDPOINT_STRING
  1224. );
  1225. MIDL_user_free(NmpClusnetEndpoint);
  1226. NmpClusnetEndpoint = NULL;
  1227. }
  1228. }
  1229. if (status != ERROR_SUCCESS) {
  1230. NmpClusnetEndpoint = MIDL_user_allocate(
  1231. NM_WCSLEN(CLUSNET_DEFAULT_ENDPOINT_STRING)
  1232. );
  1233. if (NmpClusnetEndpoint == NULL) {
  1234. status = ERROR_NOT_ENOUGH_MEMORY;
  1235. wsprintfW(&(errorString[0]), L"%u", status);
  1236. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  1237. return(status);
  1238. }
  1239. lstrcpyW(NmpClusnetEndpoint, CLUSNET_DEFAULT_ENDPOINT_STRING);
  1240. }
  1241. //
  1242. // Create the node, network, and interface objects
  1243. //
  1244. status = NmpCreateClusterObjects(NULL);
  1245. if (status != ERROR_SUCCESS) {
  1246. goto error_exit;
  1247. }
  1248. //
  1249. // Perform version checking - check if we are compatible with the rest of the cluster
  1250. //
  1251. status = NmpIsNodeVersionAllowed(NmLocalNodeId, CsMyHighestVersion,
  1252. CsMyLowestVersion, FALSE);
  1253. if (status != ERROR_SUCCESS)
  1254. {
  1255. ClRtlLogPrint(LOG_CRITICAL,
  1256. "[NM] Version of Node %1!ws! is no longer compatible with other members of the cluster.\n",
  1257. NmLocalNodeIdString);
  1258. goto error_exit;
  1259. }
  1260. //If the forming node's version has changed, fix it up
  1261. status = NmpValidateNodeVersion(
  1262. NmLocalNodeIdString,
  1263. CsMyHighestVersion,
  1264. CsMyLowestVersion
  1265. );
  1266. if (status == ERROR_REVISION_MISMATCH)
  1267. {
  1268. //there was a version change, try and fix it up
  1269. status = NmpFormFixupNodeVersion(
  1270. NmLocalNodeIdString,
  1271. CsMyHighestVersion,
  1272. CsMyLowestVersion
  1273. );
  1274. NmLocalNodeVersionChanged = TRUE;
  1275. }
  1276. if (status != ERROR_SUCCESS)
  1277. {
  1278. goto error_exit;
  1279. }
  1280. //
  1281. //at this point we ready to calculate the cluster version
  1282. //all the node versions are in the registry, the fixups have
  1283. //been made if neccessary
  1284. //
  1285. NmpResetClusterVersion(FALSE);
  1286. NmpMulticastInitialize();
  1287. ClRtlLogPrint(LOG_NOISE,
  1288. "[NM] Forming cluster membership.\n"
  1289. );
  1290. status = MMJoin(
  1291. NmLocalNodeId,
  1292. NM_CLOCK_PERIOD,
  1293. NM_SEND_HB_RATE,
  1294. NM_RECV_HB_RATE,
  1295. NM_MM_JOIN_TIMEOUT
  1296. );
  1297. if (status != MM_OK) {
  1298. status = MMMapStatusToDosError(status);
  1299. eventCode = NM_EVENT_MM_FORM_FAILED;
  1300. ClRtlLogPrint(
  1301. LOG_CRITICAL,
  1302. "[NM] Membership form failed, status %1!u!. Unable to form a cluster.\n",
  1303. status
  1304. );
  1305. goto error_exit;
  1306. }
  1307. #ifdef MM_IN_CLUSNET
  1308. status = ClusnetFormCluster(
  1309. NmClusnetHandle,
  1310. NM_CLOCK_PERIOD,
  1311. NM_SEND_HB_RATE,
  1312. NM_RECV_HB_RATE
  1313. );
  1314. if (status != ERROR_SUCCESS) {
  1315. ClRtlLogPrint(
  1316. LOG_CRITICAL,
  1317. "[NM] Failed to form a cluster, status %1!u!.\n",
  1318. status
  1319. );
  1320. goto error_exit;
  1321. }
  1322. #endif // MM_IN_CLUSNET
  1323. //
  1324. // Check to see if we should come up in the paused state.
  1325. //
  1326. nodeKey = DmOpenKey(
  1327. DmNodesKey,
  1328. NmLocalNodeIdString,
  1329. KEY_READ
  1330. );
  1331. if (nodeKey != NULL) {
  1332. status = DmQueryDword(
  1333. nodeKey,
  1334. CLUSREG_NAME_NODE_PAUSED,
  1335. &isPaused,
  1336. &pausedDefault
  1337. );
  1338. if (status != ERROR_SUCCESS) {
  1339. ClRtlLogPrint(
  1340. LOG_UNUSUAL,
  1341. "[NM] Unable to query Paused value for local node, status %1!u!.\n",
  1342. status
  1343. );
  1344. }
  1345. DmCloseKey(nodeKey);
  1346. }
  1347. else {
  1348. ClRtlLogPrint(
  1349. LOG_UNUSUAL,
  1350. "[NM] Unable to open database key to local node, status %1!u!. Unable to determine Pause state.\n",
  1351. status
  1352. );
  1353. }
  1354. NmpAcquireLock();
  1355. if (isPaused) {
  1356. NmLocalNode->State = ClusterNodePaused;
  1357. } else {
  1358. NmLocalNode->State = ClusterNodeUp;
  1359. }
  1360. NmLocalNode->ExtendedState = ClusterNodeJoining;
  1361. NmpState = NmStateOnline;
  1362. NmpReleaseLock();
  1363. //
  1364. // If the cluster instance ID does not exist, create it now. The cluster
  1365. // instance ID should be in the database unless this is the first uplevel
  1366. // node.
  1367. //
  1368. NmpCreateClusterInstanceId();
  1369. //
  1370. // Derive the cluster key.
  1371. //
  1372. status = NmpRederiveClusterKey();
  1373. if (status != ERROR_SUCCESS) {
  1374. ClRtlLogPrint(LOG_CRITICAL,
  1375. "[NM] Failed to derive cluster key, status %1!u!. "
  1376. "Aborting ...\n",
  1377. status
  1378. );
  1379. goto error_exit;
  1380. }
  1381. //
  1382. // Enable communication for the local node.
  1383. //
  1384. status = ClusnetOnlineNodeComm(NmClusnetHandle, NmLocalNodeId);
  1385. if (status != ERROR_SUCCESS) {
  1386. wsprintfW(&(errorString[0]), L"%u", NmLocalNodeId);
  1387. wsprintfW(&(errorString2[0]), L"%u", status);
  1388. CsLogEvent2(
  1389. LOG_CRITICAL,
  1390. NM_EVENT_CLUSNET_ONLINE_COMM_FAILED,
  1391. errorString,
  1392. errorString2
  1393. );
  1394. ClRtlLogPrint(LOG_CRITICAL,
  1395. "[NM] Failed to enable communication for local node, status %1!u!\n",
  1396. status
  1397. );
  1398. goto error_exit;
  1399. }
  1400. GumReceiveUpdates(FALSE,
  1401. GumUpdateMembership,
  1402. NmpGumUpdateHandler,
  1403. NULL,
  1404. sizeof(NmGumDispatchTable)/sizeof(GUM_DISPATCH_ENTRY),
  1405. NmGumDispatchTable,
  1406. NULL
  1407. );
  1408. // DavidDio 8/16/2001
  1409. // Bug 456951: There is a race condition between the network and
  1410. // interface state update and setting the NM state to online. If the
  1411. // state is online but no GUM handler is registered, the update will
  1412. // not be invoked. Hence, use the following flag to indicate that
  1413. // a handler is ready.
  1414. NmpGumUpdateHandlerRegistered = TRUE;
  1415. //
  1416. // Enable network PnP event handling.
  1417. //
  1418. // If a PnP event occured during the form process, an error code will
  1419. // be returned, which will abort startup of the service.
  1420. //
  1421. status = NmpEnablePnpEvents();
  1422. if (status != ERROR_SUCCESS) {
  1423. ClRtlLogPrint(LOG_UNUSUAL,
  1424. "[NM] A network PnP event occurred during form - abort.\n");
  1425. goto error_exit;
  1426. }
  1427. //
  1428. // Check if we formed without any viable networks. The form is still
  1429. // allowed, but we record an entry in the system event log.
  1430. //
  1431. if (!NmpCheckForNetwork()) {
  1432. ClRtlLogPrint(LOG_UNUSUAL,
  1433. "[NM] Formed cluster with no viable networks.\n"
  1434. );
  1435. CsLogEvent(LOG_UNUSUAL, NM_EVENT_FORM_WITH_NO_NETWORKS);
  1436. }
  1437. //
  1438. // Force a reconfiguration of multicast parameters and plumb
  1439. // the results in clusnet.
  1440. //
  1441. NmpAcquireLock();
  1442. status = NmpStartMulticast(NULL, NmStartMulticastForm);
  1443. if (status != ERROR_SUCCESS) {
  1444. ClRtlLogPrint(LOG_UNUSUAL,
  1445. "[NM] Failed to start multicast "
  1446. "on cluster networks, status %1!u!.\n",
  1447. status
  1448. );
  1449. //
  1450. // Not a de facto fatal error.
  1451. //
  1452. status = ERROR_SUCCESS;
  1453. }
  1454. NmpReleaseLock();
  1455. error_exit:
  1456. if (eventCode != 0) {
  1457. wsprintfW(&(errorString[0]), L"%u", status);
  1458. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  1459. }
  1460. return(status);
  1461. } // NmFormNewCluster
  1462. //
  1463. //
  1464. // Client-side routines for joining a cluster.
  1465. //
  1466. //
  1467. DWORD
  1468. NmJoinCluster(
  1469. IN RPC_BINDING_HANDLE SponsorBinding
  1470. )
  1471. {
  1472. DWORD status;
  1473. DWORD sponsorNodeId;
  1474. PNM_INTERFACE netInterface;
  1475. PNM_NETWORK network;
  1476. PNM_NODE node;
  1477. PLIST_ENTRY nodeEntry, ifEntry;
  1478. WCHAR errorString[12], errorString2[12];
  1479. DWORD eventCode = 0;
  1480. DWORD versionFlags = 0;
  1481. extern BOOLEAN bFormCluster;
  1482. DWORD retry;
  1483. BOOLEAN joinBegin3 = TRUE;
  1484. LPWSTR clusterInstanceId = NULL;
  1485. ClRtlLogPrint(LOG_NOISE,
  1486. "[NMJOIN] Beginning cluster join process.\n"
  1487. );
  1488. // GN: If a node tries to restart immediately after a clean shutdown,
  1489. // NmRpcJoinBegin2 can fail with ERROR_CLUSTER_NODE_UP. Since the regroup
  1490. // incident caused by this node might not be finished.
  1491. //
  1492. // If we are getting error CLUSTER_NODE_UP, we will keep retrying for
  1493. // 12 seconds, hoping that regroup will finish.
  1494. retry = 120 / 3; // We sleep for 3 seconds. Need to wait 2 minutes //
  1495. for (;;) {
  1496. //
  1497. // Get the join sequence number so we can tell if the cluster
  1498. // configuration changes during the join process. We overload the
  1499. // use of the NmpJoinSequence variable since it isn't used in the
  1500. // sponsor capacity until the node joins.
  1501. //
  1502. //
  1503. // Try NmRpcJoinBegin3. If it fails with an RPC procnum out of
  1504. // range error, the sponsor is a downlevel node. Revert to
  1505. // NmRpcJoinBegin2.
  1506. //
  1507. if (joinBegin3) {
  1508. // Only read the cluster instance ID from the registry on
  1509. // the first try.
  1510. if (clusterInstanceId == NULL) {
  1511. DWORD clusterInstanceIdBufSize = 0;
  1512. DWORD clusterInstanceIdSize = 0;
  1513. status = NmpQueryString(
  1514. DmClusterParametersKey,
  1515. L"ClusterInstanceID",
  1516. REG_SZ,
  1517. &clusterInstanceId,
  1518. &clusterInstanceIdBufSize,
  1519. &clusterInstanceIdSize
  1520. );
  1521. if (status != ERROR_SUCCESS) {
  1522. ClRtlLogPrint(LOG_UNUSUAL,
  1523. "[NMJOIN] Failed to read cluster instance ID from database, status %1!u!.\n",
  1524. status
  1525. );
  1526. // Try to join with the downlevel interface. It is
  1527. // possible that this node was just upgraded and the
  1528. // last time it was in the cluster there was no
  1529. // cluster instance ID.
  1530. joinBegin3 = FALSE;
  1531. continue;
  1532. }
  1533. }
  1534. status = NmRpcJoinBegin3(
  1535. SponsorBinding,
  1536. clusterInstanceId,
  1537. NmLocalNodeIdString,
  1538. NmLocalNodeName,
  1539. CsMyHighestVersion,
  1540. CsMyLowestVersion,
  1541. 0, // joiner's major node version
  1542. 0, // joiner's minor node version
  1543. L"", // joiner's CsdVersion
  1544. 0, // joiner's product suite
  1545. &sponsorNodeId,
  1546. &NmpJoinSequence,
  1547. &NmpClusnetEndpoint
  1548. );
  1549. if (status == RPC_S_PROCNUM_OUT_OF_RANGE) {
  1550. // retry immediately with JoinBegin2
  1551. joinBegin3 = FALSE;
  1552. continue;
  1553. }
  1554. } else {
  1555. status = NmRpcJoinBegin2(
  1556. SponsorBinding,
  1557. NmLocalNodeIdString,
  1558. NmLocalNodeName,
  1559. CsMyHighestVersion,
  1560. CsMyLowestVersion,
  1561. &sponsorNodeId,
  1562. &NmpJoinSequence,
  1563. &NmpClusnetEndpoint
  1564. );
  1565. }
  1566. if ( ((status != ERROR_CLUSTER_NODE_UP
  1567. && status != ERROR_CLUSTER_JOIN_IN_PROGRESS) ) || retry == 0 )
  1568. {
  1569. break;
  1570. }
  1571. ClRtlLogPrint(LOG_UNUSUAL,
  1572. "[NMJOIN] Unable to begin join, status %1!u!. Retrying ...\n",
  1573. status
  1574. );
  1575. CsServiceStatus.dwCheckPoint++;
  1576. CsAnnounceServiceStatus();
  1577. Sleep(3000);
  1578. --retry;
  1579. }
  1580. // Free the cluster instance ID string, if necessary.
  1581. if (clusterInstanceId != NULL) {
  1582. midl_user_free(clusterInstanceId);
  1583. }
  1584. // [GORN Jan/7/2000]
  1585. // If we are here, then we have already successfully talked to the sponsor
  1586. // via JoinVersion interface.
  1587. //
  1588. // We shouldn't try to form the cluster if NmRpcJoinBegin2 fails.
  1589. // Otherwise we may steal the quorum on the move [452108]
  1590. //
  1591. // Past this point we will not try to form a cluster
  1592. //
  1593. bFormCluster = FALSE;
  1594. if (status != ERROR_SUCCESS) {
  1595. eventCode = NM_EVENT_BEGIN_JOIN_FAILED;
  1596. ClRtlLogPrint(LOG_CRITICAL,
  1597. "[NMJOIN] Unable to begin join, status %1!u!.\n",
  1598. status
  1599. );
  1600. goto error_exit;
  1601. }
  1602. ClRtlLogPrint(LOG_NOISE,
  1603. "[NMJOIN] Sponsor node ID = %1!u!. Join sequence number = %2!u!, endpoint = %3!ws!.\n",
  1604. sponsorNodeId,
  1605. NmpJoinSequence,
  1606. NmpClusnetEndpoint
  1607. );
  1608. //
  1609. // Create all of the cluster objects for which we are responsible.
  1610. //
  1611. status = NmpCreateClusterObjects(SponsorBinding);
  1612. if (status != ERROR_SUCCESS) {
  1613. goto error_exit;
  1614. }
  1615. // The local node version might have changed, fix it
  1616. // The sponsorer fixes it in the registry and tells other
  1617. // nodes about it, however the joining node is not a part
  1618. // of the cluster membership as yet.
  1619. // The local node structure is created early on in NmInitialize()
  1620. // hence it must get fixed up
  1621. if ((NmLocalNode->HighestVersion != CsMyHighestVersion) ||
  1622. (NmLocalNode->LowestVersion != CsMyLowestVersion))
  1623. {
  1624. ClRtlLogPrint(LOG_UNUSUAL,
  1625. "[NMJOIN] Local Node version changed probably due to upgrade/deinstall\n");
  1626. NmLocalNode->HighestVersion = CsMyHighestVersion;
  1627. NmLocalNode->LowestVersion = CsMyLowestVersion;
  1628. NmLocalNodeVersionChanged = TRUE;
  1629. }
  1630. //at this point we ready to calculate the cluster version
  1631. //all the node objects contain the correct node versions
  1632. NmpResetClusterVersion(FALSE);
  1633. NmpMulticastInitialize();
  1634. //
  1635. // Enable communication for the local node.
  1636. //
  1637. status = ClusnetOnlineNodeComm(NmClusnetHandle, NmLocalNodeId);
  1638. if (status != ERROR_SUCCESS) {
  1639. wsprintfW(&(errorString[0]), L"%u", NmLocalNodeId);
  1640. wsprintfW(&(errorString2[0]), L"%u", status);
  1641. CsLogEvent2(
  1642. LOG_CRITICAL,
  1643. NM_EVENT_CLUSNET_ONLINE_COMM_FAILED,
  1644. errorString,
  1645. errorString2
  1646. );
  1647. ClRtlLogPrint(LOG_CRITICAL,
  1648. "[NMJOIN] Unable to enable communication for local node, status %1!u!.\n",
  1649. status
  1650. );
  1651. goto error_exit;
  1652. }
  1653. //
  1654. // Fire up the intracluster RPC server so we can perform the membership
  1655. // join.
  1656. //
  1657. status = ClusterRegisterIntraclusterRpcInterface();
  1658. if ( status != ERROR_SUCCESS ) {
  1659. eventCode = CS_EVENT_RPC_INIT_FAILED;
  1660. ClRtlLogPrint(LOG_CRITICAL,
  1661. "ClusSvc: Error starting intracluster RPC server, Status = %1!u!\n",
  1662. status);
  1663. goto error_exit;
  1664. }
  1665. //
  1666. // Cycle through the list of cluster nodes and create mutual RPC bindings
  1667. // for the intracluster interface with each.
  1668. //
  1669. for (nodeEntry = NmpNodeList.Flink;
  1670. nodeEntry != &NmpNodeList;
  1671. nodeEntry = nodeEntry->Flink
  1672. )
  1673. {
  1674. node = CONTAINING_RECORD(nodeEntry, NM_NODE, Linkage);
  1675. if ( (node != NmLocalNode)
  1676. &&
  1677. ( (node->State == ClusterNodeUp)
  1678. ||
  1679. (node->State == ClusterNodePaused)
  1680. )
  1681. )
  1682. {
  1683. ClRtlLogPrint(LOG_NOISE,
  1684. "[NMJOIN] Creating RPC bindings for member node %1!u!\n",
  1685. node->NodeId
  1686. );
  1687. //
  1688. //
  1689. // Cycle through the target node's interfaces
  1690. //
  1691. for (ifEntry = node->InterfaceList.Flink;
  1692. ifEntry != &(node->InterfaceList);
  1693. ifEntry = ifEntry->Flink
  1694. )
  1695. {
  1696. netInterface = CONTAINING_RECORD(
  1697. ifEntry,
  1698. NM_INTERFACE,
  1699. NodeLinkage
  1700. );
  1701. network = netInterface->Network;
  1702. if (NmpIsNetworkForInternalUse(network)) {
  1703. if ( (network->LocalInterface != NULL) &&
  1704. NmpIsInterfaceRegistered(network->LocalInterface) &&
  1705. NmpIsInterfaceRegistered(netInterface)
  1706. )
  1707. {
  1708. PNM_INTERFACE localInterface = network->LocalInterface;
  1709. ClRtlLogPrint(LOG_NOISE,
  1710. "[NMJOIN] Attempting to use network %1!ws! to "
  1711. "create bindings for node %2!u!\n",
  1712. OmObjectName(network),
  1713. node->NodeId
  1714. );
  1715. status = NmpSetNodeInterfacePriority(
  1716. node,
  1717. 0xFFFFFFFF,
  1718. netInterface,
  1719. 1
  1720. );
  1721. if (status == ERROR_SUCCESS) {
  1722. status = NmRpcCreateBinding(
  1723. SponsorBinding,
  1724. NmpJoinSequence,
  1725. NmLocalNodeIdString,
  1726. (LPWSTR) OmObjectId(localInterface),
  1727. (LPWSTR) OmObjectId(node)
  1728. );
  1729. if (status == ERROR_SUCCESS) {
  1730. //
  1731. // Create RPC bindings for the target node.
  1732. //
  1733. status = NmpCreateRpcBindings(node);
  1734. if (status == ERROR_SUCCESS) {
  1735. ClRtlLogPrint(LOG_NOISE,
  1736. "[NMJOIN] Created binding for node "
  1737. "%1!u!\n",
  1738. node->NodeId
  1739. );
  1740. break;
  1741. }
  1742. wsprintfW(&(errorString[0]), L"%u", status);
  1743. CsLogEvent3(
  1744. LOG_UNUSUAL,
  1745. NM_EVENT_JOIN_BIND_OUT_FAILED,
  1746. OmObjectName(node),
  1747. OmObjectName(network),
  1748. errorString
  1749. );
  1750. ClRtlLogPrint(LOG_UNUSUAL,
  1751. "[NMJOIN] Unable to create binding for "
  1752. "node %1!u!, status %2!u!.\n",
  1753. node->NodeId,
  1754. status
  1755. );
  1756. }
  1757. else {
  1758. wsprintfW(&(errorString[0]), L"%u", status);
  1759. CsLogEvent3(
  1760. LOG_UNUSUAL,
  1761. NM_EVENT_JOIN_BIND_IN_FAILED,
  1762. OmObjectName(node),
  1763. OmObjectName(network),
  1764. errorString
  1765. );
  1766. ClRtlLogPrint(LOG_CRITICAL,
  1767. "[NMJOIN] Member node %1!u! failed to "
  1768. "create binding to us, status %2!u!\n",
  1769. node->NodeId,
  1770. status
  1771. );
  1772. }
  1773. }
  1774. else {
  1775. wsprintfW(&(errorString[0]), L"%u", node->NodeId);
  1776. wsprintfW(&(errorString2[0]), L"%u", status);
  1777. CsLogEvent2(
  1778. LOG_UNUSUAL,
  1779. NM_EVENT_CLUSNET_SET_INTERFACE_PRIO_FAILED,
  1780. errorString,
  1781. errorString2
  1782. );
  1783. ClRtlLogPrint(LOG_CRITICAL,
  1784. "[NMJOIN] Failed to set interface priorities "
  1785. "for node %1!u!, status %2!u!\n",
  1786. node->NodeId,
  1787. status
  1788. );
  1789. }
  1790. }
  1791. else {
  1792. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  1793. ClRtlLogPrint(LOG_NOISE,
  1794. "[NMJOIN] No matching local interface for "
  1795. "network %1!ws!\n",
  1796. OmObjectName(netInterface->Network)
  1797. );
  1798. }
  1799. }
  1800. else {
  1801. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  1802. ClRtlLogPrint(LOG_NOISE,
  1803. "[NMJOIN] Network %1!ws! is not used for internal "
  1804. "communication.\n",
  1805. OmObjectName(netInterface->Network)
  1806. );
  1807. }
  1808. }
  1809. if (status != ERROR_SUCCESS) {
  1810. //
  1811. // Cannot make contact with this node. The join fails.
  1812. //
  1813. CsLogEvent1(
  1814. LOG_CRITICAL,
  1815. NM_EVENT_NODE_UNREACHABLE,
  1816. OmObjectName(node)
  1817. );
  1818. ClRtlLogPrint(LOG_NOISE,
  1819. "[NMJOIN] Cluster node %1!u! is not reachable. Join "
  1820. "failed.\n",
  1821. node->NodeId
  1822. );
  1823. goto error_exit;
  1824. }
  1825. }
  1826. }
  1827. CL_ASSERT(status == ERROR_SUCCESS);
  1828. //
  1829. // run through the active nodes again, this time establishing
  1830. // security contexts to use in signing packets
  1831. //
  1832. ClRtlLogPrint(LOG_NOISE,
  1833. "[NMJOIN] Establishing security contexts with all active nodes.\n"
  1834. );
  1835. for (nodeEntry = NmpNodeList.Flink;
  1836. nodeEntry != &NmpNodeList;
  1837. nodeEntry = nodeEntry->Flink
  1838. )
  1839. {
  1840. node = CONTAINING_RECORD(nodeEntry, NM_NODE, Linkage);
  1841. status = ClMsgCreateActiveNodeSecurityContext(NmpJoinSequence, node);
  1842. if ( status != ERROR_SUCCESS ) {
  1843. wsprintfW(&(errorString[0]), L"%u", status);
  1844. CsLogEvent2(
  1845. LOG_UNUSUAL,
  1846. NM_EVENT_CREATE_SECURITY_CONTEXT_FAILED,
  1847. OmObjectName(node),
  1848. errorString
  1849. );
  1850. ClRtlLogPrint(LOG_CRITICAL,
  1851. "[NMJOIN] Unable to establish security context for node %1!u!, status 0x%2!08X!\n",
  1852. node->NodeId,
  1853. status
  1854. );
  1855. goto error_exit;
  1856. }
  1857. }
  1858. //
  1859. // Finally, petition the sponsor for membership
  1860. //
  1861. ClRtlLogPrint(LOG_NOISE,
  1862. "[NMJOIN] Petitioning to join cluster membership.\n"
  1863. );
  1864. #ifdef CLUSTER_TESTPOINT
  1865. TESTPT(TpFailJoinPetitionForMembership) {
  1866. status = 999999;
  1867. goto error_exit;
  1868. }
  1869. #endif
  1870. status = NmRpcPetitionForMembership(
  1871. SponsorBinding,
  1872. NmpJoinSequence,
  1873. NmLocalNodeIdString
  1874. );
  1875. if (status != ERROR_SUCCESS) {
  1876. //
  1877. // Our petition was denied.
  1878. //
  1879. eventCode = NM_EVENT_PETITION_FAILED;
  1880. ClRtlLogPrint(LOG_CRITICAL,
  1881. "[NMJOIN] Petition to join was denied %1!d!\n",
  1882. status
  1883. );
  1884. goto error_exit;
  1885. }
  1886. #ifdef CLUSTER_TESTPOINT
  1887. TESTPT(TpFailNmJoin) {
  1888. status = 999999;
  1889. goto error_exit;
  1890. }
  1891. #endif
  1892. //
  1893. // Reset the interface priorities for all nodes to default to
  1894. // the priorities of the associated networks.
  1895. //
  1896. NmpAcquireLock();
  1897. for (ifEntry = NmpInterfaceList.Flink;
  1898. ifEntry != &NmpInterfaceList;
  1899. ifEntry = ifEntry->Flink
  1900. )
  1901. {
  1902. netInterface = CONTAINING_RECORD(ifEntry, NM_INTERFACE, Linkage);
  1903. network = netInterface->Network;
  1904. if ( NmpIsNetworkForInternalUse(network) &&
  1905. NmpIsInterfaceRegistered(netInterface)
  1906. )
  1907. {
  1908. status = ClusnetSetInterfacePriority(
  1909. NmClusnetHandle,
  1910. netInterface->Node->NodeId,
  1911. netInterface->Network->ShortId,
  1912. 0
  1913. );
  1914. CL_ASSERT(status == ERROR_SUCCESS);
  1915. }
  1916. }
  1917. NmpState = NmStateOnline;
  1918. NmpReleaseLock();
  1919. //
  1920. // Invoke other components to create RPC bindings for each node.
  1921. //
  1922. //
  1923. // Enable our GUM update handler.
  1924. //
  1925. GumReceiveUpdates(
  1926. TRUE,
  1927. GumUpdateMembership,
  1928. NmpGumUpdateHandler,
  1929. NULL,
  1930. sizeof(NmGumDispatchTable)/sizeof(GUM_DISPATCH_ENTRY),
  1931. NmGumDispatchTable,
  1932. NULL
  1933. );
  1934. // DavidDio 8/16/2001
  1935. // Bug 456951: There is a race condition in the form path between
  1936. // the network and interface state update and setting the NM state
  1937. // to online. If the state is online but no GUM handler is registered,
  1938. // the update will not be invoked. Hence, use the following flag to
  1939. // indicate that a handler is ready.
  1940. NmpGumUpdateHandlerRegistered = TRUE;
  1941. return(ERROR_SUCCESS);
  1942. error_exit:
  1943. if (eventCode != 0) {
  1944. wsprintfW(&(errorString[0]), L"%u", status);
  1945. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  1946. }
  1947. return(status);
  1948. } // NmJoinCluster
  1949. BOOLEAN
  1950. NmpVerifyJoinerConnectivity(
  1951. IN PNM_NODE JoiningNode,
  1952. OUT PNM_NODE * UnreachableNode
  1953. )
  1954. {
  1955. PLIST_ENTRY entry;
  1956. PNM_NODE node;
  1957. ClRtlLogPrint(LOG_NOISE,
  1958. "[NMJOIN] Verifying connectivity to active cluster nodes\n"
  1959. );
  1960. *UnreachableNode = NULL;
  1961. for (entry = NmpNodeList.Flink;
  1962. entry != &NmpNodeList;
  1963. entry = entry->Flink
  1964. )
  1965. {
  1966. node = CONTAINING_RECORD(
  1967. entry,
  1968. NM_NODE,
  1969. Linkage
  1970. );
  1971. if (NM_NODE_UP(node)) {
  1972. if (!NmpVerifyNodeConnectivity(JoiningNode, node, NULL)) {
  1973. *UnreachableNode = node;
  1974. return(FALSE);
  1975. }
  1976. }
  1977. }
  1978. return(TRUE);
  1979. } // NmpVerifyJoinerConnectivity
  1980. DWORD
  1981. NmGetJoinSequence(
  1982. VOID
  1983. )
  1984. {
  1985. DWORD sequence;
  1986. NmpAcquireLock();
  1987. sequence = NmpJoinSequence;
  1988. NmpReleaseLock();
  1989. return(sequence);
  1990. } // NmGetJoinSequence
  1991. DWORD
  1992. NmJoinComplete(
  1993. OUT DWORD *EndSeq
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. This routine is called by the initialization sequence once a
  1998. join has successfully completed and the node can transition
  1999. from ClusterNodeJoining to ClusterNodeOnline.
  2000. Arguments:
  2001. None
  2002. Return Value:
  2003. ERROR_SUCCESS if successful
  2004. Win32 error otherwise.
  2005. --*/
  2006. {
  2007. DWORD Sequence;
  2008. DWORD Status;
  2009. PNM_JOIN_UPDATE JoinUpdate = NULL;
  2010. DWORD UpdateLength;
  2011. HDMKEY NodeKey = NULL;
  2012. DWORD Default = 0;
  2013. DWORD NumRetries=50;
  2014. DWORD eventCode = 0;
  2015. WCHAR errorString[12];
  2016. PNM_NETWORK_STATE_ENUM networkStateEnum = NULL;
  2017. PNM_NETWORK_STATE_INFO networkStateInfo;
  2018. PNM_INTERFACE_STATE_ENUM interfaceStateEnum = NULL;
  2019. PNM_INTERFACE_STATE_INFO interfaceStateInfo;
  2020. DWORD i;
  2021. PNM_NETWORK network;
  2022. PNM_INTERFACE netInterface;
  2023. PLIST_ENTRY entry;
  2024. DWORD moveCount;
  2025. UpdateLength = sizeof(NM_JOIN_UPDATE) +
  2026. (lstrlenW(OmObjectId(NmLocalNode))+1)*sizeof(WCHAR);
  2027. JoinUpdate = LocalAlloc(LMEM_FIXED, UpdateLength);
  2028. if (JoinUpdate == NULL) {
  2029. Status = ERROR_NOT_ENOUGH_MEMORY;
  2030. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  2031. ClRtlLogPrint(LOG_CRITICAL, "[NMJOIN] Unable to allocate memory.\n");
  2032. goto error_exit;
  2033. }
  2034. JoinUpdate->JoinSequence = NmpJoinSequence;
  2035. lstrcpyW(JoinUpdate->NodeId, OmObjectId(NmLocalNode));
  2036. NodeKey = DmOpenKey(DmNodesKey, OmObjectId(NmLocalNode), KEY_READ);
  2037. if (NodeKey == NULL) {
  2038. Status = GetLastError();
  2039. wsprintfW(&(errorString[0]), L"%u", Status);
  2040. CsLogEvent2(
  2041. LOG_CRITICAL,
  2042. CS_EVENT_REG_OPEN_FAILED,
  2043. OmObjectId(NmLocalNode),
  2044. errorString
  2045. );
  2046. ClRtlLogPrint(
  2047. LOG_CRITICAL,
  2048. "[NMJOIN] Unable to open database key to local node, status %1!u!.\n",
  2049. Status
  2050. );
  2051. goto error_exit;
  2052. }
  2053. retry:
  2054. Status = GumBeginJoinUpdate(GumUpdateMembership, &Sequence);
  2055. if (Status != ERROR_SUCCESS) {
  2056. eventCode = NM_EVENT_GENERAL_JOIN_ERROR;
  2057. goto error_exit;
  2058. }
  2059. //
  2060. // Get the leader node ID from the sponsor.
  2061. //
  2062. Status = NmRpcGetLeaderNodeId(
  2063. CsJoinSponsorBinding,
  2064. NmpJoinSequence,
  2065. NmLocalNodeIdString,
  2066. &NmpLeaderNodeId
  2067. );
  2068. if (Status != ERROR_SUCCESS) {
  2069. if (Status == ERROR_CALL_NOT_IMPLEMENTED) {
  2070. //
  2071. // The sponsor is an NT4 node. Make this node the leader.
  2072. //
  2073. NmpLeaderNodeId = NmLocalNodeId;
  2074. }
  2075. else {
  2076. ClRtlLogPrint(LOG_CRITICAL,
  2077. "[NMJOIN] Failed to get leader node ID from sponsor, status %1!u!.\n",
  2078. Status
  2079. );
  2080. goto error_exit;
  2081. }
  2082. }
  2083. ClRtlLogPrint(LOG_NOISE,
  2084. "[NMJOIN] Node %1!u! is the leader.\n",
  2085. NmpLeaderNodeId
  2086. );
  2087. //
  2088. // Fetch the network and interface states from the sponsor
  2089. //
  2090. Status = NmRpcEnumNetworkAndInterfaceStates(
  2091. CsJoinSponsorBinding,
  2092. NmpJoinSequence,
  2093. NmLocalNodeIdString,
  2094. &networkStateEnum,
  2095. &interfaceStateEnum
  2096. );
  2097. if (Status != ERROR_SUCCESS) {
  2098. ClRtlLogPrint(LOG_CRITICAL,
  2099. "[NMJOIN] Failed to get network and interface state values from sponsor, status %1!u!.\n",
  2100. Status
  2101. );
  2102. goto error_exit;
  2103. }
  2104. NmpAcquireLock();
  2105. for (i=0; i<networkStateEnum->NetworkCount; i++) {
  2106. networkStateInfo = &(networkStateEnum->NetworkList[i]);
  2107. network = OmReferenceObjectById(
  2108. ObjectTypeNetwork,
  2109. networkStateInfo->Id
  2110. );
  2111. if (network == NULL) {
  2112. ClRtlLogPrint(LOG_CRITICAL,
  2113. "[NMJOIN] Cannot find network %1!ws! to update state.\n",
  2114. networkStateInfo->Id
  2115. );
  2116. NmpReleaseLock();
  2117. NmpFreeNetworkStateEnum(networkStateEnum);
  2118. LocalFree(JoinUpdate);
  2119. DmCloseKey(NodeKey);
  2120. return(ERROR_CLUSTER_NETWORK_NOT_FOUND);
  2121. }
  2122. network->State = networkStateInfo->State;
  2123. OmDereferenceObject(network);
  2124. }
  2125. for (i=0; i<interfaceStateEnum->InterfaceCount; i++) {
  2126. interfaceStateInfo = &(interfaceStateEnum->InterfaceList[i]);
  2127. netInterface = OmReferenceObjectById(
  2128. ObjectTypeNetInterface,
  2129. interfaceStateInfo->Id
  2130. );
  2131. if (netInterface == NULL) {
  2132. ClRtlLogPrint(LOG_CRITICAL,
  2133. "[NMJOIN] Cannot find interface %1!ws! to update state.\n",
  2134. interfaceStateInfo->Id
  2135. );
  2136. NmpReleaseLock();
  2137. NmpFreeInterfaceStateEnum(interfaceStateEnum);
  2138. LocalFree(JoinUpdate);
  2139. DmCloseKey(NodeKey);
  2140. return(ERROR_CLUSTER_NETINTERFACE_NOT_FOUND);
  2141. }
  2142. netInterface->State = interfaceStateInfo->State;
  2143. OmDereferenceObject(netInterface);
  2144. }
  2145. NmpReleaseLock();
  2146. NmpFreeInterfaceStateEnum(interfaceStateEnum);
  2147. interfaceStateEnum = NULL;
  2148. //
  2149. // Check the registry to see if we should come up paused.
  2150. //
  2151. JoinUpdate->IsPaused = Default;
  2152. Status = DmQueryDword(NodeKey,
  2153. CLUSREG_NAME_NODE_PAUSED,
  2154. &JoinUpdate->IsPaused,
  2155. &Default);
  2156. if (Status != ERROR_SUCCESS) {
  2157. ClRtlLogPrint(LOG_UNUSUAL,
  2158. "[NMJOIN] Unable to query Paused value for local node, status %1!u!.\n",
  2159. Status
  2160. );
  2161. }
  2162. Status = GumEndJoinUpdate(Sequence,
  2163. GumUpdateMembership,
  2164. NmUpdateJoinComplete,
  2165. UpdateLength,
  2166. JoinUpdate);
  2167. if (Status != ERROR_SUCCESS) {
  2168. if (Status == ERROR_CLUSTER_JOIN_ABORTED) {
  2169. //
  2170. // The join was aborted by the cluster members. Don't retry.
  2171. //
  2172. CsLogEvent(LOG_CRITICAL, NM_EVENT_JOIN_ABORTED);
  2173. goto error_exit;
  2174. }
  2175. ClRtlLogPrint(LOG_UNUSUAL,
  2176. "[NMJOIN] GumEndJoinUpdate with sequence %1!d! failed %2!d!\n",
  2177. Sequence,
  2178. Status
  2179. );
  2180. if (--NumRetries == 0) {
  2181. CsLogEvent(LOG_CRITICAL, NM_EVENT_JOIN_ABANDONED);
  2182. ClRtlLogPrint(LOG_UNUSUAL,
  2183. "[NMJOIN] Tried to complete join too many times. Giving up.\n"
  2184. );
  2185. goto error_exit;
  2186. }
  2187. goto retry;
  2188. }
  2189. //
  2190. // If the cluster instance ID does not exist, create it now. The cluster
  2191. // instance ID should be in the database unless this is the first uplevel
  2192. // node.
  2193. //
  2194. NmpCreateClusterInstanceId();
  2195. //
  2196. // Derive the cluster key.
  2197. //
  2198. Status = NmpRederiveClusterKey();
  2199. if (Status != ERROR_SUCCESS) {
  2200. ClRtlLogPrint(LOG_UNUSUAL,
  2201. "[NM] Failed to derive cluster key, status %1!u!. "
  2202. "Aborting ...\n",
  2203. Status
  2204. );
  2205. goto error_exit;
  2206. }
  2207. NmpAcquireLock();
  2208. if (JoinUpdate->IsPaused != 0) {
  2209. //
  2210. // We should be coming up paused.
  2211. //
  2212. NmLocalNode->State = ClusterNodePaused;
  2213. } else {
  2214. //
  2215. // Set our state to online.
  2216. //
  2217. NmLocalNode->State = ClusterNodeUp;
  2218. }
  2219. //
  2220. // Start multicast for all networks.
  2221. //
  2222. Status = NmpStartMulticast(NULL, NmStartMulticastJoin);
  2223. if (Status != ERROR_SUCCESS) {
  2224. ClRtlLogPrint(LOG_UNUSUAL,
  2225. "[NM] Failed to refresh multicast configuration "
  2226. "for cluster networks, status %1!u!.\n",
  2227. Status
  2228. );
  2229. //
  2230. // Not a fatal error.
  2231. //
  2232. Status = ERROR_SUCCESS;
  2233. }
  2234. NmpReleaseLock();
  2235. //
  2236. // Finally, enable network PnP event handling.
  2237. //
  2238. // If a PnP event occured during the join process, an error code will
  2239. // be returned, which will abort startup of the service.
  2240. //
  2241. Status = NmpEnablePnpEvents();
  2242. if (Status != ERROR_SUCCESS) {
  2243. ClRtlLogPrint(LOG_UNUSUAL,
  2244. "[NMJOIN] A network PnP event occurred during join - abort.\n");
  2245. goto error_exit;
  2246. }
  2247. //
  2248. // Mark end sequence
  2249. *EndSeq = Sequence;
  2250. ClRtlLogPrint(LOG_NOISE, "[NMJOIN] Join complete, node now online\n");
  2251. error_exit:
  2252. if (JoinUpdate != NULL) {
  2253. LocalFree(JoinUpdate);
  2254. }
  2255. if (NodeKey != NULL) {
  2256. DmCloseKey(NodeKey);
  2257. }
  2258. if (eventCode != 0) {
  2259. wsprintfW(&(errorString[0]), L"%u", Status);
  2260. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  2261. }
  2262. return(Status);
  2263. } // NmJoinComplete
  2264. //
  2265. // Server-side routines for sponsoring a joining node.
  2266. //
  2267. /*
  2268. Notes On Joining:
  2269. Only a single node may join the cluster at any time. A join begins with
  2270. a JoinBegin global update. A join completes successfully with a
  2271. JoinComplete global update. A join is aborted with a JoinAbort global
  2272. update.
  2273. A timer runs on the sponsor during a join. The timer is suspended
  2274. while the sponsor is performing work on behalf of the joiner. If the
  2275. timer expires, a worker thread is scheduled to initiate the abort
  2276. process.
  2277. If the sponsor goes down while a join is in progress, the node
  2278. down handling code on each remaining node will abort the join.
  2279. */
  2280. error_status_t
  2281. s_NmRpcJoinBegin(
  2282. IN handle_t IDL_handle,
  2283. IN LPWSTR JoinerNodeId,
  2284. IN LPWSTR JoinerNodeName,
  2285. OUT LPDWORD SponsorNodeId,
  2286. OUT LPDWORD JoinSequenceNumber,
  2287. OUT LPWSTR * ClusnetEndpoint
  2288. )
  2289. /*++
  2290. Routine Description:
  2291. Called by a joining node to begin the join process.
  2292. Issues a JoinBegin global update.
  2293. --*/
  2294. {
  2295. DWORD status=ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  2296. ClRtlLogPrint(LOG_NOISE,
  2297. "[NMJOIN] Request by node %1!ws! to begin joining, refused. Using obsolete join interface\n",
  2298. JoinerNodeId
  2299. );
  2300. if ( status != ERROR_SUCCESS ) {
  2301. WCHAR errorCode[16];
  2302. wsprintfW( errorCode, L"%u", status );
  2303. CsLogEvent2(
  2304. LOG_CRITICAL,
  2305. NM_EVENT_JOIN_REFUSED,
  2306. JoinerNodeId,
  2307. errorCode
  2308. );
  2309. }
  2310. return(status);
  2311. } // s_NmRpcJoinBegin
  2312. //
  2313. // Server-side routines for sponsoring a joining node.
  2314. //
  2315. /*
  2316. Notes On Joining:
  2317. */
  2318. //#pragma optimize("", off)
  2319. DWORD
  2320. NmpJoinBegin(
  2321. IN LPWSTR JoinerNodeId,
  2322. IN LPWSTR JoinerNodeName,
  2323. IN DWORD JoinerHighestVersion,
  2324. IN DWORD JoinerLowestVersion,
  2325. OUT LPDWORD SponsorNodeId,
  2326. OUT LPDWORD JoinSequenceNumber,
  2327. OUT LPWSTR * ClusnetEndpoint
  2328. )
  2329. /*++
  2330. Routine Description:
  2331. Called from s_NmRpcJoinBegin2 and s_NmRpcJoinBegin3.
  2332. Contains functionality common to both JoinBegin versions.
  2333. Notes:
  2334. Called with NM lock held and NmpLockedEnterApi already
  2335. called.
  2336. --*/
  2337. {
  2338. DWORD status = ERROR_SUCCESS;
  2339. PNM_NODE joinerNode = NULL;
  2340. LPWSTR endpoint = NULL;
  2341. joinerNode = OmReferenceObjectById(
  2342. ObjectTypeNode,
  2343. JoinerNodeId
  2344. );
  2345. if (joinerNode == NULL) {
  2346. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2347. ClRtlLogPrint(LOG_UNUSUAL,
  2348. "[NMJOIN] Node %1!ws! is not a member of this cluster. Cannot join.\n",
  2349. JoinerNodeId
  2350. );
  2351. goto FnExit;
  2352. }
  2353. endpoint = MIDL_user_allocate(NM_WCSLEN(NmpClusnetEndpoint));
  2354. if (endpoint == NULL) {
  2355. status = ERROR_NOT_ENOUGH_MEMORY;
  2356. goto FnExit;
  2357. }
  2358. lstrcpyW(endpoint, NmpClusnetEndpoint);
  2359. if (NmpJoinBeginInProgress || NmpJoinerNodeId != ClusterInvalidNodeId) {
  2360. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  2361. ClRtlLogPrint(LOG_UNUSUAL,
  2362. "[NMJOIN] Node %1!ws! cannot join because a join is already in progress (%2!d!).\n",
  2363. JoinerNodeId,
  2364. NmpJoinerNodeId
  2365. );
  2366. goto FnExit;
  2367. }
  2368. //
  2369. //validate the nodes version's number
  2370. //ie. check to see what the cluster database
  2371. //claims this node's version is vs what the node
  2372. //itself suggests
  2373. status = NmpValidateNodeVersion(
  2374. JoinerNodeId,
  2375. JoinerHighestVersion,
  2376. JoinerLowestVersion
  2377. );
  2378. //since this node joined, its version has changed
  2379. //this may happen due to upgrades or reinstall
  2380. //if this version cant join due to versioning,fail the join
  2381. if (status == ERROR_REVISION_MISMATCH) {
  2382. DWORD id = NmGetNodeId(joinerNode);
  2383. status = NmpIsNodeVersionAllowed(
  2384. id,
  2385. JoinerHighestVersion,
  2386. JoinerLowestVersion,
  2387. TRUE
  2388. );
  2389. if (status != ERROR_SUCCESS) {
  2390. ClRtlLogPrint(LOG_NOISE,
  2391. "[NMJOIN] The version of the cluster prevents Node %1!ws! from joining the cluster\n",
  2392. JoinerNodeId
  2393. );
  2394. goto FnExit;
  2395. }
  2396. }
  2397. else if (status != ERROR_SUCCESS) {
  2398. ClRtlLogPrint(LOG_NOISE,
  2399. "[NMJOIN] The version of Node %1!ws! cannot be validated.\n",
  2400. JoinerNodeId
  2401. );
  2402. goto FnExit;
  2403. }
  2404. //
  2405. // Lock out other join attempts with this sponsor.
  2406. //
  2407. NmpJoinBeginInProgress = TRUE;
  2408. NmpSuccessfulMMJoin = FALSE;
  2409. NmpReleaseLock();
  2410. status = GumSendUpdateEx(
  2411. GumUpdateMembership,
  2412. NmUpdateJoinBegin2,
  2413. 5,
  2414. NM_WCSLEN(JoinerNodeId),
  2415. JoinerNodeId,
  2416. NM_WCSLEN(JoinerNodeName),
  2417. JoinerNodeName,
  2418. NM_WCSLEN(NmLocalNodeIdString),
  2419. NmLocalNodeIdString,
  2420. sizeof(DWORD),
  2421. &JoinerHighestVersion,
  2422. sizeof(DWORD),
  2423. &JoinerLowestVersion
  2424. );
  2425. NmpAcquireLock();
  2426. CL_ASSERT(NmpJoinBeginInProgress == TRUE);
  2427. NmpJoinBeginInProgress = FALSE;
  2428. if (status != ERROR_SUCCESS)
  2429. {
  2430. ClRtlLogPrint(LOG_UNUSUAL,
  2431. "[NMJOIN] JoinBegin2 update for node %1!ws! failed, status %2!u!\n",
  2432. JoinerNodeId,
  2433. status
  2434. );
  2435. goto FnExit;
  2436. }
  2437. //
  2438. // Verify that the join is still in progress with
  2439. // this node as the sponsor.
  2440. //
  2441. if ( (NmpJoinerNodeId == joinerNode->NodeId) &&
  2442. (NmpSponsorNodeId == NmLocalNodeId)
  2443. )
  2444. {
  2445. //
  2446. // Give the joiner parameters for future
  2447. // join-related calls.
  2448. //
  2449. *SponsorNodeId = NmLocalNodeId;
  2450. *JoinSequenceNumber = NmpJoinSequence;
  2451. //
  2452. // Start the join timer
  2453. //
  2454. NmpJoinTimer = NM_JOIN_TIMEOUT;
  2455. ClRtlLogPrint(LOG_NOISE,
  2456. "[NMJOIN] Node %1!ws! has begun the join process.\n",
  2457. JoinerNodeId
  2458. );
  2459. }
  2460. else
  2461. {
  2462. status = ERROR_CLUSTER_JOIN_ABORTED;
  2463. ClRtlLogPrint(LOG_UNUSUAL,
  2464. "[NMJOIN] Begin join of node %1!ws! was aborted\n",
  2465. JoinerNodeId
  2466. );
  2467. }
  2468. FnExit:
  2469. if (joinerNode) {
  2470. OmDereferenceObject(joinerNode);
  2471. }
  2472. if (status == ERROR_SUCCESS) {
  2473. *ClusnetEndpoint = endpoint;
  2474. }
  2475. else {
  2476. WCHAR errorCode[16];
  2477. if (endpoint) MIDL_user_free(endpoint);
  2478. wsprintfW( errorCode, L"%u", status );
  2479. CsLogEvent2(
  2480. LOG_CRITICAL,
  2481. NM_EVENT_JOIN_REFUSED,
  2482. JoinerNodeId,
  2483. errorCode
  2484. );
  2485. }
  2486. return(status);
  2487. } // NmpJoinBegin
  2488. error_status_t
  2489. s_NmRpcJoinBegin2(
  2490. IN handle_t IDL_handle,
  2491. IN LPWSTR JoinerNodeId,
  2492. IN LPWSTR JoinerNodeName,
  2493. IN DWORD JoinerHighestVersion,
  2494. IN DWORD JoinerLowestVersion,
  2495. OUT LPDWORD SponsorNodeId,
  2496. OUT LPDWORD JoinSequenceNumber,
  2497. OUT LPWSTR * ClusnetEndpoint
  2498. )
  2499. /*++
  2500. Routine Description:
  2501. Called by a joining node to begin the join process.
  2502. Issues a JoinBegin global update.
  2503. --*/
  2504. {
  2505. DWORD status = ERROR_SUCCESS;
  2506. status = FmDoesQuorumAllowJoin( JoinerNodeId );
  2507. if (status != ERROR_SUCCESS)
  2508. {
  2509. ClRtlLogPrint(LOG_NOISE,
  2510. "[NMJOIN] Quorum Characteristics prevent the node %1!ws! to from joining, Status=%2!u!.\n",
  2511. JoinerNodeId,
  2512. status
  2513. );
  2514. return(status);
  2515. }
  2516. NmpAcquireLock();
  2517. ClRtlLogPrint(LOG_NOISE,
  2518. "[NMJOIN] Processing request by node %1!ws! to begin joining (2).\n",
  2519. JoinerNodeId
  2520. );
  2521. if (!NmpLockedEnterApi(NmStateOnline)) {
  2522. status = ERROR_NODE_NOT_AVAILABLE;
  2523. ClRtlLogPrint(LOG_UNUSUAL,
  2524. "[NMJOIN] Cannot sponsor a joining node at this time.\n"
  2525. );
  2526. NmpReleaseLock();
  2527. return(status);
  2528. }
  2529. status = NmpJoinBegin(
  2530. JoinerNodeId,
  2531. JoinerNodeName,
  2532. JoinerHighestVersion,
  2533. JoinerLowestVersion,
  2534. SponsorNodeId,
  2535. JoinSequenceNumber,
  2536. ClusnetEndpoint
  2537. );
  2538. NmpLockedLeaveApi();
  2539. NmpReleaseLock();
  2540. return(status);
  2541. } // s_NmRpcJoinBegin2
  2542. error_status_t
  2543. s_NmRpcJoinBegin3(
  2544. IN handle_t IDL_handle,
  2545. IN LPWSTR JoinerClusterInstanceId,
  2546. IN LPWSTR JoinerNodeId,
  2547. IN LPWSTR JoinerNodeName,
  2548. IN DWORD JoinerHighestVersion,
  2549. IN DWORD JoinerLowestVersion,
  2550. IN DWORD JoinerMajorVersion,
  2551. IN DWORD JoinerMinorVersion,
  2552. IN LPWSTR JoinerCsdVersion,
  2553. IN DWORD JoinerProductSuite,
  2554. OUT LPDWORD SponsorNodeId,
  2555. OUT LPDWORD JoinSequenceNumber,
  2556. OUT LPWSTR * ClusnetEndpoint
  2557. )
  2558. {
  2559. DWORD status = ERROR_SUCCESS;
  2560. LPWSTR clusterInstanceId = NULL;
  2561. DWORD clusterInstanceIdBufSize = 0;
  2562. DWORD clusterInstanceIdSize = 0;
  2563. ClRtlLogPrint(LOG_NOISE,
  2564. "[NMJOIN] Processing request by node %1!ws! to begin joining (3).\n",
  2565. JoinerNodeId
  2566. );
  2567. status = FmDoesQuorumAllowJoin( JoinerNodeId );
  2568. if (status != ERROR_SUCCESS)
  2569. {
  2570. ClRtlLogPrint(LOG_NOISE,
  2571. "[NMJOIN] Quorum Characteristics prevent node %1!ws! from joining, Status=%2!u!.\n",
  2572. JoinerNodeId,
  2573. status
  2574. );
  2575. return(status);
  2576. }
  2577. //
  2578. // Check our cluster instance ID against the joiner's.
  2579. //
  2580. if (NmpClusterInstanceId == NULL ||
  2581. lstrcmpiW(NmpClusterInstanceId, JoinerClusterInstanceId) != 0) {
  2582. WCHAR errorCode[16];
  2583. status = ERROR_CLUSTER_INSTANCE_ID_MISMATCH;
  2584. ClRtlLogPrint(LOG_CRITICAL,
  2585. "[NMJOIN] Sponsor cluster instance ID %1!ws! does not match joiner cluster instance id %2!ws!.\n",
  2586. ((NmpClusterInstanceId == NULL) ? L"<NULL>" : NmpClusterInstanceId),
  2587. JoinerClusterInstanceId
  2588. );
  2589. wsprintfW( errorCode, L"%u", status );
  2590. CsLogEvent2(
  2591. LOG_CRITICAL,
  2592. NM_EVENT_JOIN_REFUSED,
  2593. JoinerNodeId,
  2594. errorCode
  2595. );
  2596. return(status);
  2597. } else {
  2598. ClRtlLogPrint(LOG_NOISE,
  2599. "[NMJOIN] Sponsor cluster instance ID matches joiner cluster instance id (%1!ws!).\n",
  2600. JoinerClusterInstanceId
  2601. );
  2602. }
  2603. NmpAcquireLock();
  2604. if (!NmpLockedEnterApi(NmStateOnline)) {
  2605. status = ERROR_NODE_NOT_AVAILABLE;
  2606. ClRtlLogPrint(LOG_UNUSUAL,
  2607. "[NMJOIN] Cannot sponsor a joining node at this time.\n"
  2608. );
  2609. } else {
  2610. status = NmpJoinBegin(
  2611. JoinerNodeId,
  2612. JoinerNodeName,
  2613. JoinerHighestVersion,
  2614. JoinerLowestVersion,
  2615. SponsorNodeId,
  2616. JoinSequenceNumber,
  2617. ClusnetEndpoint
  2618. );
  2619. NmpLockedLeaveApi();
  2620. }
  2621. NmpReleaseLock();
  2622. return(status);
  2623. } // s_NmRpcJoinBegin3
  2624. DWORD
  2625. NmpUpdateJoinBegin(
  2626. IN BOOL SourceNode,
  2627. IN LPWSTR JoinerNodeId,
  2628. IN LPWSTR JoinerNodeName,
  2629. IN LPWSTR SponsorNodeId
  2630. )
  2631. {
  2632. DWORD status=ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  2633. ClRtlLogPrint(LOG_NOISE,
  2634. "[NMJOIN] Failing update to begin join of node %1!ws! with "
  2635. "sponsor %2!ws!. Using obsolete join interface.\n",
  2636. JoinerNodeId,
  2637. SponsorNodeId
  2638. );
  2639. return(status);
  2640. } // NmpUpdateJoinBegin
  2641. DWORD
  2642. NmpUpdateJoinBegin2(
  2643. IN BOOL SourceNode,
  2644. IN LPWSTR JoinerNodeId,
  2645. IN LPWSTR JoinerNodeName,
  2646. IN LPWSTR SponsorNodeId,
  2647. IN LPDWORD JoinerHighestVersion,
  2648. IN LPDWORD JoinerLowestVersion
  2649. )
  2650. {
  2651. DWORD status = ERROR_SUCCESS;
  2652. PNM_NODE sponsorNode=NULL;
  2653. PNM_NODE joinerNode=NULL;
  2654. HLOCALXSACTION hXsaction=NULL;
  2655. BOOLEAN lockAcquired = FALSE;
  2656. BOOLEAN fakeSuccess = FALSE;
  2657. ClRtlLogPrint(LOG_NOISE,
  2658. "[NMJOIN] Received update to begin join (2) of node %1!ws! with "
  2659. "sponsor %2!ws!.\n",
  2660. JoinerNodeId,
  2661. SponsorNodeId
  2662. );
  2663. //
  2664. // If running with -noquorum flag or if not online, don't sponsor
  2665. // any node.
  2666. //
  2667. if (CsNoQuorum || !NmpEnterApi(NmStateOnline)) {
  2668. ClRtlLogPrint(LOG_NOISE,
  2669. "[NM] Not in valid state to begin a join operation.\n"
  2670. );
  2671. return(ERROR_NODE_NOT_AVAILABLE);
  2672. }
  2673. //
  2674. // Find the sponsor node
  2675. //
  2676. sponsorNode = OmReferenceObjectById(
  2677. ObjectTypeNode,
  2678. SponsorNodeId
  2679. );
  2680. if (sponsorNode == NULL) {
  2681. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2682. ClRtlLogPrint(LOG_UNUSUAL,
  2683. "[NMJOIN] JoinBegin update for node %1!ws! failed because "
  2684. "sponsor node %2!ws! is not a member of this cluster.\n",
  2685. JoinerNodeId,
  2686. SponsorNodeId
  2687. );
  2688. goto FnExit;
  2689. }
  2690. //
  2691. // Find the joiner node
  2692. //
  2693. joinerNode = OmReferenceObjectById(
  2694. ObjectTypeNode,
  2695. JoinerNodeId
  2696. );
  2697. if (joinerNode == NULL) {
  2698. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2699. ClRtlLogPrint(LOG_UNUSUAL,
  2700. "[NMJOIN] Node %1!ws! is not a member of this cluster. "
  2701. "Cannot join.\n",
  2702. JoinerNodeId
  2703. );
  2704. goto FnExit;
  2705. }
  2706. hXsaction = DmBeginLocalUpdate();
  2707. if (hXsaction == NULL) {
  2708. status = GetLastError();
  2709. ClRtlLogPrint(LOG_CRITICAL,
  2710. "[NM] Failed to start a transaction, status %1!u!\n",
  2711. status
  2712. );
  2713. goto FnExit;
  2714. }
  2715. NmpAcquireLock(); lockAcquired = TRUE;
  2716. if (!NM_NODE_UP(sponsorNode)) {
  2717. //
  2718. // [GorN 4/3/2000] See bug#98287
  2719. // This hack is a kludgy solution to a problem that
  2720. // a replay of this Gum update after the sponsor death
  2721. // will fail on all the nodes that didn't see the update.
  2722. //
  2723. fakeSuccess = TRUE;
  2724. status = ERROR_NODE_NOT_AVAILABLE;
  2725. ClRtlLogPrint(LOG_UNUSUAL,
  2726. "[NMJOIN] Sponsor node %1!ws! is not up. Join of node %2!ws! "
  2727. "failed.\n",
  2728. SponsorNodeId,
  2729. JoinerNodeId
  2730. );
  2731. goto FnExit;
  2732. }
  2733. //
  2734. // Check that the joiner is really who we think it is.
  2735. //
  2736. if (lstrcmpiW( OmObjectName(joinerNode), JoinerNodeName)) {
  2737. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2738. ClRtlLogPrint(LOG_UNUSUAL,
  2739. "[NMJOIN] Node %1!ws! is not a member of this cluster. "
  2740. "Cannot join.\n",
  2741. JoinerNodeName
  2742. );
  2743. goto FnExit;
  2744. }
  2745. //
  2746. // Make sure the joiner is currently down.
  2747. //
  2748. if (joinerNode->State != ClusterNodeDown) {
  2749. status = ERROR_CLUSTER_NODE_UP;
  2750. ClRtlLogPrint(LOG_UNUSUAL,
  2751. "[NMJOIN] Node %1!ws! is not down. Cannot begin join.\n",
  2752. JoinerNodeId
  2753. );
  2754. goto FnExit;
  2755. }
  2756. //
  2757. // Make sure we aren't already in a join.
  2758. //
  2759. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  2760. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  2761. ClRtlLogPrint(LOG_UNUSUAL,
  2762. "[NMJOIN] Node %1!ws! cannot begin join because a join is "
  2763. "already in progress for node %2!u!.\n",
  2764. JoinerNodeId,
  2765. NmpJoinerNodeId
  2766. );
  2767. goto FnExit;
  2768. }
  2769. //
  2770. // Perform the version compatibility check.
  2771. //
  2772. status = NmpIsNodeVersionAllowed(
  2773. NmGetNodeId(joinerNode),
  2774. *JoinerHighestVersion,
  2775. *JoinerLowestVersion,
  2776. TRUE
  2777. );
  2778. if (status != ERROR_SUCCESS) {
  2779. ClRtlLogPrint(LOG_UNUSUAL,
  2780. "[NMJOIN] The version of the cluster prevents Node %1!ws! "
  2781. "from joining the cluster\n",
  2782. JoinerNodeId
  2783. );
  2784. goto FnExit;
  2785. }
  2786. // Fix up the joiner's version number if needed.
  2787. //
  2788. status = NmpValidateNodeVersion(
  2789. JoinerNodeId,
  2790. *JoinerHighestVersion,
  2791. *JoinerLowestVersion
  2792. );
  2793. if (status == ERROR_REVISION_MISMATCH) {
  2794. //
  2795. // At this point, the registry contains the new
  2796. // versions for the joining code.
  2797. // The new node information should be reread
  2798. // from the registry before resetting the cluster
  2799. // version
  2800. // make sure the joiner gets the database from the
  2801. // sponsor after the fixups have occured
  2802. //
  2803. status = NmpJoinFixupNodeVersion(
  2804. hXsaction,
  2805. JoinerNodeId,
  2806. *JoinerHighestVersion,
  2807. *JoinerLowestVersion
  2808. );
  2809. if (status != ERROR_SUCCESS) {
  2810. ClRtlLogPrint(LOG_UNUSUAL,
  2811. "[NMJOIN] Node %1!ws! failed to fixup its node version\r\n",
  2812. JoinerNodeId);
  2813. goto FnExit;
  2814. }
  2815. }
  2816. else if (status != ERROR_SUCCESS) {
  2817. ClRtlLogPrint(LOG_UNUSUAL,
  2818. "[NMJOIN] The verison of Node %1!ws! could not be validated\n",
  2819. JoinerNodeId);
  2820. goto FnExit;
  2821. }
  2822. //
  2823. //at this point we ready to calculate the cluster version
  2824. //all the node versions are in the registry, the fixups have
  2825. //been made if neccessary
  2826. //
  2827. NmpResetClusterVersion(TRUE);
  2828. //
  2829. // Enable communication to the joiner.
  2830. //
  2831. // This must be the last test that can fail before the join is allowed
  2832. // to proceed.
  2833. //
  2834. status = ClusnetOnlineNodeComm(NmClusnetHandle, joinerNode->NodeId);
  2835. if (status != ERROR_SUCCESS) {
  2836. if (status != ERROR_CLUSTER_NODE_ALREADY_UP) {
  2837. ClRtlLogPrint(LOG_CRITICAL,
  2838. "[NMJOIN] Failed to enable communication for node %1!u!, "
  2839. "status %2!u!\n",
  2840. JoinerNodeId,
  2841. status
  2842. );
  2843. goto FnExit;
  2844. }
  2845. else {
  2846. status = ERROR_SUCCESS;
  2847. }
  2848. }
  2849. //
  2850. // Officially begin the join process
  2851. //
  2852. CL_ASSERT(NmpJoinTimer == 0);
  2853. CL_ASSERT(NmpJoinAbortPending == FALSE);
  2854. CL_ASSERT(NmpJoinerUp == FALSE);
  2855. CL_ASSERT(NmpSponsorNodeId == ClusterInvalidNodeId);
  2856. NmpJoinerNodeId = joinerNode->NodeId;
  2857. NmpSponsorNodeId = sponsorNode->NodeId;
  2858. NmpJoinerOutOfSynch = FALSE;
  2859. NmpJoinSequence = GumGetCurrentSequence(GumUpdateMembership);
  2860. joinerNode->State = ClusterNodeJoining;
  2861. ClusterEvent(
  2862. CLUSTER_EVENT_NODE_JOIN,
  2863. joinerNode
  2864. );
  2865. NmpCleanupIfJoinAborted = TRUE;
  2866. ClRtlLogPrint(LOG_NOISE,
  2867. "[NMJOIN] Node %1!ws! join sequence = %2!u!\n",
  2868. JoinerNodeId,
  2869. NmpJoinSequence
  2870. );
  2871. CL_ASSERT(status == ERROR_SUCCESS);
  2872. FnExit:
  2873. if (lockAcquired) {
  2874. NmpLockedLeaveApi();
  2875. NmpReleaseLock();
  2876. }
  2877. else {
  2878. NmpLeaveApi();
  2879. }
  2880. if (hXsaction != NULL) {
  2881. if (status == ERROR_SUCCESS) {
  2882. DmCommitLocalUpdate(hXsaction);
  2883. }
  2884. else {
  2885. DmAbortLocalUpdate(hXsaction);
  2886. }
  2887. }
  2888. if (joinerNode != NULL) {
  2889. OmDereferenceObject(joinerNode);
  2890. }
  2891. if (sponsorNode != NULL) {
  2892. OmDereferenceObject(sponsorNode);
  2893. }
  2894. if (fakeSuccess) {
  2895. status = ERROR_SUCCESS;
  2896. }
  2897. return(status);
  2898. } // NmpUpdateJoinBegin2
  2899. DWORD
  2900. NmpCreateRpcBindings(
  2901. IN PNM_NODE Node
  2902. )
  2903. {
  2904. DWORD status;
  2905. //
  2906. // Create the default binding for the whole cluster service
  2907. //
  2908. status = ClMsgCreateDefaultRpcBinding(
  2909. Node, &Node->DefaultRpcBindingGeneration);
  2910. if (status != ERROR_SUCCESS) {
  2911. return(status);
  2912. }
  2913. //
  2914. // Create private bindings for the NM's use.
  2915. // We create one for reporting network connectivity and one for
  2916. // performing network failure isolation. The NM uses the
  2917. // default binding for operations on behalf of joining nodes.
  2918. //
  2919. if (Node->ReportRpcBinding != NULL) {
  2920. //
  2921. // Reuse the old binding.
  2922. //
  2923. status = ClMsgVerifyRpcBinding(Node->ReportRpcBinding);
  2924. if (status != ERROR_SUCCESS) {
  2925. ClRtlLogPrint(LOG_CRITICAL,
  2926. "[NM] Failed to verify RPC binding for node %1!u!, "
  2927. "status %2!u!.\n",
  2928. Node->NodeId,
  2929. status
  2930. );
  2931. return(status);
  2932. }
  2933. }
  2934. else {
  2935. //
  2936. // Create a new binding
  2937. //
  2938. status = ClMsgCreateRpcBinding(
  2939. Node,
  2940. &(Node->ReportRpcBinding),
  2941. 0 );
  2942. if (status != ERROR_SUCCESS) {
  2943. ClRtlLogPrint(LOG_CRITICAL,
  2944. "[NM] Failed to create RPC binding for node %1!u!, "
  2945. "status %2!u!.\n",
  2946. Node->NodeId,
  2947. status
  2948. );
  2949. return(status);
  2950. }
  2951. }
  2952. if (Node->IsolateRpcBinding != NULL) {
  2953. //
  2954. // Reuse the old binding.
  2955. //
  2956. status = ClMsgVerifyRpcBinding(Node->IsolateRpcBinding);
  2957. if (status != ERROR_SUCCESS) {
  2958. ClRtlLogPrint(LOG_CRITICAL,
  2959. "[NM] Failed to verify RPC binding for node %1!u!, "
  2960. "status %2!u!.\n",
  2961. Node->NodeId,
  2962. status
  2963. );
  2964. return(status);
  2965. }
  2966. }
  2967. else {
  2968. //
  2969. // Create a new binding
  2970. //
  2971. status = ClMsgCreateRpcBinding(
  2972. Node,
  2973. &(Node->IsolateRpcBinding),
  2974. 0 );
  2975. if (status != ERROR_SUCCESS) {
  2976. ClRtlLogPrint(LOG_CRITICAL,
  2977. "[NM] Failed to create RPC binding for node %1!u!, "
  2978. "status %2!u!.\n",
  2979. Node->NodeId,
  2980. status
  2981. );
  2982. return(status);
  2983. }
  2984. }
  2985. //
  2986. // Call other components to create their private bindings
  2987. //
  2988. status = GumCreateRpcBindings(Node);
  2989. if (status != ERROR_SUCCESS) {
  2990. return(status);
  2991. }
  2992. status = EvCreateRpcBindings(Node);
  2993. if (status != ERROR_SUCCESS) {
  2994. return(status);
  2995. }
  2996. status = FmCreateRpcBindings(Node);
  2997. if (status != ERROR_SUCCESS) {
  2998. return(status);
  2999. }
  3000. return(ERROR_SUCCESS);
  3001. } // NmpCreateRpcBindings
  3002. error_status_t
  3003. s_NmRpcCreateBinding(
  3004. IN handle_t IDL_handle,
  3005. IN DWORD JoinSequence,
  3006. IN LPWSTR JoinerNodeId,
  3007. IN LPWSTR JoinerInterfaceId,
  3008. IN LPWSTR MemberNodeId
  3009. )
  3010. {
  3011. DWORD status;
  3012. NmpAcquireLock();
  3013. ClRtlLogPrint(LOG_NOISE,
  3014. "[NMJOIN] Processing CreateBinding request from joining node %1!ws! for member node %2!ws!\n",
  3015. JoinerNodeId,
  3016. MemberNodeId
  3017. );
  3018. if (NmpLockedEnterApi(NmStateOnlinePending)) {
  3019. PNM_NODE joinerNode = OmReferenceObjectById(
  3020. ObjectTypeNode,
  3021. JoinerNodeId
  3022. );
  3023. if (joinerNode != NULL) {
  3024. if ( (JoinSequence == NmpJoinSequence) &&
  3025. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3026. (NmpSponsorNodeId == NmLocalNodeId) &&
  3027. !NmpJoinAbortPending
  3028. )
  3029. {
  3030. PNM_NODE memberNode;
  3031. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3032. CL_ASSERT(NmpJoinerUp == FALSE);
  3033. CL_ASSERT(NmpJoinTimer != 0);
  3034. //
  3035. // Suspend the join timer while we are working on
  3036. // behalf of the joiner. This precludes an abort
  3037. // from occuring as well.
  3038. //
  3039. NmpJoinTimer = 0;
  3040. memberNode = OmReferenceObjectById(
  3041. ObjectTypeNode,
  3042. MemberNodeId
  3043. );
  3044. if (memberNode != NULL) {
  3045. PNM_INTERFACE netInterface = OmReferenceObjectById(
  3046. ObjectTypeNetInterface,
  3047. JoinerInterfaceId
  3048. );
  3049. if (netInterface != NULL) {
  3050. if (memberNode == NmLocalNode) {
  3051. status = NmpCreateJoinerRpcBindings(
  3052. joinerNode,
  3053. netInterface
  3054. );
  3055. }
  3056. else {
  3057. if (NM_NODE_UP(memberNode)) {
  3058. DWORD joinSequence = NmpJoinSequence;
  3059. RPC_BINDING_HANDLE binding =
  3060. Session[memberNode->NodeId];
  3061. CL_ASSERT(binding != NULL);
  3062. NmpReleaseLock();
  3063. NmStartRpc(memberNode->NodeId);
  3064. status = NmRpcCreateJoinerBinding(
  3065. binding,
  3066. joinSequence,
  3067. JoinerNodeId,
  3068. JoinerInterfaceId
  3069. );
  3070. NmEndRpc(memberNode->NodeId);
  3071. if(status != RPC_S_OK) {
  3072. NmDumpRpcExtErrorInfo(status);
  3073. }
  3074. NmpAcquireLock();
  3075. }
  3076. else {
  3077. status = ERROR_CLUSTER_NODE_DOWN;
  3078. ClRtlLogPrint(LOG_UNUSUAL,
  3079. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because member node %2!ws! is down.\n",
  3080. JoinerNodeId,
  3081. MemberNodeId
  3082. );
  3083. }
  3084. }
  3085. OmDereferenceObject(netInterface);
  3086. }
  3087. else {
  3088. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  3089. ClRtlLogPrint(LOG_CRITICAL,
  3090. "[NMJOIN] Can't create binding for joining node %1!ws! - interface %2!ws! doesn't exist.\n",
  3091. JoinerNodeId,
  3092. JoinerInterfaceId
  3093. );
  3094. }
  3095. OmDereferenceObject(memberNode);
  3096. }
  3097. else {
  3098. status = ERROR_CLUSTER_NODE_NOT_FOUND;
  3099. ClRtlLogPrint(LOG_UNUSUAL,
  3100. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because member node %2!ws! does not exist\n",
  3101. JoinerNodeId,
  3102. MemberNodeId
  3103. );
  3104. }
  3105. //
  3106. // Verify that the join is still in progress
  3107. //
  3108. if ( (JoinSequence == NmpJoinSequence) &&
  3109. (NmpJoinerNodeId == joinerNode->NodeId)
  3110. )
  3111. {
  3112. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3113. CL_ASSERT(NmpJoinerUp == FALSE);
  3114. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  3115. CL_ASSERT(NmpJoinTimer == 0);
  3116. CL_ASSERT(NmpJoinAbortPending == FALSE);
  3117. //
  3118. // Restart the join timer.
  3119. //
  3120. NmpJoinTimer = NM_JOIN_TIMEOUT;
  3121. }
  3122. else {
  3123. status = ERROR_CLUSTER_JOIN_ABORTED;
  3124. ClRtlLogPrint(LOG_UNUSUAL,
  3125. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the join was aborted.\n",
  3126. JoinerNodeId
  3127. );
  3128. }
  3129. }
  3130. else {
  3131. status = ERROR_CLUSTER_JOIN_ABORTED;
  3132. ClRtlLogPrint(LOG_UNUSUAL,
  3133. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the join was aborted.\n",
  3134. JoinerNodeId
  3135. );
  3136. }
  3137. OmDereferenceObject(joinerNode);
  3138. }
  3139. else {
  3140. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3141. ClRtlLogPrint(LOG_UNUSUAL,
  3142. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  3143. JoinerNodeId
  3144. );
  3145. }
  3146. NmpLockedLeaveApi();
  3147. }
  3148. else {
  3149. status = ERROR_NODE_NOT_AVAILABLE;
  3150. ClRtlLogPrint(LOG_NOISE,
  3151. "[NMJOIN] Not in valid state to process the request.\n"
  3152. );
  3153. }
  3154. NmpReleaseLock();
  3155. return(status);
  3156. } // s_NmRpcCreateBinding
  3157. error_status_t
  3158. s_NmRpcCreateJoinerBinding(
  3159. IN handle_t IDL_handle,
  3160. IN DWORD JoinSequence,
  3161. IN LPWSTR JoinerNodeId,
  3162. IN LPWSTR JoinerInterfaceId
  3163. )
  3164. /*++
  3165. Notes:
  3166. The sponsor is responsible for aborting the join on failure.
  3167. --*/
  3168. {
  3169. DWORD status;
  3170. NmpAcquireLock();
  3171. ClRtlLogPrint(LOG_NOISE,
  3172. "[NMJOIN] Processing CreateBinding request for joining node %1!ws!.\n",
  3173. JoinerNodeId
  3174. );
  3175. if (NmpLockedEnterApi(NmStateOnline)) {
  3176. PNM_NODE joinerNode = OmReferenceObjectById(
  3177. ObjectTypeNode,
  3178. JoinerNodeId
  3179. );
  3180. if (joinerNode != NULL) {
  3181. PNM_INTERFACE netInterface = OmReferenceObjectById(
  3182. ObjectTypeNetInterface,
  3183. JoinerInterfaceId
  3184. );
  3185. if (netInterface != NULL) {
  3186. //
  3187. // Verify that a join is still in progress.
  3188. //
  3189. if ( (JoinSequence == NmpJoinSequence) &&
  3190. (NmpJoinerNodeId == joinerNode->NodeId)
  3191. )
  3192. {
  3193. status = NmpCreateJoinerRpcBindings(
  3194. joinerNode,
  3195. netInterface
  3196. );
  3197. if (status != ERROR_SUCCESS) {
  3198. WCHAR errorString[12];
  3199. wsprintfW(&(errorString[0]), L"%u", status);
  3200. CsLogEvent3(
  3201. LOG_UNUSUAL,
  3202. NM_EVENT_JOINER_BIND_FAILED,
  3203. OmObjectName(joinerNode),
  3204. OmObjectName(netInterface->Network),
  3205. errorString
  3206. );
  3207. }
  3208. }
  3209. else {
  3210. status = ERROR_CLUSTER_JOIN_ABORTED;
  3211. ClRtlLogPrint(LOG_UNUSUAL,
  3212. "[NMJOIN] Failing create bindings for joining node %1!ws! because the join was aborted\n",
  3213. JoinerNodeId
  3214. );
  3215. }
  3216. OmDereferenceObject(netInterface);
  3217. }
  3218. else {
  3219. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  3220. ClRtlLogPrint(LOG_CRITICAL,
  3221. "[NMJOIN] Can't create binding for joining node %1!ws! - no corresponding interface for joiner interface %2!ws!.\n",
  3222. JoinerNodeId,
  3223. JoinerInterfaceId
  3224. );
  3225. }
  3226. OmDereferenceObject(joinerNode);
  3227. }
  3228. else {
  3229. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3230. ClRtlLogPrint(LOG_UNUSUAL,
  3231. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  3232. JoinerNodeId
  3233. );
  3234. }
  3235. NmpLockedLeaveApi();
  3236. }
  3237. else {
  3238. status = ERROR_NODE_NOT_AVAILABLE;
  3239. ClRtlLogPrint(LOG_NOISE,
  3240. "[NMJOIN] Not in valid state to process the request.\n"
  3241. );
  3242. }
  3243. NmpReleaseLock();
  3244. return(status);
  3245. } // s_NmRpcCreateJoinerBinding
  3246. DWORD
  3247. NmpCreateJoinerRpcBindings(
  3248. IN PNM_NODE JoinerNode,
  3249. IN PNM_INTERFACE JoinerInterface
  3250. )
  3251. /*++
  3252. Notes:
  3253. Called with the NmpLock held.
  3254. --*/
  3255. {
  3256. DWORD status;
  3257. PNM_NETWORK network = JoinerInterface->Network;
  3258. CL_NODE_ID joinerNodeId = JoinerNode->NodeId;
  3259. CL_ASSERT(JoinerNode->NodeId == NmpJoinerNodeId);
  3260. CL_ASSERT(JoinerNode->State == ClusterNodeJoining);
  3261. ClRtlLogPrint(LOG_NOISE,
  3262. "[NMJOIN] Creating bindings for joining node %1!u! using network %2!ws!\n",
  3263. joinerNodeId,
  3264. OmObjectName(JoinerInterface->Network)
  3265. );
  3266. //
  3267. // Make sure that this node has an interface on the target network.
  3268. //
  3269. if (NmpIsNetworkForInternalUse(network)) {
  3270. if (network->LocalInterface != NULL) {
  3271. if ( NmpIsInterfaceRegistered(JoinerInterface) &&
  3272. NmpIsInterfaceRegistered(network->LocalInterface)
  3273. )
  3274. {
  3275. status = NmpSetNodeInterfacePriority(
  3276. JoinerNode,
  3277. 0xFFFFFFFF,
  3278. JoinerInterface,
  3279. 1
  3280. );
  3281. if (status == ERROR_SUCCESS) {
  3282. PNM_INTERFACE localInterface = network->LocalInterface;
  3283. //
  3284. // Create intracluster RPC bindings for the petitioner.
  3285. // The MM relies on these to perform the join.
  3286. //
  3287. OmReferenceObject(localInterface);
  3288. OmReferenceObject(JoinerNode);
  3289. NmpReleaseLock();
  3290. status = NmpCreateRpcBindings(JoinerNode);
  3291. NmpAcquireLock();
  3292. if (status != ERROR_SUCCESS) {
  3293. ClRtlLogPrint(LOG_UNUSUAL,
  3294. "[NMJOIN] Unable to create RPC binding for "
  3295. "joining node %1!u!, status %2!u!.\n",
  3296. joinerNodeId,
  3297. status
  3298. );
  3299. }
  3300. OmDereferenceObject(JoinerNode);
  3301. OmDereferenceObject(localInterface);
  3302. }
  3303. else {
  3304. ClRtlLogPrint(LOG_CRITICAL,
  3305. "[NMJOIN] Failed to set interface priority for "
  3306. "network %1!ws! (%2!ws!), status %3!u!\n",
  3307. OmObjectId(network),
  3308. OmObjectName(network),
  3309. status
  3310. );
  3311. }
  3312. }
  3313. else {
  3314. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  3315. }
  3316. }
  3317. else {
  3318. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  3319. }
  3320. }
  3321. else {
  3322. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  3323. }
  3324. if (status !=ERROR_SUCCESS) {
  3325. ClRtlLogPrint(LOG_CRITICAL,
  3326. "[NMJOIN] Failed to create binding for joining node %1!u! "
  3327. "on network %2!ws! (%3!ws!), status %4!u!\n",
  3328. joinerNodeId,
  3329. OmObjectId(network),
  3330. OmObjectName(network),
  3331. status
  3332. );
  3333. }
  3334. return(status);
  3335. } // NmpCreateJoinerRpcBinding
  3336. error_status_t
  3337. s_NmRpcPetitionForMembership(
  3338. IN handle_t IDL_handle,
  3339. IN DWORD JoinSequence,
  3340. IN LPCWSTR JoinerNodeId
  3341. )
  3342. /*++
  3343. Routine Description:
  3344. Server side of a join petition.
  3345. Arguments:
  3346. IDL_handle - RPC binding handle, not used.
  3347. JoinSequence - Supplies the sequence returned from NmRpcJoinBegin
  3348. JoinerNodeId - Supplies the ID of the node attempting to join.
  3349. Return Value:
  3350. ERROR_SUCCESS if successful
  3351. Win32 error otherwise.
  3352. --*/
  3353. {
  3354. DWORD status;
  3355. PNM_NODE joinerNode;
  3356. #ifdef CLUSTER_TESTPOINT
  3357. TESTPT(TestpointJoinFailPetition) {
  3358. return(999999);
  3359. }
  3360. #endif
  3361. NmpAcquireLock();
  3362. ClRtlLogPrint(LOG_UNUSUAL,
  3363. "[NMJOIN] Processing petition to join from node %1!ws!.\n",
  3364. JoinerNodeId
  3365. );
  3366. if (NmpLockedEnterApi(NmStateOnline)) {
  3367. joinerNode = OmReferenceObjectById(ObjectTypeNode, JoinerNodeId);
  3368. if (joinerNode != NULL) {
  3369. //
  3370. // Verify that the join is still in progress
  3371. //
  3372. //
  3373. // DavidDio 6/13/2000
  3374. // There is a small window where a begin join update can
  3375. // succeed during a regroup, but the regroup ends before
  3376. // the joining node petitions to join. In this case, the
  3377. // node will be marked out of sync. Aborting the join
  3378. // after MMJoin() is much more heavyweight than before,
  3379. // so check for this condition now. (Bug 125778).
  3380. //
  3381. if ( (JoinSequence == NmpJoinSequence) &&
  3382. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3383. (NmpSponsorNodeId == NmLocalNodeId) &&
  3384. (!NmpJoinAbortPending) &&
  3385. (!NmpJoinerOutOfSynch)
  3386. )
  3387. {
  3388. ClRtlLogPrint(LOG_UNUSUAL, "[NMJOIN] Performing join.\n");
  3389. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3390. CL_ASSERT(NmpJoinerUp == FALSE);
  3391. CL_ASSERT(NmpJoinTimer != 0);
  3392. //
  3393. // Call the MM to join this node to the cluster membership.
  3394. // Disable the join timer. Once the node becomes an active
  3395. // member, we won't need it anymore.
  3396. //
  3397. NmpJoinTimer = 0;
  3398. NmpReleaseLock();
  3399. status = MMJoin(
  3400. joinerNode->NodeId,
  3401. NM_CLOCK_PERIOD,
  3402. NM_SEND_HB_RATE,
  3403. NM_RECV_HB_RATE,
  3404. NM_MM_JOIN_TIMEOUT
  3405. );
  3406. NmpAcquireLock();
  3407. //
  3408. // Verify that the join is still in progress
  3409. //
  3410. if ( (JoinSequence == NmpJoinSequence) &&
  3411. (NmpJoinerNodeId == joinerNode->NodeId)
  3412. )
  3413. {
  3414. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  3415. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3416. CL_ASSERT(NmpJoinTimer == 0);
  3417. CL_ASSERT(NmpJoinAbortPending == FALSE);
  3418. // GorN 3/22/2000
  3419. // We hit a case when MMJoin has succeeded after a regroup
  3420. // that killed one of the nodes (not joiner and not sponsor)
  3421. // thus leaving the joiner out of sync
  3422. // We need to abourt the join in this case too
  3423. if (status != MM_OK || NmpJoinerOutOfSynch) {
  3424. status = MMMapStatusToDosError(status);
  3425. if (NmpJoinerOutOfSynch) {
  3426. status = ERROR_CLUSTER_JOIN_ABORTED;
  3427. }
  3428. //
  3429. // Abort the join
  3430. //
  3431. ClRtlLogPrint(LOG_UNUSUAL,
  3432. "[NMJOIN] Petition to join by node %1!ws! failed, status %2!u!.\n",
  3433. JoinerNodeId,
  3434. status
  3435. );
  3436. //
  3437. // If MMJoin was unsuccessful it initiates a banishing
  3438. // regroup. This regroup will deliver node down events
  3439. // on all nodes that saw hb's from the joiner.
  3440. //
  3441. // Calling MMBlockIfRegroupIsInProgress here will guarantee that
  3442. // Phase2 cleanup is complete on all nodes, before we
  3443. // call NmpJoinAbort.
  3444. //
  3445. NmpReleaseLock();
  3446. MMBlockIfRegroupIsInProgress();
  3447. NmpAcquireLock();
  3448. NmpJoinAbort(status, joinerNode);
  3449. }
  3450. else {
  3451. NmpSuccessfulMMJoin = TRUE;
  3452. ClRtlLogPrint(LOG_UNUSUAL,
  3453. "[NMJOIN] Petition to join by node %1!ws! succeeded.\n",
  3454. JoinerNodeId
  3455. );
  3456. }
  3457. #ifdef MM_IN_CLUSNET
  3458. if (status == MM_OK) {
  3459. status = NmJoinNodeToCluster(joinerNodeId);
  3460. if (status != ERROR_SUCCESS) {
  3461. DWORD clusnetStatus;
  3462. ClRtlLogPrint(LOG_UNUSUAL,
  3463. "[NMJOIN] Join of node %1!ws! failed, status %2!u!.\n",
  3464. JoinerNodeId,
  3465. status
  3466. );
  3467. CL_LOGFAILURE( status );
  3468. NmpReleaseLock();
  3469. MMEject(joinerNodeId);
  3470. NmpAcquireLock();
  3471. clusnetStatus = ClusnetOfflineNodeComm(
  3472. NmClusnetHandle,
  3473. joinerNodeId
  3474. );
  3475. CL_ASSERT(
  3476. (status == ERROR_SUCCESS) ||
  3477. (status == ERROR_CLUSTER_NODE_ALREADY_DOWN
  3478. );
  3479. }
  3480. else {
  3481. ClRtlLogPrint(LOG_UNUSUAL,
  3482. "[NMJOIN] Join completed successfully.\n"
  3483. );
  3484. }
  3485. }
  3486. #endif // MM_IN_CLUSNET
  3487. }
  3488. else {
  3489. status = ERROR_CLUSTER_JOIN_ABORTED;
  3490. ClRtlLogPrint(LOG_UNUSUAL,
  3491. "[NMJOIN] Petition to join by node %1!ws! failed because the join was aborted.\n",
  3492. JoinerNodeId
  3493. );
  3494. }
  3495. }
  3496. else {
  3497. status = ERROR_CLUSTER_JOIN_ABORTED;
  3498. ClRtlLogPrint(LOG_UNUSUAL,
  3499. "[NMJOIN] Petition by node %1!ws! failed because the join was aborted\n",
  3500. JoinerNodeId
  3501. );
  3502. }
  3503. OmDereferenceObject(joinerNode);
  3504. }
  3505. else {
  3506. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3507. ClRtlLogPrint(LOG_UNUSUAL,
  3508. "[NMJOIN] Petition to join by %1!ws! failed because the node is not a cluster member\n",
  3509. JoinerNodeId
  3510. );
  3511. }
  3512. NmpLockedLeaveApi();
  3513. }
  3514. else {
  3515. status = ERROR_NODE_NOT_AVAILABLE;
  3516. ClRtlLogPrint(LOG_NOISE,
  3517. "[NMJOIN] Not in valid state to process the request.\n"
  3518. );
  3519. }
  3520. NmpReleaseLock();
  3521. return(status);
  3522. } // s_NmRpcPetitionForMembership
  3523. error_status_t
  3524. s_NmRpcGetLeaderNodeId(
  3525. IN handle_t IDL_handle,
  3526. IN DWORD JoinSequence, OPTIONAL
  3527. IN LPWSTR JoinerNodeId, OPTIONAL
  3528. OUT LPDWORD LeaderNodeId
  3529. )
  3530. {
  3531. DWORD status = ERROR_SUCCESS;
  3532. PNM_NODE joinerNode = NULL;
  3533. NmpAcquireLock();
  3534. if (NmpLockedEnterApi(NmStateOnline)){
  3535. joinerNode = OmReferenceObjectById(
  3536. ObjectTypeNode,
  3537. JoinerNodeId
  3538. );
  3539. if (joinerNode != NULL) {
  3540. if ( (JoinSequence == NmpJoinSequence) &&
  3541. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3542. (NmpSponsorNodeId == NmLocalNodeId) &&
  3543. !NmpJoinAbortPending
  3544. )
  3545. {
  3546. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3547. *LeaderNodeId = NmpLeaderNodeId;
  3548. }
  3549. else {
  3550. status = ERROR_CLUSTER_JOIN_ABORTED;
  3551. ClRtlLogPrint(LOG_UNUSUAL,
  3552. "[NMJOIN] GetLeaderNodeId call for joining node %1!ws! failed because the join was aborted.\n",
  3553. JoinerNodeId
  3554. );
  3555. }
  3556. OmDereferenceObject(joinerNode);
  3557. }
  3558. else {
  3559. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3560. ClRtlLogPrint(LOG_UNUSUAL,
  3561. "[NMJOIN] GetLeaderNodeId call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  3562. JoinerNodeId
  3563. );
  3564. }
  3565. NmpLockedLeaveApi();
  3566. }
  3567. else {
  3568. status = ERROR_NODE_NOT_AVAILABLE;
  3569. ClRtlLogPrint(LOG_NOISE,
  3570. "[NMJOIN] Not in valid state to process GetLeaderNodeId request.\n"
  3571. );
  3572. }
  3573. NmpReleaseLock();
  3574. return(status);
  3575. } // s_NmRpcGetLeaderNodeId
  3576. DWORD
  3577. NmpUpdateJoinComplete(
  3578. IN PNM_JOIN_UPDATE JoinUpdate
  3579. )
  3580. {
  3581. DWORD status;
  3582. NmpAcquireLock();
  3583. ClRtlLogPrint(LOG_NOISE,
  3584. "[NMJOIN] Processing JoinComplete update from node %1!ws!\n",
  3585. JoinUpdate->NodeId
  3586. );
  3587. if (NmpLockedEnterApi(NmStateOnline)) {
  3588. PNM_NODE joinerNode;
  3589. LPWSTR joinerIdString = JoinUpdate->NodeId;
  3590. joinerNode = OmReferenceObjectById(ObjectTypeNode, joinerIdString);
  3591. if (joinerNode != NULL) {
  3592. CL_ASSERT(joinerNode != NmLocalNode);
  3593. //
  3594. // Verify that the join is still in progress and nothing has
  3595. // changed.
  3596. //
  3597. if ( (JoinUpdate->JoinSequence == NmpJoinSequence) &&
  3598. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3599. (joinerNode->State == ClusterNodeJoining) &&
  3600. NmpJoinerUp &&
  3601. !NmpJoinerOutOfSynch
  3602. )
  3603. {
  3604. PNM_INTERFACE netInterface;
  3605. PNM_NETWORK network;
  3606. PLIST_ENTRY ifEntry;
  3607. NmpJoinerNodeId = ClusterInvalidNodeId;
  3608. NmpSponsorNodeId = ClusterInvalidNodeId;
  3609. NmpJoinTimer = 0;
  3610. NmpJoinAbortPending = FALSE;
  3611. NmpJoinSequence = 0;
  3612. NmpJoinerUp = FALSE;
  3613. if (JoinUpdate->IsPaused != 0) {
  3614. //
  3615. // This node is coming up in the paused state.
  3616. //
  3617. joinerNode->State = ClusterNodePaused;
  3618. } else {
  3619. joinerNode->State = ClusterNodeUp;
  3620. }
  3621. joinerNode->ExtendedState = ClusterNodeJoining;
  3622. ClusterEvent(CLUSTER_EVENT_NODE_UP, (PVOID)joinerNode);
  3623. //
  3624. // Reset the interface priorities for this node.
  3625. //
  3626. for (ifEntry = joinerNode->InterfaceList.Flink;
  3627. ifEntry != &joinerNode->InterfaceList;
  3628. ifEntry = ifEntry->Flink
  3629. )
  3630. {
  3631. netInterface = CONTAINING_RECORD(
  3632. ifEntry,
  3633. NM_INTERFACE,
  3634. NodeLinkage
  3635. );
  3636. network = netInterface->Network;
  3637. if ( NmpIsNetworkForInternalUse(network) &&
  3638. NmpIsInterfaceRegistered(netInterface)
  3639. )
  3640. {
  3641. status = ClusnetSetInterfacePriority(
  3642. NmClusnetHandle,
  3643. joinerNode->NodeId,
  3644. network->ShortId,
  3645. 0
  3646. );
  3647. CL_ASSERT(status == ERROR_SUCCESS);
  3648. }
  3649. }
  3650. status = ERROR_SUCCESS;
  3651. }
  3652. else {
  3653. status = ERROR_CLUSTER_JOIN_ABORTED;
  3654. ClRtlLogPrint(LOG_UNUSUAL,
  3655. "[NMJOIN] Join of node %1!ws! cannot complete because the join was aborted\n",
  3656. joinerIdString
  3657. );
  3658. }
  3659. OmDereferenceObject(joinerNode);
  3660. }
  3661. else {
  3662. status =ERROR_CLUSTER_NODE_NOT_MEMBER;
  3663. ClRtlLogPrint(LOG_UNUSUAL,
  3664. "[NMJOIN] Join of node %1!ws! cannot complete because the node is not a cluster member.\n",
  3665. joinerIdString
  3666. );
  3667. }
  3668. NmpLockedLeaveApi();
  3669. }
  3670. else {
  3671. status = ERROR_NODE_NOT_AVAILABLE;
  3672. ClRtlLogPrint(LOG_UNUSUAL,
  3673. "[NMJOIN] Not in valid state to process JoinComplete update.\n"
  3674. );
  3675. }
  3676. NmpReleaseLock();
  3677. // DavidDio 10/27/2000
  3678. // Bug 213781: NmpUpdateJoinComplete must always return ERROR_SUCCESS.
  3679. // Otherwise, there is a small window whereby GUM sequence numbers on
  3680. // remaining cluster nodes can fall out of sync. If the join should
  3681. // be aborted, return ERROR_SUCCESS but poison the joiner out-of-band.
  3682. if (status != ERROR_SUCCESS) {
  3683. DWORD dwJoinerId;
  3684. if (JoinUpdate->NodeId != NULL) {
  3685. dwJoinerId = wcstoul(JoinUpdate->NodeId, NULL, 10);
  3686. ClRtlLogPrint(LOG_UNUSUAL,
  3687. "[NMJOIN] Join of node %1!u! failed with status %2!u!. Initiating banishment.\n",
  3688. dwJoinerId,
  3689. status
  3690. );
  3691. NmAdviseNodeFailure(dwJoinerId, status);
  3692. } else {
  3693. dwJoinerId = ClusterInvalidNodeId;
  3694. ClRtlLogPrint(LOG_UNUSUAL,
  3695. "[NMJOIN] Join of node %1!ws! failed with status %2!u!. Cannot initiate banishment as node id is unknown.\n",
  3696. dwJoinerId,
  3697. status
  3698. );
  3699. }
  3700. }
  3701. return(ERROR_SUCCESS);
  3702. } // NmpUpdateJoinComplete
  3703. DWORD
  3704. NmpUpdateJoinAbort(
  3705. IN BOOL SourceNode,
  3706. IN LPDWORD JoinSequence,
  3707. IN LPWSTR JoinerNodeId
  3708. )
  3709. /*++
  3710. Notes:
  3711. --*/
  3712. {
  3713. DWORD status = ERROR_SUCCESS;
  3714. NmpAcquireLock();
  3715. ClRtlLogPrint(LOG_NOISE,
  3716. "[NMJOIN] Received update to abort join sequence %1!u! (joiner id %2!ws!).\n",
  3717. *JoinSequence,
  3718. JoinerNodeId
  3719. );
  3720. if (NmpLockedEnterApi(NmStateOnline)) {
  3721. PNM_NODE joinerNode = OmReferenceObjectById(
  3722. ObjectTypeNode,
  3723. JoinerNodeId
  3724. );
  3725. if (joinerNode != NULL) {
  3726. //
  3727. // Check if the specified join is still in progress.
  3728. //
  3729. if ( (*JoinSequence == NmpJoinSequence) &&
  3730. (NmpJoinerNodeId == joinerNode->NodeId)
  3731. )
  3732. {
  3733. CL_ASSERT(NmpSponsorNodeId != ClusterInvalidNodeId);
  3734. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3735. //
  3736. // Assumption:
  3737. //
  3738. // An abort cannot occur during the MM join process.
  3739. // If the joiner is not already up, it cannot come up
  3740. // during the abort processing.
  3741. //
  3742. // Assert condition may not be true with the current MM join code.
  3743. // Some nodes might have got monitor node and set
  3744. // NmpJoinerUp state to TRUE by the time the sponsor issued
  3745. // an abort update
  3746. //
  3747. //CL_ASSERT(NmpJoinerUp == FALSE);
  3748. if (NmpCleanupIfJoinAborted) {
  3749. NmpCleanupIfJoinAborted = FALSE;
  3750. ClRtlLogPrint(LOG_UNUSUAL,
  3751. "[NMJOIN] Issuing a node down event for %1!u!.\n",
  3752. joinerNode->NodeId
  3753. );
  3754. //
  3755. // This node is not yet active in the membership.
  3756. // Call the node down event handler to finish the abort.
  3757. //
  3758. //
  3759. // We will not call NmpMsgCleanup1 and NmpMsgCleanup2,
  3760. // because we cannot guarantee that they will get executed
  3761. // in a barrier style fashion
  3762. //
  3763. // !!! Lock will be acquired by NmpNodeDownEventHandler
  3764. // second time. Is it OK?
  3765. //
  3766. NmpNodeDownEventHandler(joinerNode);
  3767. } else {
  3768. ClRtlLogPrint(LOG_UNUSUAL,
  3769. "[NMJOIN] Node down was already issued for %1!u!.\n",
  3770. joinerNode->NodeId
  3771. );
  3772. }
  3773. }
  3774. else {
  3775. ClRtlLogPrint(LOG_UNUSUAL,
  3776. "[NMJOIN] Ignoring old join abort update with sequence %1!u!.\n",
  3777. *JoinSequence
  3778. );
  3779. }
  3780. OmDereferenceObject(joinerNode);
  3781. status = ERROR_SUCCESS;
  3782. }
  3783. else {
  3784. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3785. ClRtlLogPrint(LOG_UNUSUAL,
  3786. "[NMJOIN] Join of node %1!ws! cannot be aborted because the node is not a cluster member.\n",
  3787. JoinerNodeId
  3788. );
  3789. }
  3790. NmpLockedLeaveApi();
  3791. }
  3792. else {
  3793. status = ERROR_NODE_NOT_AVAILABLE;
  3794. ClRtlLogPrint(LOG_UNUSUAL,
  3795. "[NMJOIN] Not in valid state to process JoinAbort update.\n"
  3796. );
  3797. }
  3798. NmpReleaseLock();
  3799. return(status);
  3800. } // NmpUpdateJoinAbort
  3801. VOID
  3802. NmpJoinAbort(
  3803. DWORD AbortStatus,
  3804. PNM_NODE JoinerNode
  3805. )
  3806. /*++
  3807. Routine Description:
  3808. Issues a JoinAbort update.
  3809. Notes:
  3810. Called with the NmpLock held.
  3811. --*/
  3812. {
  3813. DWORD status;
  3814. DWORD joinSequence = NmpJoinSequence;
  3815. WCHAR errorString[12];
  3816. // GorN 10/31/2001 #488486
  3817. // By the time we get to the NmpJoinAbort code
  3818. // we can have a node down event processed
  3819. // that clears up NmpJoinerNodeId.
  3820. // In this case just log the message and bail out
  3821. // CL_ASSERT(NmpJoinerNodeId != ClusterInvalidNodeId);
  3822. // CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  3823. // CL_ASSERT(JoinerNode->State == ClusterNodeJoining);
  3824. if (AbortStatus == ERROR_TIMEOUT) {
  3825. wsprintfW(&(errorString[0]), L"%u", AbortStatus);
  3826. CsLogEvent1(
  3827. LOG_CRITICAL,
  3828. NM_EVENT_JOIN_TIMED_OUT,
  3829. OmObjectName(JoinerNode)
  3830. );
  3831. }
  3832. else {
  3833. wsprintfW(&(errorString[0]), L"%u", AbortStatus);
  3834. CsLogEvent2(
  3835. LOG_CRITICAL,
  3836. NM_EVENT_SPONSOR_JOIN_ABORTED,
  3837. OmObjectName(JoinerNode),
  3838. errorString
  3839. );
  3840. }
  3841. //
  3842. // Assumption:
  3843. //
  3844. // An abort cannot occur during the MM join process. If the joiner
  3845. // is not already up, it cannot come up during the abort processing.
  3846. //
  3847. if (NmpSuccessfulMMJoin == FALSE) {
  3848. //
  3849. // The joining node has not become active yet. Issue
  3850. // an abort update.
  3851. //
  3852. joinSequence = NmpJoinSequence;
  3853. ClRtlLogPrint(LOG_NOISE,
  3854. "[NMJOIN] Issuing update to abort join of node %1!u!.\n",
  3855. NmpJoinerNodeId
  3856. );
  3857. NmpReleaseLock();
  3858. status = GumSendUpdateEx(
  3859. GumUpdateMembership,
  3860. NmUpdateJoinAbort,
  3861. 2,
  3862. sizeof(DWORD),
  3863. &joinSequence,
  3864. NM_WCSLEN(OmObjectId(JoinerNode)),
  3865. OmObjectId(JoinerNode)
  3866. );
  3867. NmpAcquireLock();
  3868. }
  3869. else {
  3870. //
  3871. // The joining node is already active in the membership.
  3872. // Ask the MM to kick it out. The node down event will
  3873. // finish the abort process.
  3874. //
  3875. CL_NODE_ID joinerNodeId = NmpJoinerNodeId;
  3876. ClRtlLogPrint(LOG_NOISE,
  3877. "[NMJOIN] Ejecting joining node %1!u! from the cluster membership.\n",
  3878. NmpJoinerNodeId
  3879. );
  3880. NmpReleaseLock();
  3881. status = MMEject(joinerNodeId);
  3882. NmpAcquireLock();
  3883. }
  3884. if (status != MM_OK) {
  3885. status = MMMapStatusToDosError(status);
  3886. ClRtlLogPrint(LOG_UNUSUAL,
  3887. "[NMJOIN] Update to abort join of node %1!u! failed, status %2!u!\n",
  3888. JoinerNode->NodeId,
  3889. status
  3890. );
  3891. //
  3892. // If the join is still pending, and this is the sponsor node,
  3893. // force a timeout to retry the abort. If we aren't the sponsor,
  3894. // there isn't much we can do.
  3895. //
  3896. if ( (joinSequence == NmpJoinSequence) &&
  3897. (NmpJoinerNodeId == JoinerNode->NodeId) &&
  3898. (NmpSponsorNodeId == NmLocalNodeId)
  3899. )
  3900. {
  3901. NmpJoinTimer = 1;
  3902. NmpJoinAbortPending = FALSE;
  3903. }
  3904. }
  3905. return;
  3906. } // NmpJoinAbort
  3907. VOID
  3908. NmpJoinAbortWorker(
  3909. IN PCLRTL_WORK_ITEM WorkItem,
  3910. IN DWORD Status,
  3911. IN DWORD BytesTransferred,
  3912. IN ULONG_PTR IoContext
  3913. )
  3914. /*++
  3915. Routine Description:
  3916. Worker thread for aborting a join.
  3917. --*/
  3918. {
  3919. DWORD joinSequence = PtrToUlong(WorkItem->Context);
  3920. NmpAcquireLock();
  3921. //
  3922. // The active thread count was bumped up when this item was scheduled.
  3923. // No need to call NmpEnterApi().
  3924. //
  3925. //
  3926. // If the join is still pending, begin the abort process.
  3927. //
  3928. if ( (joinSequence == NmpJoinSequence) &&
  3929. (NmpJoinerNodeId != ClusterInvalidNodeId) &&
  3930. NmpJoinAbortPending
  3931. )
  3932. {
  3933. PNM_NODE joinerNode = NmpIdArray[NmpJoinerNodeId];
  3934. if (joinerNode != NULL) {
  3935. ClRtlLogPrint(LOG_NOISE,
  3936. "[NMJOIN] Worker thread initiating abort of joining node %1!u!\n",
  3937. NmpJoinerNodeId
  3938. );
  3939. NmpJoinAbort(ERROR_TIMEOUT, joinerNode);
  3940. }
  3941. else {
  3942. CL_ASSERT(joinerNode != NULL);
  3943. }
  3944. }
  3945. else {
  3946. ClRtlLogPrint(LOG_NOISE,
  3947. "[NMJOIN] Skipping join abort, sequence to abort %1!u!, current join sequence %2!u!, "
  3948. "joiner node: %3!u! sponsor node: %4!u!\n",
  3949. joinSequence,
  3950. NmpJoinSequence,
  3951. NmpJoinerNodeId,
  3952. NmpSponsorNodeId
  3953. );
  3954. }
  3955. NmpLockedLeaveApi();
  3956. NmpReleaseLock();
  3957. LocalFree(WorkItem);
  3958. return;
  3959. } // NmpJoinAbortWorker
  3960. VOID
  3961. NmpJoinTimerTick(
  3962. IN DWORD MsTickInterval
  3963. )
  3964. /*++
  3965. Notes:
  3966. Called with NmpLock held.
  3967. --*/
  3968. {
  3969. if (NmpLockedEnterApi(NmStateOnline)) {
  3970. //
  3971. // If we are sponsoring a join, update the timer.
  3972. //
  3973. if ( (NmpJoinerNodeId != ClusterInvalidNodeId) &&
  3974. (NmpSponsorNodeId == NmLocalNodeId) &&
  3975. !NmpJoinAbortPending &&
  3976. (NmpJoinTimer != 0)
  3977. )
  3978. {
  3979. //ClRtlLogPrint(LOG_NOISE,
  3980. // "[NMJOIN] Timer tick (%1!u! ms)\n",
  3981. // Interval
  3982. // );
  3983. if (NmpJoinTimer > MsTickInterval) {
  3984. NmpJoinTimer -= MsTickInterval;
  3985. }
  3986. else {
  3987. //
  3988. // The join has timed out. Schedule a worker thread to
  3989. // carry out the abort process.
  3990. //
  3991. PCLRTL_WORK_ITEM workItem;
  3992. ClRtlLogPrint(LOG_UNUSUAL,
  3993. "[NMJOIN] Join of node %1!u! has timed out.\n",
  3994. NmpJoinerNodeId
  3995. );
  3996. workItem = LocalAlloc(LMEM_FIXED, sizeof(CLRTL_WORK_ITEM));
  3997. if (workItem != NULL) {
  3998. DWORD status;
  3999. ClRtlInitializeWorkItem(
  4000. workItem,
  4001. NmpJoinAbortWorker,
  4002. ULongToPtr(NmpJoinSequence)
  4003. );
  4004. status = ClRtlPostItemWorkQueue(
  4005. CsDelayedWorkQueue,
  4006. workItem,
  4007. 0,
  4008. 0
  4009. );
  4010. if (status == ERROR_SUCCESS) {
  4011. //
  4012. // Stop the timer, flag that an abort is in progress,
  4013. // and account for the thread we just scheduled.
  4014. //
  4015. NmpJoinTimer = 0;
  4016. NmpJoinAbortPending = TRUE;
  4017. NmpActiveThreadCount++;
  4018. }
  4019. else {
  4020. ClRtlLogPrint(LOG_UNUSUAL,
  4021. "[NMJOIN] Failed to schedule abort of join, status %1!u!.\n",
  4022. status
  4023. );
  4024. LocalFree(workItem);
  4025. }
  4026. }
  4027. else {
  4028. ClRtlLogPrint(LOG_UNUSUAL,
  4029. "[NMJOIN] Failed to allocate memory for join abort.\n"
  4030. );
  4031. }
  4032. }
  4033. }
  4034. NmpLockedLeaveApi();
  4035. }
  4036. return;
  4037. } // NmpJoinTimerTick
  4038. DWORD
  4039. NmpNetworkTimerThread(
  4040. PVOID Parameter
  4041. )
  4042. /*++
  4043. Routine Description:
  4044. Forked as the cluster is initializing, calls NmTimerTick to
  4045. drive the NM timers.
  4046. Separated from the MM timer thread for bug 742997. Code is
  4047. modeled after MM timer, except that we assume that the tick
  4048. interval cannot change.
  4049. Arguments:
  4050. Parameter - points to event that is signaled when thread
  4051. should stop
  4052. Return value:
  4053. SUCCESS
  4054. --*/
  4055. {
  4056. HANDLE stopEvent = (HANDLE) Parameter;
  4057. DWORD status;
  4058. do {
  4059. // Wait on the stop event. If the stop event is
  4060. // signalled, clussvc is exiting and we break out
  4061. // of the loop. Otherwise, the timeout will fire
  4062. // and we drive the NM timers.
  4063. status = WaitForSingleObject(
  4064. stopEvent,
  4065. RGP_CLOCK_PERIOD
  4066. );
  4067. if (status == WAIT_TIMEOUT) {
  4068. NmTimerTick(RGP_CLOCK_PERIOD);
  4069. }
  4070. } while (status == WAIT_TIMEOUT);
  4071. if (status != WAIT_OBJECT_0) {
  4072. DWORD error = GetLastError();
  4073. ClRtlLogPrint(LOG_CRITICAL,
  4074. "[NM] NM timer thread exiting with "
  4075. "status %1!u!, last error %2!u!. Removing "
  4076. "self from cluster.\n",
  4077. status, error
  4078. );
  4079. // We cannot continue without the NM timer.
  4080. CsInconsistencyHalt(status);
  4081. } else {
  4082. ClRtlLogPrint(LOG_NOISE,
  4083. "[NM] NM timer thread exiting.\n"
  4084. );
  4085. }
  4086. return(status);
  4087. } // NmpNetworkTimerThread
  4088. DWORD
  4089. NmpStartNetworkTimerThread(
  4090. VOID
  4091. )
  4092. /*++
  4093. Routine Description:
  4094. Starts the NM timer thread.
  4095. Arguments:
  4096. None.
  4097. Return value:
  4098. Status of event and thread creation.
  4099. --*/
  4100. {
  4101. DWORD status;
  4102. DWORD threadID = 0;
  4103. NmpNetworkTimerThreadHandle = NULL;
  4104. NmpNetworkTimerThreadStopEvent = NULL;
  4105. NmpNetworkTimerThreadStopEvent = CreateEvent(
  4106. NULL, // No security
  4107. FALSE, // Not autoreset
  4108. FALSE, // Not initially signalled
  4109. NULL // No name
  4110. );
  4111. if (NmpNetworkTimerThreadStopEvent == NULL) {
  4112. status = GetLastError();
  4113. ClRtlLogPrint(LOG_CRITICAL,
  4114. "[NM] Failed to create NM timer thread stop event, "
  4115. "error %1!u!.\n",
  4116. status
  4117. );
  4118. goto error_exit;
  4119. }
  4120. NmpNetworkTimerThreadHandle =
  4121. CreateThread(
  4122. 0, // security
  4123. 0, // stack size - use same as primary thread
  4124. (LPTHREAD_START_ROUTINE) NmpNetworkTimerThread,
  4125. (PVOID) NmpNetworkTimerThreadStopEvent, // stop event is parameter
  4126. CREATE_SUSPENDED, // start it after setting prio
  4127. &threadID // thread ID returned here
  4128. );
  4129. if (NmpNetworkTimerThreadHandle == NULL) {
  4130. status = GetLastError();
  4131. ClRtlLogPrint(LOG_CRITICAL,
  4132. "[NM] Failed to create NM timer thread, "
  4133. "error %1!u!.\n",
  4134. status
  4135. );
  4136. goto error_exit;
  4137. }
  4138. // Set the priority, just as done to the MM timer thread
  4139. if (!SetThreadPriority(
  4140. NmpNetworkTimerThreadHandle,
  4141. NM_TIMER_THREAD_PRIORITY
  4142. )) {
  4143. status = GetLastError();
  4144. ClRtlLogPrint(LOG_CRITICAL,
  4145. "[NM] Failed to set NM timer thread priority to %1!u!, "
  4146. "error %2!u!.\n",
  4147. NM_TIMER_THREAD_PRIORITY, status
  4148. );
  4149. goto error_exit;
  4150. }
  4151. // Start the thread.
  4152. if (ResumeThread(NmpNetworkTimerThreadHandle) == -1) {
  4153. status = GetLastError();
  4154. ClRtlLogPrint(LOG_CRITICAL,
  4155. "[NM] Failed to resume NM timer thread, "
  4156. "error %1!u!.\n",
  4157. status
  4158. );
  4159. goto error_exit;
  4160. }
  4161. ClRtlLogPrint(LOG_NOISE,
  4162. "[NM] Started NM timer thread, thread id 0x%1!x!.\n",
  4163. threadID
  4164. );
  4165. return(ERROR_SUCCESS);
  4166. error_exit:
  4167. if (NmpNetworkTimerThreadStopEvent != NULL) {
  4168. CloseHandle(NmpNetworkTimerThreadStopEvent);
  4169. NmpNetworkTimerThreadStopEvent = NULL;
  4170. }
  4171. if (NmpNetworkTimerThreadHandle != NULL) {
  4172. CloseHandle(NmpNetworkTimerThreadHandle);
  4173. NmpNetworkTimerThreadHandle = NULL;
  4174. }
  4175. return(status);
  4176. } // NmpStartNetworkTimerThread
  4177. VOID
  4178. NmpStopNetworkTimerThread(
  4179. VOID
  4180. )
  4181. /*++
  4182. Routine Description:
  4183. Stops the NM timer thread by signaling the stop event.
  4184. Waits maximum of 60 seconds before giving up and letting
  4185. process cleanup sort out the mess (this is okay because
  4186. the NM timer thread is stopped only when the clussvc process
  4187. is exiting).
  4188. Arguments:
  4189. None.
  4190. Return value:
  4191. None.
  4192. --*/
  4193. {
  4194. DWORD status;
  4195. if (NmpNetworkTimerThreadStopEvent != NULL &&
  4196. NmpNetworkTimerThreadHandle != NULL) {
  4197. // Signal the thread to stop.
  4198. SetEvent(NmpNetworkTimerThreadStopEvent);
  4199. // Wait for the thread to exit.
  4200. status = WaitForSingleObject(NmpNetworkTimerThreadHandle, 60 * 1000);
  4201. if (status != WAIT_OBJECT_0) {
  4202. DWORD error = GetLastError();
  4203. ClRtlLogPrint(LOG_UNUSUAL,
  4204. "[NM] NM network timer thread could not be gracefully "
  4205. "stopped, status %1!u!, last error %2!u!.\n",
  4206. status, error
  4207. );
  4208. }
  4209. CloseHandle(NmpNetworkTimerThreadStopEvent);
  4210. CloseHandle(NmpNetworkTimerThreadHandle);
  4211. }
  4212. NmpNetworkTimerThreadStopEvent = NULL;
  4213. NmpNetworkTimerThreadHandle = NULL;
  4214. return;
  4215. } // NmpStopNetworkTimerThread
  4216. VOID
  4217. NmTimerTick(
  4218. IN DWORD MsTickInterval
  4219. )
  4220. /*++
  4221. Routine Description:
  4222. Implements all of the NM timers. Called on every tick of
  4223. the common NM/MM timer - currently every 300ms.
  4224. Arguments:
  4225. MsTickInterval - The number of milliseconds that have passed
  4226. since the last tick.
  4227. ReturnValue:
  4228. None.
  4229. --*/
  4230. {
  4231. NmpAcquireLock();
  4232. NmpNetworkTimerTick(MsTickInterval);
  4233. NmpJoinTimerTick(MsTickInterval);
  4234. #if DBG
  4235. // Addition for checking for hung RPC threads.
  4236. NmpRpcTimerTick(MsTickInterval);
  4237. #endif // DBG
  4238. NmpReleaseLock();
  4239. return;
  4240. } // NmTimerTick
  4241. error_status_t
  4242. s_JoinAddNode4(
  4243. IN handle_t IDL_handle,
  4244. IN LPCWSTR lpszNodeName,
  4245. IN DWORD dwNodeHighestVersion,
  4246. IN DWORD dwNodeLowestVersion,
  4247. IN DWORD dwNodeProductSuite,
  4248. IN BOOL IsNodeRunningWin64,
  4249. IN DWORD dwNodeProcessorArchitecture
  4250. )
  4251. /*++
  4252. Routine Description:
  4253. Adds a new node to the cluster.
  4254. Arguments:
  4255. IDL_handle - RPC binding handle, not used.
  4256. lpszNodeName - Supplies the name of the new node.
  4257. dwNodeHighestVersion - The highest cluster version number that the
  4258. new node can support.
  4259. dwNodeLowestVersion - The lowest cluster version number that the
  4260. new node can support.
  4261. dwNodeProductSuite - The product suite type identifier for the new node.
  4262. Return Value:
  4263. ERROR_SUCCESS if successful
  4264. Win32 error code otherwise.
  4265. Notes:
  4266. This is a new routine in Whistler. It will be invoked only by
  4267. Whistler Setup.
  4268. The cluster registry APIs cannot be called while holding the NmpLock,
  4269. or a deadlock may occur.
  4270. --*/
  4271. {
  4272. DWORD status;
  4273. DWORD registryNodeLimit;
  4274. SYSTEM_INFO SystemInfo;
  4275. ClRtlLogPrint(LOG_NOISE,
  4276. "[NMJOIN] Received request to add node '%1!ws!' to the cluster.\n",
  4277. lpszNodeName
  4278. );
  4279. //
  4280. // Read the necessary registry parameters before acquiring
  4281. // the NM lock.
  4282. //
  4283. status = DmQueryDword(
  4284. DmClusterParametersKey,
  4285. CLUSREG_NAME_MAX_NODES,
  4286. &registryNodeLimit,
  4287. NULL
  4288. );
  4289. if (status != ERROR_SUCCESS) {
  4290. registryNodeLimit = 0;
  4291. }
  4292. NmpAcquireLock();
  4293. if (NmpLockedEnterApi(NmStateOnline)) {
  4294. DWORD retryCount = 0;
  4295. //if this is the last node and it has been evicted
  4296. //but the cleanup hasnt completed and hence the
  4297. //service is up, then it should not entertain
  4298. //any new join requests
  4299. if (NmpLastNodeEvicted)
  4300. {
  4301. ClRtlLogPrint(LOG_UNUSUAL,
  4302. "[NMJOIN] This node was evicted and hence is not in a valid state to process a "
  4303. "request to add a node to the cluster.\n"
  4304. );
  4305. status = ERROR_NODE_NOT_AVAILABLE;
  4306. NmpLockedLeaveApi();
  4307. goto FnExit;
  4308. }
  4309. #if 0
  4310. status = ClRtlCheck64BitCompatibility(ClRtlIsProcessRunningOnWin64(GetCurrentProcess),
  4311. IsNodeRunningWin64);
  4312. if (status != ERROR_SUCCESS)
  4313. {
  4314. ClRtlLogPrint(LOG_UNUSUAL,
  4315. "[NMJOIN] This joining node doesnt match the 32/64 bitness of the current cluster\n"
  4316. );
  4317. NmpLockedLeaveApi();
  4318. goto FnExit;
  4319. }
  4320. #endif
  4321. GetSystemInfo(&SystemInfo);
  4322. status = ClRtlCheckProcArchCompatibility(SystemInfo.wProcessorArchitecture,
  4323. (WORD)dwNodeProcessorArchitecture);
  4324. if (status != ERROR_SUCCESS)
  4325. {
  4326. ClRtlLogPrint(LOG_UNUSUAL,
  4327. "[NMJOIN] This joining node doesnt meet the processor architecture compatibility with this cluster\n"
  4328. );
  4329. NmpLockedLeaveApi();
  4330. goto FnExit;
  4331. }
  4332. while (TRUE) {
  4333. if (NmpLeaderNodeId == NmLocalNodeId) {
  4334. //
  4335. // This node is the leader, call the internal
  4336. // handler directly.
  4337. //
  4338. status = NmpAddNode(
  4339. lpszNodeName,
  4340. dwNodeHighestVersion,
  4341. dwNodeLowestVersion,
  4342. dwNodeProductSuite,
  4343. registryNodeLimit
  4344. );
  4345. }
  4346. else {
  4347. //
  4348. // Forward the request to the leader.
  4349. //
  4350. RPC_BINDING_HANDLE binding = Session[NmpLeaderNodeId];
  4351. ClRtlLogPrint(LOG_NOISE,
  4352. "[NMJOIN] Forwarding request to add node '%1!ws!' "
  4353. "to the cluster to the leader (node %2!u!).\n",
  4354. lpszNodeName,
  4355. NmpLeaderNodeId
  4356. );
  4357. CL_ASSERT(binding != NULL);
  4358. NmpReleaseLock();
  4359. status = NmRpcAddNode(
  4360. binding,
  4361. lpszNodeName,
  4362. dwNodeHighestVersion,
  4363. dwNodeLowestVersion,
  4364. dwNodeProductSuite
  4365. );
  4366. NmpAcquireLock();
  4367. }
  4368. //
  4369. // Check for the error codes that indicate either that
  4370. // another AddNode operation is in progress or that the
  4371. // leadership is changing. We will retry in these cases.
  4372. //
  4373. if ( (status != ERROR_CLUSTER_JOIN_IN_PROGRESS) &&
  4374. (status != ERROR_NODE_NOT_AVAILABLE)
  4375. ) {
  4376. break;
  4377. }
  4378. //
  4379. // Sleep for 3 seconds and try again. We will give up and
  4380. // return the error after retrying for 2 minutes.
  4381. //
  4382. if (++retryCount > 40) {
  4383. break;
  4384. }
  4385. ClRtlLogPrint(LOG_NOISE,
  4386. "[NMJOIN] AddNode operation for node '%1!ws! delayed "
  4387. "waiting for competing AddNode operation to complete.\n",
  4388. lpszNodeName
  4389. );
  4390. NmpReleaseLock();
  4391. Sleep(3000);
  4392. NmpAcquireLock();
  4393. } // end while(TRUE)
  4394. NmpLockedLeaveApi();
  4395. }
  4396. else {
  4397. ClRtlLogPrint(LOG_UNUSUAL,
  4398. "[NMJOIN] This system is not in a valid state to process a "
  4399. "request to add a node to the cluster.\n"
  4400. );
  4401. status = ERROR_NODE_NOT_AVAILABLE;
  4402. }
  4403. FnExit:
  4404. NmpReleaseLock();
  4405. return(status);
  4406. } // s_NmJoinAddNode4
  4407. error_status_t
  4408. s_JoinAddNode3(
  4409. IN handle_t IDL_handle,
  4410. IN LPCWSTR lpszNodeName,
  4411. IN DWORD dwNodeHighestVersion,
  4412. IN DWORD dwNodeLowestVersion,
  4413. IN DWORD dwNodeProductSuite
  4414. )
  4415. /*++
  4416. Routine Description:
  4417. Adds a new node to the cluster.
  4418. Arguments:
  4419. IDL_handle - RPC binding handle, not used.
  4420. lpszNodeName - Supplies the name of the new node.
  4421. dwNodeHighestVersion - The highest cluster version number that the
  4422. new node can support.
  4423. dwNodeLowestVersion - The lowest cluster version number that the
  4424. new node can support.
  4425. dwNodeProductSuite - The product suite type identifier for the new node.
  4426. Return Value:
  4427. ERROR_SUCCESS if successful
  4428. Win32 error code otherwise.
  4429. Notes:
  4430. This is a new routine in NT5. It performs the AddNode operation
  4431. correctly. It will never be invoked by an NT4 system. It cannot
  4432. be invoked if an NT4 node is in the cluster without violating
  4433. the license agreement.
  4434. The cluster registry APIs cannot be called while holding the NmpLock,
  4435. or a deadlock may occur.
  4436. --*/
  4437. {
  4438. return(s_JoinAddNode4(IDL_handle, lpszNodeName, dwNodeHighestVersion,
  4439. dwNodeLowestVersion,dwNodeProductSuite, FALSE, (DWORD)PROCESSOR_ARCHITECTURE_INTEL));
  4440. } // s_NmJoinAddNode3
  4441. // This is used by setup of all highest major versions post 1.0
  4442. error_status_t
  4443. s_JoinAddNode2(
  4444. IN handle_t IDL_handle,
  4445. IN LPCWSTR lpszNodeName,
  4446. IN DWORD dwNodeHighestVersion,
  4447. IN DWORD dwNodeLowestVersion
  4448. )
  4449. /*++
  4450. Routine Description:
  4451. Adds a new node to the cluster database.
  4452. Arguments:
  4453. IDL_handle - RPC binding handle, not used.
  4454. lpszNodeName - Supplies the name of the new node.
  4455. Return Value:
  4456. ERROR_SUCCESS if successful
  4457. Win32 error code otherwise.
  4458. Notes:
  4459. This routine was defined in NT4-SP4. JoinAddNode3 is used by NT5. Since
  4460. it is impossible to install clustering using the NT4-SP4 software,
  4461. this routine should never be invoked.
  4462. --*/
  4463. {
  4464. CL_ASSERT(FALSE);
  4465. return(ERROR_CLUSTER_INCOMPATIBLE_VERSIONS);
  4466. }
  4467. error_status_t
  4468. s_JoinAddNode(
  4469. IN handle_t IDL_handle,
  4470. IN LPCWSTR lpszNodeName
  4471. )
  4472. /*++
  4473. Routine Description:
  4474. Adds a new node to the cluster database.
  4475. Arguments:
  4476. IDL_handle - RPC binding handle, not used.
  4477. lpszNodeName - Supplies the name of the new node.
  4478. Return Value:
  4479. ERROR_SUCCESS if successful
  4480. Win32 error code otherwise.
  4481. Notes:
  4482. This is the routine that NT4-SP3 setup invokes to add a new node to
  4483. a cluster. The combination of NT4-SP3 and NT5 is not supported.
  4484. --*/
  4485. {
  4486. return(ERROR_CLUSTER_INCOMPATIBLE_VERSIONS);
  4487. }
  4488. //
  4489. // The rest of the code is currently unused.
  4490. //
  4491. error_status_t
  4492. s_NmRpcDeliverJoinMessage(
  4493. IN handle_t IDL_handle,
  4494. IN UCHAR * Message,
  4495. IN DWORD MessageLength
  4496. )
  4497. /*++
  4498. Routine Description:
  4499. Server side of the RPC interface for delivering membership
  4500. join messages.
  4501. Arguments:
  4502. IDL_handle - RPC binding handle, not used.
  4503. buffer - Supplies a pointer to the message data.
  4504. length - Supplies the length of the message data.
  4505. Return Value:
  4506. ERROR_SUCCESS
  4507. --*/
  4508. {
  4509. DWORD status = ERROR_SUCCESS;
  4510. #ifdef MM_IN_CLUSNET
  4511. ClRtlLogPrint(LOG_NOISE,
  4512. "[NMJOIN] Delivering join message to Clusnet.\n"
  4513. );
  4514. status = ClusnetDeliverJoinMessage(
  4515. NmClusnetHandle,
  4516. Message,
  4517. MessageLength
  4518. );
  4519. #endif
  4520. return(status);
  4521. }
  4522. #ifdef MM_IN_CLUSNET
  4523. DWORD
  4524. NmpSendJoinMessage(
  4525. IN ULONG DestNodeMask,
  4526. IN PVOID Message,
  4527. IN ULONG MessageLength
  4528. )
  4529. {
  4530. DWORD status = ERROR_SUCCESS;
  4531. CL_NODE_ID node;
  4532. CL_ASSERT(NmMaxNodeId != ClusterInvalidNodeId);
  4533. for ( node = ClusterMinNodeId;
  4534. node <= NmMaxNodeId;
  4535. node++, (DestNodeMask >>= 1)
  4536. )
  4537. {
  4538. if (DestNodeMask & 0x1) {
  4539. if (node != NmLocalNodeId) {
  4540. ClRtlLogPrint(LOG_NOISE,
  4541. "[NMJOIN] Sending join message to node %1!u!.\n",
  4542. node
  4543. );
  4544. status = NmRpcDeliverJoinMessage(
  4545. Session[node->NodeId],
  4546. Message,
  4547. MessageLength
  4548. );
  4549. if (status == RPC_S_CALL_FAILED_DNE) {
  4550. //
  4551. // Try again since the first call to a restarted
  4552. // RPC server will fail.
  4553. //
  4554. status = NmRpcDeliverJoinMessage(
  4555. Session[node->NodeId],
  4556. Message,
  4557. MessageLength
  4558. );
  4559. }
  4560. }
  4561. else {
  4562. ClRtlLogPrint(LOG_NOISE,
  4563. "[NMJOIN] Delivering join message to local node.\n"
  4564. );
  4565. status = ClusnetDeliverJoinMessage(
  4566. NmClusnetHandle,
  4567. Message,
  4568. MessageLength
  4569. );
  4570. }
  4571. if (status != ERROR_SUCCESS) {
  4572. ClRtlLogPrint(LOG_NOISE,
  4573. "[NMJOIN] send of join message to node %1!u! failed, status %2!u!\n",
  4574. node,
  4575. status
  4576. );
  4577. break;
  4578. }
  4579. }
  4580. }
  4581. return(status);
  4582. } // NmpSendJoinMessage
  4583. DWORD
  4584. NmJoinNodeToCluster(
  4585. CL_NODE_ID joinerNodeId
  4586. )
  4587. {
  4588. DWORD status;
  4589. PVOID message = NULL;
  4590. ULONG messageLength;
  4591. ULONG destMask;
  4592. CLUSNET_JOIN_PHASE phase;
  4593. ClRtlLogPrint(LOG_NOISE,
  4594. "[NMJOIN] Joining node %1!u! to the cluster.\n",
  4595. joinerNodeId
  4596. );
  4597. for (phase = ClusnetJoinPhase1; phase <= ClusnetJoinPhase4; phase++) {
  4598. ClRtlLogPrint(LOG_NOISE,
  4599. "[NMJOIN] JoinNode phase %1!u!\n",
  4600. phase
  4601. );
  4602. status = ClusnetJoinCluster(
  4603. NmClusnetHandle,
  4604. joinerNodeId,
  4605. phase,
  4606. NM_MM_JOIN_TIMEOUT,
  4607. &message,
  4608. &messageLength,
  4609. &destMask
  4610. );
  4611. if (status != ERROR_SUCCESS) {
  4612. ClRtlLogPrint(LOG_NOISE,
  4613. "[NMJOIN] JoinNode phase %1!u! failed, status %2!u!\n",
  4614. phase,
  4615. status
  4616. );
  4617. break;
  4618. }
  4619. status = NmpSendJoinMessage(
  4620. destMask,
  4621. message,
  4622. messageLength
  4623. );
  4624. if (status != ERROR_SUCCESS) {
  4625. DWORD abortStatus;
  4626. ClRtlLogPrint(LOG_NOISE,
  4627. "[NMJOIN] send join message failed %1!u!, aborting join of node %2!u!.\n",
  4628. status,
  4629. joinerNodeId
  4630. );
  4631. abortStatus = ClusnetJoinCluster(
  4632. NmClusnetHandle,
  4633. joinerNodeId,
  4634. ClusnetJoinPhaseAbort,
  4635. NM_MM_JOIN_TIMEOUT,
  4636. &message,
  4637. &messageLength,
  4638. &destMask
  4639. );
  4640. if (abortStatus == ERROR_SUCCESS) {
  4641. (VOID) NmpSendJoinMessage(
  4642. destMask,
  4643. message,
  4644. messageLength
  4645. );
  4646. }
  4647. break;
  4648. }
  4649. }
  4650. if (message != NULL) {
  4651. ClusnetEndJoinCluster(NmClusnetHandle, message);
  4652. }
  4653. return(status);
  4654. } // NmJoinNodeToCluster
  4655. #endif // MM_IN_CLUSNET