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.

4774 lines
121 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. node.c
  5. Abstract:
  6. Private Node Manager routines.
  7. Author:
  8. Mike Massa (mikemas) 12-Mar-1996
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "nmp.h"
  13. /////////////////////////////////////////////////////////////////////////////
  14. //
  15. // Data
  16. //
  17. /////////////////////////////////////////////////////////////////////////////
  18. ULONG NmMaxNodes = ClusterInvalidNodeId;
  19. CL_NODE_ID NmMaxNodeId = ClusterInvalidNodeId;
  20. CL_NODE_ID NmLocalNodeId = ClusterInvalidNodeId;
  21. PNM_NODE NmLocalNode = NULL;
  22. WCHAR NmLocalNodeIdString[CS_MAX_NODE_ID_LENGTH+1];
  23. WCHAR NmLocalNodeName[CS_MAX_NODE_NAME_LENGTH+1];
  24. LIST_ENTRY NmpNodeList = {NULL, NULL};
  25. PNM_NODE * NmpIdArray = NULL;
  26. DWORD NmpNodeCount = 0;
  27. BOOL NmpLastNodeEvicted = FALSE;
  28. BOOL NmLocalNodeVersionChanged = FALSE;
  29. LIST_ENTRY * NmpIntraClusterRpcArr=NULL;
  30. CRITICAL_SECTION NmpRPCLock;
  31. // Use space hang detection parameters.
  32. DWORD NmClusSvcHeartbeatTimeout=0;
  33. ClussvcHangAction NmHangRecoveryAction;
  34. #if DBG
  35. DWORD NmpRpcTimer=0;
  36. #endif // DBG
  37. ///////////////////////////////////////////////////////////////////////////
  38. //
  39. // Initialization/Cleanup Routines
  40. //
  41. ///////////////////////////////////////////////////////////////////////////
  42. VOID
  43. NmpCleanupNodes(
  44. VOID
  45. )
  46. {
  47. PNM_NODE node;
  48. PLIST_ENTRY entry, nextEntry;
  49. DWORD status;
  50. ClRtlLogPrint(LOG_NOISE,"[NM] Node cleanup starting...\n");
  51. NmpAcquireLock();
  52. while (!IsListEmpty(&NmpNodeList)) {
  53. entry = NmpNodeList.Flink;
  54. node = CONTAINING_RECORD(entry, NM_NODE, Linkage);
  55. if (node == NmLocalNode) {
  56. entry = node->Linkage.Flink;
  57. if (entry == &NmpNodeList) {
  58. break;
  59. }
  60. node = CONTAINING_RECORD(entry, NM_NODE, Linkage);
  61. }
  62. CL_ASSERT(NM_OM_INSERTED(node));
  63. CL_ASSERT(!NM_DELETE_PENDING(node));
  64. NmpDeleteNodeObject(node, FALSE);
  65. }
  66. NmpReleaseLock();
  67. ClRtlLogPrint(LOG_NOISE,"[NM] Node cleanup complete\n");
  68. return;
  69. } // NmpCleanupNodes
  70. /////////////////////////////////////////////////////////////////////////////
  71. //
  72. // Remote procedures called by joining nodes or on behalf of joining nodes.
  73. //
  74. /////////////////////////////////////////////////////////////////////////////
  75. error_status_t
  76. s_NmRpcEnumNodeDefinitions(
  77. IN handle_t IDL_handle,
  78. IN DWORD JoinSequence, OPTIONAL
  79. IN LPWSTR JoinerNodeId, OPTIONAL
  80. OUT PNM_NODE_ENUM * NodeEnum1
  81. )
  82. {
  83. DWORD status = ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  84. ClRtlLogPrint(LOG_UNUSUAL,
  85. "[NMJOIN] Refusing node info to joining node nodeid=%1!ws!. Aborting join, obsolete interface.\n",
  86. JoinerNodeId
  87. );
  88. return(status);
  89. } // s_NmRpcEnumNodeDefinitions
  90. error_status_t
  91. s_NmRpcEnumNodeDefinitions2(
  92. IN handle_t IDL_handle,
  93. IN DWORD JoinSequence, OPTIONAL
  94. IN LPWSTR JoinerNodeId, OPTIONAL
  95. OUT PNM_NODE_ENUM2 * NodeEnum
  96. )
  97. {
  98. DWORD status = ERROR_SUCCESS;
  99. PNM_NODE joinerNode = NULL;
  100. NmpAcquireLock();
  101. if (NmpLockedEnterApi(NmStateOnline)) {
  102. ClRtlLogPrint(LOG_NOISE,
  103. "[NMJOIN] Supplying node information to joining node.\n"
  104. );
  105. if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
  106. joinerNode = OmReferenceObjectById(
  107. ObjectTypeNode,
  108. JoinerNodeId
  109. );
  110. if (joinerNode != NULL) {
  111. if ( (JoinSequence == NmpJoinSequence) &&
  112. (NmpJoinerNodeId == joinerNode->NodeId) &&
  113. (NmpSponsorNodeId == NmLocalNodeId) &&
  114. !NmpJoinAbortPending
  115. )
  116. {
  117. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  118. CL_ASSERT(NmpJoinerUp == FALSE);
  119. CL_ASSERT(NmpJoinTimer != 0);
  120. //
  121. // Suspend the join timer while we are working on
  122. // behalf of the joiner. This precludes an abort
  123. // from occuring as well.
  124. //
  125. NmpJoinTimer = 0;
  126. }
  127. else {
  128. status = ERROR_CLUSTER_JOIN_ABORTED;
  129. ClRtlLogPrint(LOG_UNUSUAL,
  130. "[NMJOIN] EnumNodeDefinitions call for joining node %1!ws! failed because the join was aborted.\n",
  131. JoinerNodeId
  132. );
  133. }
  134. }
  135. else {
  136. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  137. ClRtlLogPrint(LOG_UNUSUAL,
  138. "[NMJOIN] EnumNodeDefinitions call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  139. JoinerNodeId
  140. );
  141. }
  142. }
  143. if (status == ERROR_SUCCESS) {
  144. status = NmpEnumNodeObjects(NodeEnum);
  145. if (joinerNode != NULL) {
  146. if (status == ERROR_SUCCESS) {
  147. //
  148. // Restart the join timer.
  149. //
  150. NmpJoinTimer = NM_JOIN_TIMEOUT;
  151. }
  152. else {
  153. ClRtlLogPrint(LOG_CRITICAL,
  154. "[NMJOIN] EnumNodeDefinitions failed, status %1!u!.\n",
  155. status
  156. );
  157. //
  158. // Abort the join
  159. //
  160. NmpJoinAbort(status, joinerNode);
  161. }
  162. }
  163. }
  164. if (joinerNode != NULL) {
  165. OmDereferenceObject(joinerNode);
  166. }
  167. NmpLockedLeaveApi();
  168. }
  169. else {
  170. status = ERROR_NODE_NOT_AVAILABLE;
  171. ClRtlLogPrint(LOG_NOISE,
  172. "[NM] Not in valid state to process EnumNodeDefinitions request.\n"
  173. );
  174. }
  175. NmpReleaseLock();
  176. return(status);
  177. } // s_NmRpcEnumNodeDefinitions2
  178. error_status_t
  179. s_NmRpcAddNode(
  180. IN handle_t IDL_handle,
  181. IN LPCWSTR NewNodeName,
  182. IN DWORD NewNodeHighestVersion,
  183. IN DWORD NewNodeLowestVersion,
  184. IN DWORD NewNodeProductSuite
  185. )
  186. /*++
  187. Routine Description:
  188. Adds a new node to the cluster by selecting an ID and
  189. issuing a global update.
  190. Arguments:
  191. IDL_handle - RPC client interface handle.
  192. NewNodeName - A pointer to a string containing the name of the
  193. new node.
  194. NewNodeHighestVersion - The highest cluster version number that the
  195. new node can support.
  196. NewNodeLowestVersion - The lowest cluster version number that the
  197. new node can support.
  198. NewNodeProductSuite - The product suite identifier for the new node.
  199. Return Value:
  200. A Win32 status code.
  201. Notes:
  202. Called with NmpLock held.
  203. --*/
  204. {
  205. DWORD status;
  206. DWORD registryNodeLimit;
  207. ClRtlLogPrint(LOG_UNUSUAL,
  208. "[NMJOIN] Received forwarded request to add node '%1!ws!' to the "
  209. "cluster.\n",
  210. NewNodeName
  211. );
  212. //
  213. // Read the registry override before acquiring the NM lock.
  214. //
  215. status = DmQueryDword(
  216. DmClusterParametersKey,
  217. CLUSREG_NAME_MAX_NODES,
  218. &registryNodeLimit,
  219. NULL
  220. );
  221. if (status != ERROR_SUCCESS) {
  222. registryNodeLimit = 0;
  223. }
  224. NmpAcquireLock();
  225. if (!NmpLockedEnterApi(NmStateOnline)) {
  226. ClRtlLogPrint(LOG_UNUSUAL,
  227. "[NMJOIN] This node is not in a valid state to process a "
  228. "request to add node '%1!ws!' to the cluster.\n",
  229. NewNodeName
  230. );
  231. NmpReleaseLock();
  232. return(ERROR_NODE_NOT_AVAILABLE);
  233. }
  234. if (NmpLeaderNodeId == NmLocalNodeId) {\
  235. //
  236. // Call the internal handler.
  237. //
  238. status = NmpAddNode(
  239. NewNodeName,
  240. NewNodeHighestVersion,
  241. NewNodeLowestVersion,
  242. NewNodeProductSuite,
  243. registryNodeLimit
  244. );
  245. }
  246. else {
  247. //
  248. // This node is not the leader.
  249. // Fail the request.
  250. //
  251. status = ERROR_NODE_NOT_AVAILABLE;
  252. ClRtlLogPrint(LOG_UNUSUAL,
  253. "[NMJOIN] Cannot process request to add node '%1!ws!' to the "
  254. "cluster because this node is not the leader.\n",
  255. NewNodeName
  256. );
  257. }
  258. NmpLockedLeaveApi();
  259. NmpReleaseLock();
  260. return(status);
  261. } // s_NmRpcAddNode
  262. /////////////////////////////////////////////////////////////////////////////
  263. //
  264. // Routines called by other cluster service components
  265. //
  266. /////////////////////////////////////////////////////////////////////////////
  267. /////////////////////////////////////////////////////////////////////////////
  268. //
  269. // Setting up ClusSvc to ClusNet Heartbeating.
  270. //
  271. /////////////////////////////////////////////////////////////////////////////
  272. DWORD NmInitializeClussvcClusnetHb(VOID)
  273. {
  274. DWORD status = ERROR_SUCCESS;
  275. DWORD hAct;
  276. LPWSTR actStr;
  277. HANDLE th;
  278. DWORD thId;
  279. // Initialize all the parameters with default values.
  280. NmClusSvcHeartbeatTimeout = CLUSTER_HEARTBEAT_TIMEOUT_DEFAULT;
  281. NmHangRecoveryAction = CLUSTER_HANG_RECOVERY_ACTION_DEFAULT;
  282. // Get the values of ClussvcClusnetHbTimeout and ClssvcClusnetHbTimeoutAction if present.
  283. // They are in HKLM\Cluster\Parameters
  284. DmQueryDword(
  285. DmClusterParametersKey,
  286. CLUSTER_HEARTBEAT_TIMEOUT_KEYNAME,
  287. &NmClusSvcHeartbeatTimeout,
  288. NULL
  289. );
  290. status = DmQueryDword(
  291. DmClusterParametersKey,
  292. CLUSTER_HANG_RECOVERY_ACTION_KEYNAME,
  293. &hAct,
  294. NULL
  295. );
  296. if (status == ERROR_SUCCESS) {
  297. NmHangRecoveryAction = (ClussvcHangAction)hAct;
  298. }
  299. // Check that they are within limits else use default.
  300. if (NmClusSvcHeartbeatTimeout < CLUSTER_HEARTBEAT_TIMEOUT_MIN)
  301. NmClusSvcHeartbeatTimeout = CLUSTER_HEARTBEAT_TIMEOUT_DEFAULT;
  302. if (NmHangRecoveryAction >= ClussvcHangActionMax)
  303. NmHangRecoveryAction = CLUSTER_HANG_RECOVERY_ACTION_DEFAULT;
  304. if(NmHangRecoveryAction == ClussvcHangActionTerminateService)
  305. actStr = L"Terminate Service";
  306. else if(NmHangRecoveryAction == ClussvcHangActionLog)
  307. actStr = L"Log";
  308. else if(NmHangRecoveryAction == ClussvcHangActionDisable)
  309. actStr = L"Disabled";
  310. else
  311. actStr = L"BugCheck Node";
  312. ClRtlLogPrint(LOG_NOISE,
  313. "[NM] Setting ClusSvc ClusNet HB params, Timeout=%1!u!(s) Action= %2!ws!.\n",
  314. NmClusSvcHeartbeatTimeout,
  315. actStr
  316. );
  317. // ClusSvc, ClusNet comes up with this feature in disabled state. So if the action is
  318. // diable then do nothing.
  319. if (NmHangRecoveryAction == ClussvcHangActionDisable)
  320. return ERROR_SUCCESS;
  321. // Tell Clusnet to start monitoring.
  322. // Note: Actual monitoring would not start till first HB is received by clusnet.
  323. status = ClusnetSetIamaliveParam(
  324. NmClusnetHandle,
  325. NmClusSvcHeartbeatTimeout,
  326. NmHangRecoveryAction
  327. );
  328. // Now tell RGP to start heartbeating.
  329. if (status == ERROR_SUCCESS) {
  330. ClRtlLogPrint(LOG_NOISE,
  331. "[NM] Successfully initialized Clussvc to Clusnet heartbeating\n"
  332. );
  333. MMStartClussvcClusnetHb();
  334. }
  335. else {
  336. ClRtlLogPrint(LOG_NOISE,
  337. "[NM] Clussvc to Clusnet heartbeating initialization failed status=%1!u!\n",
  338. status
  339. );
  340. }
  341. return status;
  342. }// NmInitializeClussvcClusnetHb
  343. /////////////////////////////////////////////////////////////////////////////
  344. //
  345. // Rpc Extended error tracking.
  346. //
  347. /////////////////////////////////////////////////////////////////////////////
  348. VOID NmDumpRpcExtErrorInfo(RPC_STATUS status)
  349. {
  350. RPC_STATUS status2;
  351. RPC_ERROR_ENUM_HANDLE enumHandle;
  352. status2 = RpcErrorStartEnumeration(&enumHandle);
  353. if(status2 == RPC_S_ENTRY_NOT_FOUND) {
  354. ClRtlLogPrint(LOG_UNUSUAL,
  355. "[NM] RpcExtErrorInfo: Error info not found.\n"
  356. );
  357. }
  358. else if(status2 != RPC_S_OK) {
  359. ClRtlLogPrint(LOG_UNUSUAL,
  360. "[NM] RpcExtErrorInfo: Couldn't get error info, status %1!u!\n",
  361. status2
  362. );
  363. }
  364. else {
  365. RPC_EXTENDED_ERROR_INFO errorInfo;
  366. int records;
  367. BOOL result;
  368. BOOL copyStrings=TRUE;
  369. BOOL fUseFileTime=TRUE;
  370. SYSTEMTIME *systemTimeToUse;
  371. SYSTEMTIME systemTimeBuffer;
  372. while(status2 == RPC_S_OK) {
  373. errorInfo.Version = RPC_EEINFO_VERSION;
  374. errorInfo.Flags = 0;
  375. errorInfo.NumberOfParameters = 4;
  376. if(fUseFileTime) {
  377. errorInfo.Flags |= EEInfoUseFileTime;
  378. }
  379. status2 = RpcErrorGetNextRecord(&enumHandle, copyStrings, &errorInfo);
  380. if(status2 == RPC_S_ENTRY_NOT_FOUND) {
  381. break;
  382. }
  383. else if(status2 != RPC_S_OK) {
  384. ClRtlLogPrint(LOG_UNUSUAL,
  385. "[NM] RpcExtErrorInfo: Couldn't complete enumeration, status %1!u!\n",
  386. status2
  387. );
  388. break;
  389. }
  390. else {
  391. int i;
  392. if(errorInfo.ComputerName) {
  393. ClRtlLogPrint(LOG_NOISE,
  394. "[NM] RpcExtErrorInfo: ComputerName= %1!ws!\n",
  395. errorInfo.ComputerName
  396. );
  397. }
  398. if(copyStrings) {
  399. result = HeapFree(GetProcessHeap(), 0, errorInfo.ComputerName);
  400. CL_ASSERT(result);
  401. }
  402. ClRtlLogPrint(LOG_NOISE,
  403. "[NM] RpcExtErrorInfo: ProcessId= %1!u!\n",
  404. errorInfo.ProcessID
  405. );
  406. if(fUseFileTime) {
  407. result = FileTimeToSystemTime(&errorInfo.u.FileTime, &systemTimeBuffer);
  408. CL_ASSERT(result);
  409. systemTimeToUse = &systemTimeBuffer;
  410. }
  411. else {
  412. systemTimeToUse = &errorInfo.u.SystemTime;
  413. }
  414. ClRtlLogPrint(LOG_NOISE,
  415. "[NM] RpcExtErrorInfo: SystemTime= %1!u!/%2!u!/%3!u! %4!u!:%5!u!:%6!u!:%7!u!\n",
  416. systemTimeToUse->wMonth,
  417. systemTimeToUse->wDay,
  418. systemTimeToUse->wYear,
  419. systemTimeToUse->wHour,
  420. systemTimeToUse->wMinute,
  421. systemTimeToUse->wSecond,
  422. systemTimeToUse->wMilliseconds
  423. );
  424. ClRtlLogPrint(LOG_NOISE,
  425. "[NM] RpcExtErrorInfo: GeneratingComponent= %1!u!\n",
  426. errorInfo.GeneratingComponent
  427. );
  428. ClRtlLogPrint(LOG_NOISE,
  429. "[NM] RpcExtErrorInfo: Status= 0x%1!x!\n",
  430. errorInfo.Status
  431. );
  432. ClRtlLogPrint(LOG_NOISE,
  433. "[NM] RpcExtErrorInfo: Detection Location= %1!u!\n",
  434. (DWORD)errorInfo.DetectionLocation
  435. );
  436. ClRtlLogPrint(LOG_NOISE,
  437. "[NM] RpcExtErrorInfo: Flags= 0x%1!x!\n",
  438. errorInfo.Flags
  439. );
  440. ClRtlLogPrint(LOG_NOISE,
  441. "[NM] RpcExtErrorInfo: Number of Parameters= %1!u!\n",
  442. errorInfo.NumberOfParameters
  443. );
  444. for(i=0;i<errorInfo.NumberOfParameters;i++) {
  445. switch(errorInfo.Parameters[i].ParameterType) {
  446. case eeptAnsiString:
  447. ClRtlLogPrint(LOG_NOISE,
  448. "[NM] RpcExtErrorInfo: Ansi String= %1!s!\n",
  449. errorInfo.Parameters[i].u.AnsiString
  450. );
  451. if(copyStrings) {
  452. result = HeapFree(GetProcessHeap(), 0, errorInfo.Parameters[i].u.AnsiString);
  453. CL_ASSERT(result);
  454. }
  455. break;
  456. case eeptUnicodeString:
  457. ClRtlLogPrint(LOG_NOISE,
  458. "[NM] RpcExtErrorInfo: Unicode String= %1!S!\n",
  459. errorInfo.Parameters[i].u.UnicodeString
  460. );
  461. if(copyStrings) {
  462. result = HeapFree(GetProcessHeap(), 0, errorInfo.Parameters[i].u.UnicodeString);
  463. CL_ASSERT(result);
  464. }
  465. break;
  466. case eeptLongVal:
  467. ClRtlLogPrint(LOG_NOISE,
  468. "[NM] RpcExtErrorInfo: Long Val= %1!u!\n",
  469. errorInfo.Parameters[i].u.LVal
  470. );
  471. break;
  472. case eeptShortVal:
  473. ClRtlLogPrint(LOG_NOISE,
  474. "[NM] RpcExtErrorInfo: Short Val= %1!u!\n",
  475. (DWORD)errorInfo.Parameters[i].u.SVal
  476. );
  477. break;
  478. case eeptPointerVal:
  479. ClRtlLogPrint(LOG_NOISE,
  480. "[NM] RpcExtErrorInfo: Pointer Val= 0x%1!u!\n",
  481. errorInfo.Parameters[i].u.PVal
  482. );
  483. break;
  484. case eeptNone:
  485. ClRtlLogPrint(LOG_NOISE,
  486. "[NM] RpcExtErrorInfo: Truncated\n"
  487. );
  488. break;
  489. default:
  490. ClRtlLogPrint(LOG_NOISE,
  491. "[NM] RpcExtErrorInfo: Invalid Type %1!u!\n",
  492. errorInfo.Parameters[i].ParameterType
  493. );
  494. }
  495. }
  496. }
  497. }
  498. RpcErrorEndEnumeration(&enumHandle);
  499. }
  500. } //NmDumpRpcExtErrorInfo
  501. ///////////////////////////////////////////////////////////////////////////
  502. //
  503. // RPC Monitoring Routines
  504. //
  505. ///////////////////////////////////////////////////////////////////////////
  506. VOID
  507. NmStartRpc(
  508. DWORD NodeId
  509. )
  510. /*++
  511. Routine Description:
  512. Registers the fact that an RPC is about to be made to the specified
  513. node by the current thread. This allows the call to be cancelled if
  514. the target node dies.
  515. Arguments:
  516. NodeId - The ID of the node about to be called.
  517. Return Value:
  518. None
  519. Notes:
  520. This routine must not be called by a thread that makes concurrent
  521. asynch RPC calls.
  522. --*/
  523. {
  524. HANDLE thHandle;
  525. PNM_INTRACLUSTER_RPC_THREAD entry;
  526. CL_ASSERT((NodeId >= ClusterMinNodeId) && (NodeId <= NmMaxNodeId));
  527. CL_ASSERT(NmpIntraClusterRpcArr != NULL);
  528. thHandle = OpenThread(
  529. THREAD_ALL_ACCESS,
  530. FALSE,
  531. GetCurrentThreadId()
  532. );
  533. if(thHandle == NULL) {
  534. ClRtlLogPrint(LOG_UNUSUAL,
  535. "[NM] NmStartRpc: Failed to open handle to current thread.\n"
  536. );
  537. return;
  538. }
  539. entry = LocalAlloc(LMEM_FIXED, sizeof(NM_INTRACLUSTER_RPC_THREAD));
  540. if(entry == NULL) {
  541. ClRtlLogPrint(LOG_UNUSUAL,
  542. "[NM] NmStartRpc: Failed to allocate memory.\n"
  543. );
  544. CloseHandle(thHandle);
  545. return;
  546. }
  547. entry->ThreadId = GetCurrentThreadId();
  548. entry->Thread = thHandle;
  549. entry->Cancelled = FALSE;
  550. NmpAcquireRPCLock();
  551. #if DBG
  552. ClRtlLogPrint(LOG_NOISE,
  553. "[NM] Starting RPC to node %1!u!\n",
  554. NodeId
  555. );
  556. #endif
  557. InsertHeadList(&NmpIntraClusterRpcArr[NodeId], &entry->Linkage);
  558. NmpReleaseRPCLock();
  559. return;
  560. } // NmStartRpc
  561. VOID
  562. NmEndRpc(
  563. DWORD NodeId
  564. )
  565. /*++
  566. Routine Description:
  567. Cancels registration of an RPC to the specified node by the current
  568. thread.
  569. Arguments:
  570. NodeId - The ID of the node that was called.
  571. Return Value:
  572. None
  573. Notes:
  574. This routine must be invoked even if the RPC was cancelled.
  575. --*/
  576. {
  577. DWORD threadId;
  578. LIST_ENTRY *pEntry;
  579. PNM_INTRACLUSTER_RPC_THREAD pRpcTh;
  580. CL_ASSERT((NodeId >= ClusterMinNodeId) && (NodeId <= NmMaxNodeId));
  581. CL_ASSERT(NmpIntraClusterRpcArr != NULL);
  582. threadId = GetCurrentThreadId();
  583. NmpAcquireRPCLock();
  584. pEntry = NmpIntraClusterRpcArr[NodeId].Flink;
  585. while(pEntry != &NmpIntraClusterRpcArr[NodeId]) {
  586. pRpcTh = CONTAINING_RECORD(pEntry, NM_INTRACLUSTER_RPC_THREAD, Linkage);
  587. if(pRpcTh->ThreadId == threadId) {
  588. #if DBG
  589. ClRtlLogPrint(LOG_NOISE,
  590. "[NM] Finished RPC to node %1!u!\n",
  591. NodeId
  592. );
  593. #endif
  594. if (pRpcTh->Cancelled) {
  595. ClRtlLogPrint(LOG_NOISE,
  596. "[NM] RPC by this thread to node %1!u! is cancelled\n",
  597. NodeId
  598. );
  599. // Now sleep in alertable mode to drain any spurious Rpc Cancel APCs.
  600. // This is a workaround for 598037.
  601. if (SleepEx(50, TRUE) == WAIT_IO_COMPLETION) {
  602. ClRtlLogPrint(LOG_UNUSUAL,
  603. "[NM] Possibly spurious RPC Cancel APC detected.\n"
  604. );
  605. }
  606. }
  607. RemoveEntryList(pEntry);
  608. CloseHandle(pRpcTh->Thread);
  609. LocalFree(pRpcTh);
  610. NmpReleaseRPCLock();
  611. return;
  612. }
  613. pEntry = pEntry->Flink;
  614. }
  615. ClRtlLogPrint(LOG_UNUSUAL,
  616. "[NM] No record of RPC by this thread to node %1!u!.\n",
  617. NodeId
  618. );
  619. #if DBG
  620. CL_ASSERT(pEntry != &NmpIntraClusterRpcArr[NodeId]);
  621. #endif
  622. NmpReleaseRPCLock();
  623. return;
  624. } // NmEndRpc
  625. DWORD
  626. NmPauseNode(
  627. IN PNM_NODE Node
  628. )
  629. /*++
  630. Routine Description:
  631. Arguments:
  632. Return Value:
  633. --*/
  634. {
  635. LPCWSTR nodeId = OmObjectId(Node);
  636. DWORD status;
  637. ClRtlLogPrint(LOG_NOISE,
  638. "[NM] Received request to pause node %1!ws!.\n",
  639. nodeId
  640. );
  641. if (NmpEnterApi(NmStateOnline)) {
  642. status = GumSendUpdateEx(
  643. GumUpdateMembership,
  644. NmUpdatePauseNode,
  645. 1,
  646. (lstrlenW(nodeId)+1)*sizeof(WCHAR),
  647. nodeId
  648. );
  649. if (status != ERROR_SUCCESS) {
  650. ClRtlLogPrint(LOG_CRITICAL,
  651. "[NM] Global update to pause node %1!ws! failed, status %2!u!\n",
  652. nodeId,
  653. status
  654. );
  655. }
  656. NmpLeaveApi();
  657. }
  658. else {
  659. status = ERROR_NODE_NOT_AVAILABLE;
  660. ClRtlLogPrint(LOG_NOISE,
  661. "[NM] Not in valid state to process PauseNode request.\n"
  662. );
  663. }
  664. return(status);
  665. } // NmPauseNode
  666. DWORD
  667. NmResumeNode(
  668. IN PNM_NODE Node
  669. )
  670. /*++
  671. Routine Description:
  672. Arguments:
  673. Return Value:
  674. --*/
  675. {
  676. LPCWSTR nodeId = OmObjectId(Node);
  677. DWORD status;
  678. ClRtlLogPrint(LOG_NOISE,
  679. "[NM] Received request to resume node %1!ws!.\n",
  680. nodeId
  681. );
  682. if (NmpEnterApi(NmStateOnline)) {
  683. status = GumSendUpdateEx(
  684. GumUpdateMembership,
  685. NmUpdateResumeNode,
  686. 1,
  687. (lstrlenW(nodeId)+1)*sizeof(WCHAR),
  688. nodeId
  689. );
  690. if (status != ERROR_SUCCESS) {
  691. ClRtlLogPrint(LOG_CRITICAL,
  692. "[NM] Global update to resume node %1!ws! failed, status %2!u!\n",
  693. nodeId,
  694. status
  695. );
  696. }
  697. NmpLeaveApi();
  698. }
  699. else {
  700. status = ERROR_NODE_NOT_AVAILABLE;
  701. ClRtlLogPrint(LOG_NOISE,
  702. "[NM] Not in valid state to process ResumeNode request.\n"
  703. );
  704. }
  705. return(status);
  706. } // NmResumeNode
  707. DWORD
  708. NmEvictNode(
  709. IN PNM_NODE Node
  710. )
  711. /*++
  712. Routine Description:
  713. Arguments:
  714. Return Value:
  715. Notes:
  716. The caller must be holding a reference on the node object.
  717. --*/
  718. {
  719. LPCWSTR nodeId = OmObjectId(Node);
  720. DWORD status = ERROR_SUCCESS;
  721. LPCWSTR pcszNodeName = NULL;
  722. HRESULT hrStatus;
  723. BOOL fRunEvictNotifications = TRUE;
  724. int cNodes = 0;
  725. ClRtlLogPrint(LOG_NOISE,
  726. "[NM] Received request to evict node %1!ws!.\n",
  727. nodeId
  728. );
  729. if (NmpEnterApi(NmStateOnline)) {
  730. // Acquire NM lock (to ensure that the number of nodes does not change)
  731. NmpAcquireLock();
  732. // Get the node count while the ability to change it is locked...
  733. cNodes = NmpNodeCount;
  734. if (NmpNodeCount != 1 ) {
  735. NmpReleaseLock();
  736. // We are not evicting the last node.
  737. status = GumSendUpdateEx(
  738. GumUpdateMembership,
  739. NmUpdateEvictNode,
  740. 1,
  741. (lstrlenW(nodeId)+1)*sizeof(WCHAR),
  742. nodeId
  743. );
  744. if ( status != ERROR_SUCCESS ) {
  745. ClRtlLogPrint(LOG_CRITICAL,
  746. "[NM] Global update to evict node %1!ws! failed, status %2!u!\n",
  747. nodeId,
  748. status
  749. );
  750. }
  751. }
  752. else {
  753. // We are evicting the last node. Set a flag to indicate this fact.
  754. if ( NmpLastNodeEvicted == FALSE ) {
  755. NmpLastNodeEvicted = TRUE;
  756. // If we are evicting the last node then we don't want the
  757. // evict notify processing to be called.
  758. //
  759. // It doesn't make any sense to run the evict notification
  760. // processing when we are evicting the last node in the
  761. // cluster.
  762. fRunEvictNotifications = FALSE;
  763. }
  764. else {
  765. // We have already evicted this node. This is an error.
  766. status = ERROR_NODE_NOT_AVAILABLE;
  767. ClRtlLogPrint(LOG_NOISE,
  768. "[NM] Not in valid state to process EvictNode request.\n"
  769. );
  770. }
  771. NmpReleaseLock();
  772. }
  773. // ERROR_NODE_NOT_AVAILABLE can occur because of ClusApi reconnect. We should still attempt to clean
  774. // up the node and notify anyone who cares that the node was evicted.
  775. if ( (status == ERROR_SUCCESS)
  776. || (status == ERROR_NODE_NOT_AVAILABLE)) {
  777. // Get the name of the node...
  778. pcszNodeName = OmObjectName(Node);
  779. // The node was successfully evicted. Now initiate cleanup on that node.
  780. // However, specify that cleanup is to be started only after 60000 ms (1 minute).
  781. //
  782. // This delay is to for anyone using the EvictClusterNodeEx() API. This API will cleanup the
  783. // remote node and return the clean up status as extended error reporting. It is assumed that it
  784. // will do the clean up and return before 60 seconds expires. If a down level client
  785. // is used, EvictClusterNode(), then this call will clean up the remote node after the delay time
  786. // has expired. It was decided to use this mechanism rather than a new RPC call from the API to
  787. // the service. Too much testing is required for this kind of a change.
  788. hrStatus =
  789. ClRtlCleanupNode(
  790. cNodes == 1 ? NULL : pcszNodeName // Name of the node to be cleaned up. When it's the last node pass NULL.
  791. , 60000 // Amount of time (in milliseconds) to wait before starting cleanup
  792. , 0 // timeout interval in milliseconds
  793. );
  794. if ( FAILED( hrStatus ) && ( hrStatus != RPC_S_CALLPENDING ) ) {
  795. ClRtlLogPrint(LOG_UNUSUAL,
  796. "[NM] Failed to initiate cleanup of evicted node %1!ws!, hrStatus 0x%2!x!\n",
  797. nodeId,
  798. hrStatus
  799. );
  800. status = SCODE_CODE( hrStatus );
  801. }
  802. else {
  803. ClRtlLogPrint(LOG_NOISE,
  804. "[NM] Cleanup of evicted node %1!ws! successfully initiated.\n",
  805. nodeId
  806. );
  807. }
  808. // Should we run the evict notification processing?
  809. if ( fRunEvictNotifications ) {
  810. // Now that the node has been evicted and cleaned up we need to notify all who
  811. // care that this has happened.
  812. //
  813. // The evict notification will be sent even if the cleanup above
  814. // fails. Status should not be changed in the block below as we
  815. // don't want a notification failure to show up as an evict error.
  816. hrStatus = ClRtlInitiateEvictNotification( pcszNodeName );
  817. if ( FAILED( hrStatus ) ) {
  818. ClRtlLogPrint(LOG_UNUSUAL,
  819. "[NM] Failed to initiate notification that node %1!ws! was evicted, hrStatus 0x%2!x!\n",
  820. nodeId,
  821. hrStatus
  822. );
  823. //status = SCODE_CODE( hrStatus ); // Don't want to send this failure on to the caller...
  824. }
  825. else {
  826. ClRtlLogPrint(LOG_NOISE,
  827. "[NM] Notification that node %1!ws! was evicted was successfully initiated.\n",
  828. nodeId
  829. );
  830. }
  831. }
  832. }
  833. CsLogEvent1(LOG_UNUSUAL, NM_NODE_EVICTED, OmObjectName(Node));
  834. NmpLeaveApi();
  835. }
  836. else {
  837. status = ERROR_NODE_NOT_AVAILABLE;
  838. ClRtlLogPrint(LOG_NOISE,
  839. "[NM] Not in valid state to process EvictNode request.\n"
  840. );
  841. }
  842. return(status);
  843. } // NmEvictNode
  844. PNM_NODE
  845. NmReferenceNodeById(
  846. IN DWORD NodeId
  847. )
  848. /*++
  849. Routine Description:
  850. Given a node id, returns a referenced pointer to the node object.
  851. The caller is responsible for calling OmDereferenceObject.
  852. Arguments:
  853. NodeId - Supplies the node id
  854. Return Value:
  855. A pointer to the node object if it exists
  856. NULL if there is no such node.
  857. --*/
  858. {
  859. PNM_NODE Node = NULL;
  860. NmpAcquireLock();
  861. if (NmpLockedEnterApi(NmStateOnlinePending)) {
  862. CL_ASSERT(NmIsValidNodeId(NodeId));
  863. CL_ASSERT(NmpIdArray != NULL);
  864. Node = NmpIdArray[NodeId];
  865. if (NmpIdArray[NodeId] != NULL) {
  866. OmReferenceObject(Node);
  867. }
  868. else {
  869. SetLastError(ERROR_CLUSTER_NODE_NOT_FOUND);
  870. }
  871. NmpLockedLeaveApi();
  872. }
  873. else {
  874. SetLastError(ERROR_NODE_NOT_AVAILABLE);
  875. ClRtlLogPrint(LOG_NOISE,
  876. "[NM] Not in valid state to process ReferenceNodeById request.\n"
  877. );
  878. }
  879. NmpReleaseLock();
  880. return(Node);
  881. } // NmReferenceNodeById
  882. PNM_NODE
  883. NmReferenceJoinerNode(
  884. IN DWORD JoinSequence,
  885. IN CL_NODE_ID JoinerNodeId
  886. )
  887. /*++
  888. Routine Description:
  889. Given a node id, returns a referenced pointer to the node object.
  890. The caller is responsible for calling OmDereferenceObject.
  891. Also validates the joiner's information
  892. Arguments:
  893. NodeId - Supplies the node id
  894. Return Value:
  895. A pointer to the node object if it exists
  896. NULL if there is no such node.
  897. Notes:
  898. If the routine is successful, the caller must dereference the
  899. node object by calling NmDereferenceJoiningNode.
  900. --*/
  901. {
  902. PNM_NODE joinerNode = NULL;
  903. DWORD status;
  904. NmpAcquireLock();
  905. if (NmpLockedEnterApi(NmStateOnline)) {
  906. joinerNode = NmpIdArray[JoinerNodeId];
  907. if (joinerNode != NULL) {
  908. if ( (JoinSequence == NmpJoinSequence) &&
  909. (NmpJoinerNodeId == JoinerNodeId)
  910. )
  911. {
  912. OmReferenceObject(joinerNode);
  913. NmpReleaseLock();
  914. //
  915. // Return holding an active thread reference.
  916. //
  917. return(joinerNode);
  918. }
  919. else {
  920. status = ERROR_CLUSTER_JOIN_ABORTED;
  921. }
  922. }
  923. else {
  924. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  925. }
  926. NmpLockedLeaveApi();
  927. }
  928. else {
  929. status = ERROR_NODE_NOT_AVAILABLE;
  930. }
  931. NmpReleaseLock();
  932. if (status != ERROR_SUCCESS) {
  933. SetLastError(status);
  934. }
  935. return(joinerNode);
  936. } // NmReferenceJoinerNode
  937. VOID
  938. NmDereferenceJoinerNode(
  939. PNM_NODE JoinerNode
  940. )
  941. {
  942. OmDereferenceObject(JoinerNode);
  943. NmpLeaveApi();
  944. return;
  945. } // NmDereferenceJoinerNode
  946. CLUSTER_NODE_STATE
  947. NmGetNodeState(
  948. IN PNM_NODE Node
  949. )
  950. /*++
  951. Routine Description:
  952. Arguments:
  953. Return Value:
  954. Notes:
  955. Because the caller must have a reference on the node object and the
  956. call is so simple, there is no reason to put the call through the
  957. EnterApi/LeaveApi dance.
  958. --*/
  959. {
  960. CLUSTER_NODE_STATE state;
  961. NmpAcquireLock();
  962. state = Node->State;
  963. NmpReleaseLock();
  964. return(state);
  965. } // NmGetNodeState
  966. CLUSTER_NODE_STATE
  967. NmGetExtendedNodeState(
  968. IN PNM_NODE Node
  969. )
  970. /*++
  971. Routine Description:
  972. Arguments:
  973. Return Value:
  974. Notes:
  975. Because the caller must have a reference on the node object and the
  976. call is so simple, there is no reason to put the call through the
  977. EnterApi/LeaveApi dance.
  978. --*/
  979. {
  980. CLUSTER_NODE_STATE state;
  981. NmpAcquireLock();
  982. state = Node->State;
  983. if(NM_NODE_UP(Node) ) {
  984. //
  985. // We need to check whether the node is really up
  986. //
  987. switch( Node->ExtendedState ) {
  988. case ClusterNodeUp:
  989. //
  990. // The node explicitly set its extended state to UP immediately after
  991. // ClusterJoin / ClusterForm was complete.
  992. // We need to return either Up or Paused, depending on the node state
  993. //
  994. state = Node->State;
  995. break;
  996. case ClusterNodeDown:
  997. //
  998. // The node explicitly set its extended state to DOWN in the beginning of
  999. // the shutdown process. We will report the node state as down.
  1000. //
  1001. // It is better to have ClusterNodeShuttindDown state for this situation.
  1002. //
  1003. // state = ClusterNodeDown;
  1004. // We do not want to return NodeDown, we really want NodeShuttingDown.
  1005. //
  1006. // Return UP or Paused
  1007. //
  1008. state = Node->State;
  1009. break;
  1010. default:
  1011. //
  1012. // Node is up from NM standpoint, but other components are not up yet.
  1013. //
  1014. state = ClusterNodeJoining;
  1015. }
  1016. }
  1017. NmpReleaseLock();
  1018. return(state);
  1019. } // NmGetExtendedNodeState
  1020. DWORD NmpUpdateExtendedNodeState(
  1021. IN BOOL SourceNode,
  1022. IN LPWSTR NodeId,
  1023. IN CLUSTER_NODE_STATE* ExtendedState
  1024. )
  1025. {
  1026. DWORD status = ERROR_SUCCESS;
  1027. NmpAcquireLock();
  1028. ClRtlLogPrint(LOG_NOISE,
  1029. "[NM] Received update to set extended state for node %1!ws! "
  1030. "to %2!d!\n",
  1031. NodeId,
  1032. *ExtendedState
  1033. );
  1034. if (NmpLockedEnterApi(NmStateOnline)) {
  1035. PNM_NODE node = OmReferenceObjectById(ObjectTypeNode, NodeId);
  1036. if (node != NULL) {
  1037. //
  1038. // Extended State is valid only when the node is online.
  1039. // Ignore the update otherwise.
  1040. //
  1041. if ( NM_NODE_UP(node) ) {
  1042. CLUSTER_EVENT event;
  1043. node->ExtendedState = *ExtendedState;
  1044. if (*ExtendedState == ClusterNodeUp) {
  1045. event = CLUSTER_EVENT_API_NODE_UP;
  1046. } else {
  1047. event = CLUSTER_EVENT_API_NODE_SHUTTINGDOWN;
  1048. }
  1049. ClRtlLogPrint(LOG_NOISE,
  1050. "[NM] Issuing event %1!x!.\n",
  1051. event
  1052. );
  1053. ClusterEvent(event, node);
  1054. }
  1055. OmDereferenceObject(node);
  1056. }
  1057. else {
  1058. ClRtlLogPrint(LOG_NOISE,
  1059. "[NM] Node %1!ws! is not a cluster member. Rejecting request "
  1060. "to set the node's extended state.\n",
  1061. NodeId
  1062. );
  1063. status = ERROR_NODE_NOT_AVAILABLE;
  1064. }
  1065. NmpLockedLeaveApi();
  1066. } else {
  1067. ClRtlLogPrint(LOG_NOISE,
  1068. "[NM] Not in a valid state to process request to set extended "
  1069. "state for node %1!ws!\n",
  1070. NodeId
  1071. );
  1072. status = ERROR_CLUSTER_NODE_NOT_READY;
  1073. }
  1074. NmpReleaseLock();
  1075. return status;
  1076. } // NmpUpdateExtendedNodeState
  1077. DWORD
  1078. NmSetExtendedNodeState(
  1079. IN CLUSTER_NODE_STATE State
  1080. )
  1081. {
  1082. DWORD Status;
  1083. Status = GumSendUpdateEx(
  1084. GumUpdateMembership,
  1085. NmUpdateExtendedNodeState,
  1086. 2,
  1087. sizeof(NmLocalNodeIdString),
  1088. &NmLocalNodeIdString,
  1089. sizeof(CLUSTER_NODE_STATE),
  1090. &State
  1091. );
  1092. if (Status != ERROR_SUCCESS) {
  1093. ClRtlLogPrint(LOG_UNUSUAL,
  1094. "[INIT] NmUpdateExtendedNodeState node failed, status %1!d!.\n", Status);
  1095. }
  1096. return Status;
  1097. } // NmSetExtendedNodeState
  1098. DWORD
  1099. NmGetNodeId(
  1100. IN PNM_NODE Node
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. Returns the given node's node ID.
  1105. Arguments:
  1106. Node - Supplies a pointer to a node object.
  1107. Return Value:
  1108. The node's node id.
  1109. Notes:
  1110. Because the caller must have a reference on the node object and the
  1111. call is so simple, there is no reason to put the call through the
  1112. EnterApi/LeaveApi dance.
  1113. --*/
  1114. {
  1115. DWORD nodeId;
  1116. //
  1117. // Since the caller has a reference on the object, and the node ID can't
  1118. // be changed, it is safe to do this without taking a lock. It is also
  1119. // necessary to prevent some deadlocks.
  1120. //
  1121. nodeId = Node->NodeId;
  1122. return(nodeId);
  1123. } // NmGetNodeId
  1124. HANDLE
  1125. NmGetNodeStateDownEvent(
  1126. IN PNM_NODE Node
  1127. )
  1128. /*++
  1129. Routine Description:
  1130. Returns the given node's Node down event.
  1131. Arguments:
  1132. Node - Supplies a pointer to a node object.
  1133. Return Value:
  1134. Handle of node down event.
  1135. Notes:
  1136. Because the caller must have a reference on the node object and the
  1137. call is so simple, there is no reason to put the call through the
  1138. EnterApi/LeaveApi dance.
  1139. --*/
  1140. {
  1141. // Since caller has reference on the node object. It cannot vanish, the handle is only closed
  1142. // in NmpDestroyNodeObject. Since this is a manual reset event no synchronization is needed.
  1143. return Node->MmNodeStateDownEvent;
  1144. }//NmGetNodeStateDownEvent
  1145. DWORD
  1146. NmGetCurrentNumberOfNodes()
  1147. {
  1148. DWORD dwCnt = 0;
  1149. PLIST_ENTRY pListEntry;
  1150. NmpAcquireLock();
  1151. for ( pListEntry = NmpNodeList.Flink;
  1152. pListEntry != &NmpNodeList;
  1153. pListEntry = pListEntry->Flink )
  1154. {
  1155. dwCnt++;
  1156. }
  1157. NmpReleaseLock();
  1158. return(dwCnt);
  1159. }
  1160. DWORD
  1161. NmGetMaxNodeId(
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. Returns the max node's node ID.
  1166. Arguments:
  1167. Node - Supplies a pointer to a node object.
  1168. Return Value:
  1169. The node's node id.
  1170. Notes:
  1171. Because the caller must have a reference on the node object and the
  1172. call is so simple, there is no reason to put the call through the
  1173. EnterApi/LeaveApi dance.
  1174. --*/
  1175. {
  1176. return(NmMaxNodeId);
  1177. } // NmGetMaxNodeId
  1178. VOID
  1179. NmpAdviseNodeFailure(
  1180. IN PNM_NODE Node,
  1181. IN DWORD ErrorCode
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. Reports that a communication failure to the specified node has occurred.
  1186. A poison packet will be sent to the failed node and regroup initiated.
  1187. Arguments:
  1188. Node - Supplies a pointer to the node object for the failed node.
  1189. ErrorCode - Supplies the error code that was returned from RPC
  1190. Return Value:
  1191. None
  1192. Notes:
  1193. Called with NM lock held.
  1194. --*/
  1195. {
  1196. ClRtlLogPrint(LOG_NOISE,
  1197. "[NM] Received advice that node %1!u! has failed with "
  1198. "error %2!u!.\n",
  1199. Node->NodeId,
  1200. ErrorCode
  1201. );
  1202. if (Node->State != ClusterNodeDown) {
  1203. LPCWSTR nodeName = OmObjectName(Node);
  1204. DWORD status;
  1205. ClRtlLogPrint(LOG_CRITICAL,
  1206. "[NM] Banishing node %1!u! from active cluster membership.\n",
  1207. Node->NodeId
  1208. );
  1209. OmReferenceObject(Node);
  1210. NmpReleaseLock();
  1211. status = MMEject(Node->NodeId);
  1212. if (status == MM_OK) {
  1213. CsLogEvent1(
  1214. LOG_UNUSUAL,
  1215. NM_EVENT_NODE_BANISHED,
  1216. nodeName
  1217. );
  1218. }
  1219. OmDereferenceObject(Node);
  1220. NmpAcquireLock();
  1221. }
  1222. return;
  1223. } // NmpAdviseNodeFailure
  1224. VOID
  1225. NmAdviseNodeFailure(
  1226. IN DWORD NodeId,
  1227. IN DWORD ErrorCode
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. Reports that a communication failure to the specified node has occurred.
  1232. A poison packet will be sent to the failed node and regroup initiated.
  1233. Arguments:
  1234. NodeId - Supplies the node id of the failed node.
  1235. ErrorCode - Supplies the error code that was returned from RPC
  1236. Return Value:
  1237. None
  1238. --*/
  1239. {
  1240. NmpAcquireLock();
  1241. ClRtlLogPrint(LOG_NOISE,
  1242. "[NM] Received advice that node %1!u! has failed with error %2!u!.\n",
  1243. NodeId,
  1244. ErrorCode
  1245. );
  1246. if (NmpLockedEnterApi(NmStateOnline)) {
  1247. PNM_NODE node;
  1248. CL_ASSERT(NmpIdArray != NULL);
  1249. node = NmpIdArray[NodeId];
  1250. NmpAdviseNodeFailure(node, ErrorCode);
  1251. NmpLockedLeaveApi();
  1252. }
  1253. else {
  1254. ClRtlLogPrint(LOG_NOISE,
  1255. "[NM] Not in valid state to process AdviseNodeFailure request.\n"
  1256. );
  1257. }
  1258. NmpReleaseLock();
  1259. return;
  1260. } // NmAdviseNodeFailure
  1261. DWORD
  1262. NmEnumNodeInterfaces(
  1263. IN PNM_NODE Node,
  1264. OUT LPDWORD InterfaceCount,
  1265. OUT PNM_INTERFACE * InterfaceList[]
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. Returns the list of interfaces associated with a specified node.
  1270. Arguments:
  1271. Node - A pointer to the node object for which to enumerate interfaces.
  1272. InterfaceCount - On output, contains the number of items in InterfaceList.
  1273. InterfaceList - On output, points to an array of pointers to interface
  1274. objects. Each pointer in the array must be dereferenced
  1275. by the caller. The storage for the array must be
  1276. deallocated by the caller.
  1277. Return Value:
  1278. ERROR_SUCCESS if the routine is successful.
  1279. A Win32 error code othewise.
  1280. --*/
  1281. {
  1282. DWORD status = ERROR_SUCCESS;
  1283. NmpAcquireLock();
  1284. if (NmpLockedEnterApi(NmStateOnline)) {
  1285. if (Node->InterfaceCount > 0) {
  1286. PNM_INTERFACE * interfaceList = LocalAlloc(
  1287. LMEM_FIXED,
  1288. sizeof(PNM_INTERFACE) *
  1289. Node->InterfaceCount
  1290. );
  1291. if (interfaceList != NULL) {
  1292. PNM_INTERFACE netInterface;
  1293. PLIST_ENTRY entry;
  1294. DWORD i;
  1295. for (entry = Node->InterfaceList.Flink, i=0;
  1296. entry != &(Node->InterfaceList);
  1297. entry = entry->Flink, i++
  1298. )
  1299. {
  1300. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NodeLinkage);
  1301. OmReferenceObject(netInterface);
  1302. interfaceList[i] = netInterface;
  1303. }
  1304. *InterfaceCount = Node->InterfaceCount;
  1305. *InterfaceList = interfaceList;
  1306. }
  1307. else {
  1308. status = ERROR_NOT_ENOUGH_MEMORY;
  1309. }
  1310. }
  1311. else {
  1312. *InterfaceCount = 0;
  1313. *InterfaceList = NULL;
  1314. }
  1315. NmpLockedLeaveApi();
  1316. }
  1317. else {
  1318. status = ERROR_NODE_NOT_AVAILABLE;
  1319. ClRtlLogPrint(LOG_NOISE,
  1320. "[NM] Not in valid state to process EnumNodeInterfaces request.\n"
  1321. );
  1322. }
  1323. NmpReleaseLock();
  1324. return(status);
  1325. } // NmEnumNodeInterfaces
  1326. DWORD
  1327. NmGetNodeHighestVersion(
  1328. IN PNM_NODE Node
  1329. )
  1330. {
  1331. return Node->HighestVersion;
  1332. }
  1333. /////////////////////////////////////////////////////////////////////////////
  1334. //
  1335. // Handlers for global updates
  1336. //
  1337. /////////////////////////////////////////////////////////////////////////////
  1338. DWORD
  1339. NmpUpdateAddNode(
  1340. IN BOOL SourceNode,
  1341. IN LPDWORD NewNodeId,
  1342. IN LPCWSTR NewNodeName,
  1343. IN LPDWORD NewNodeHighestVersion,
  1344. IN LPDWORD NewNodeLowestVersion,
  1345. IN LPDWORD NewNodeProductSuite
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. GUM update handler for adding a new node to a cluster.
  1350. Arguments:
  1351. SourceNode - Specifies whether or not this is the source node for the update
  1352. NodeId - Specifies the ID of the node.
  1353. NewNodeName - A pointer to a string containing the name of the
  1354. new node.
  1355. NewNodeHighestVersion - A pointer to the highest cluster version number
  1356. that the new node can support.
  1357. NewNodeLowestVersion - A pointer to the lowest cluster version number
  1358. that the new node can support.
  1359. NewNodeProductSuite - A pointer to the product suite identifier for
  1360. the new node.
  1361. Return Value:
  1362. ERROR_SUCCESS if successful
  1363. Win32 error code otherwise.
  1364. Notes:
  1365. This routine is used to add an NT5 (or later) node to an NT5 (or
  1366. later) cluster. It will never be invoked in a mixed NT4/NT5
  1367. cluster.
  1368. --*/
  1369. {
  1370. PNM_NODE node = NULL;
  1371. NM_NODE_INFO2 nodeInfo;
  1372. HDMKEY nodeKey = NULL;
  1373. DWORD disposition;
  1374. DWORD status;
  1375. DWORD registryNodeLimit;
  1376. HLOCALXSACTION xaction = NULL;
  1377. BOOLEAN lockAcquired = FALSE;
  1378. if (!NmpEnterApi(NmStateOnline)) {
  1379. ClRtlLogPrint(LOG_UNUSUAL,
  1380. "[NM] This node is not in a valid state to process a request "
  1381. "to add node %1!ws! to the cluster.\n",
  1382. NewNodeName
  1383. );
  1384. return(ERROR_NODE_NOT_AVAILABLE);
  1385. }
  1386. ClRtlLogPrint(LOG_NOISE,
  1387. "[NMJOIN] Received an update to add node '%1!ws!' to "
  1388. "the cluster with node ID %2!u!.\n",
  1389. NewNodeName,
  1390. *NewNodeId
  1391. );
  1392. if (*NewNodeId > NmMaxNodeId) {
  1393. ClRtlLogPrint(LOG_UNUSUAL,
  1394. "[NMJOIN] Failed to add node %1!ws! to the cluster because the "
  1395. "specified node ID, '%2!u!' , is not valid.\n",
  1396. NewNodeName,
  1397. *NewNodeId
  1398. );
  1399. status = ERROR_INVALID_PARAMETER;
  1400. goto error_exit;
  1401. }
  1402. //
  1403. // Read the registry override before acquiring the NM lock.
  1404. //
  1405. status = DmQueryDword(
  1406. DmClusterParametersKey,
  1407. CLUSREG_NAME_MAX_NODES,
  1408. &registryNodeLimit,
  1409. NULL
  1410. );
  1411. if (status != ERROR_SUCCESS) {
  1412. registryNodeLimit = 0;
  1413. }
  1414. //
  1415. // Begin a transaction - This must be done before acquiring the
  1416. // NM lock.
  1417. //
  1418. xaction = DmBeginLocalUpdate();
  1419. if (xaction == NULL) {
  1420. status = GetLastError();
  1421. ClRtlLogPrint(LOG_UNUSUAL,
  1422. "[NM] Failed to begin a transaction to add node %1!ws! "
  1423. "to the cluster, status %2!u!.\n",
  1424. NewNodeName,
  1425. status
  1426. );
  1427. goto error_exit;
  1428. }
  1429. NmpAcquireLock(); lockAcquired = TRUE;
  1430. //
  1431. // Verify that we do not already have the maximum number of nodes
  1432. // allowed in this cluster.
  1433. //
  1434. if (!NmpIsAddNodeAllowed(*NewNodeProductSuite, registryNodeLimit, NULL)) {
  1435. ClRtlLogPrint(LOG_UNUSUAL,
  1436. "[NMJOIN] Cannot add node '%1!ws!' to the cluster. "
  1437. "The cluster already contains the maximum number of nodes "
  1438. "allowed by the product licenses of the current member nodes "
  1439. "and the proposed new node. \n",
  1440. NewNodeName
  1441. );
  1442. status = ERROR_LICENSE_QUOTA_EXCEEDED;
  1443. goto error_exit;
  1444. }
  1445. //
  1446. // Verify that the specified node ID is available.
  1447. //
  1448. if (NmpIdArray[*NewNodeId] != NULL) {
  1449. status = ERROR_CLUSTER_NODE_EXISTS;
  1450. ClRtlLogPrint(LOG_UNUSUAL,
  1451. "[NMJOIN] Cannot add node '%1!ws!' to the cluster because "
  1452. "node ID '%2!u!' is already in use.\n",
  1453. NewNodeName,
  1454. *NewNodeId
  1455. );
  1456. goto error_exit;
  1457. }
  1458. //
  1459. // Try to create a key for the node in the cluster registry.
  1460. //
  1461. wsprintfW(&(nodeInfo.NodeId[0]), L"%u", *NewNodeId);
  1462. nodeKey = DmLocalCreateKey(
  1463. xaction,
  1464. DmNodesKey,
  1465. nodeInfo.NodeId,
  1466. 0,
  1467. KEY_READ | KEY_WRITE,
  1468. NULL,
  1469. &disposition
  1470. );
  1471. if (nodeKey == NULL) {
  1472. status = GetLastError();
  1473. ClRtlLogPrint(LOG_UNUSUAL,
  1474. "[NMJOIN] Failed to create registry key for new "
  1475. "node '%1!ws!' using node ID '%2!u!', status %3!u!\n",
  1476. NewNodeName,
  1477. *NewNodeId,
  1478. status
  1479. );
  1480. goto error_exit;
  1481. }
  1482. if (disposition != REG_CREATED_NEW_KEY) {
  1483. //
  1484. // The key already exists. This must be
  1485. // garbage leftover from a failed evict or oldstyle add.
  1486. // We'll just overwrite the key.
  1487. //
  1488. ClRtlLogPrint(LOG_UNUSUAL,
  1489. "[NMJOIN] A partial definition exists for node ID '%1!u!'. "
  1490. "A node addition or eviction operation may have failed.\n",
  1491. *NewNodeId
  1492. );
  1493. }
  1494. //
  1495. // Add the rest of the node's parameters to the registry.
  1496. //
  1497. status = DmLocalSetValue(
  1498. xaction,
  1499. nodeKey,
  1500. CLUSREG_NAME_NODE_NAME,
  1501. REG_SZ,
  1502. (CONST BYTE *)NewNodeName,
  1503. NM_WCSLEN(NewNodeName)
  1504. );
  1505. if (status != ERROR_SUCCESS) {
  1506. ClRtlLogPrint(LOG_UNUSUAL,
  1507. "[NMJOIN] Failed to set registry value '%1!ws!', status %2!u!. "
  1508. "Cannot add node '%3!ws!' to the cluster.\n",
  1509. CLUSREG_NAME_NODE_NAME,
  1510. status,
  1511. NewNodeName
  1512. );
  1513. goto error_exit;
  1514. }
  1515. status = DmLocalSetValue(
  1516. xaction,
  1517. nodeKey,
  1518. CLUSREG_NAME_NODE_HIGHEST_VERSION,
  1519. REG_DWORD,
  1520. (CONST BYTE *)NewNodeHighestVersion,
  1521. sizeof(DWORD)
  1522. );
  1523. if (status != ERROR_SUCCESS) {
  1524. ClRtlLogPrint(LOG_UNUSUAL,
  1525. "[NMJOIN] Failed to set registry value '%1!ws!', status %2!u!. "
  1526. "Cannot add node '%3!ws!' to the cluster.\n",
  1527. CLUSREG_NAME_NODE_HIGHEST_VERSION,
  1528. status,
  1529. NewNodeName
  1530. );
  1531. goto error_exit;
  1532. }
  1533. status = DmLocalSetValue(
  1534. xaction,
  1535. nodeKey,
  1536. CLUSREG_NAME_NODE_LOWEST_VERSION,
  1537. REG_DWORD,
  1538. (CONST BYTE *)NewNodeLowestVersion,
  1539. sizeof(DWORD)
  1540. );
  1541. if (status != ERROR_SUCCESS) {
  1542. ClRtlLogPrint(LOG_UNUSUAL,
  1543. "[NMJOIN] Failed to set registry value %1!ws!, status %2!u!. "
  1544. "Cannot add node '%3!ws!' to the cluster.\n",
  1545. CLUSREG_NAME_NODE_LOWEST_VERSION,
  1546. status,
  1547. NewNodeName
  1548. );
  1549. goto error_exit;
  1550. }
  1551. status = DmLocalSetValue(
  1552. xaction,
  1553. nodeKey,
  1554. CLUSREG_NAME_NODE_PRODUCT_SUITE,
  1555. REG_DWORD,
  1556. (CONST BYTE *)NewNodeProductSuite,
  1557. sizeof(DWORD)
  1558. );
  1559. if (status != ERROR_SUCCESS) {
  1560. ClRtlLogPrint(LOG_UNUSUAL,
  1561. "[NMJOIN] Failed to set registry value %1!ws!, status %2!u!. "
  1562. "Cannot add node '%3!ws!' to the cluster.\n",
  1563. CLUSREG_NAME_NODE_PRODUCT_SUITE,
  1564. status,
  1565. NewNodeName
  1566. );
  1567. goto error_exit;
  1568. }
  1569. DmCloseKey(nodeKey); nodeKey = NULL;
  1570. status = NmpGetNodeDefinition(&nodeInfo);
  1571. if (status != ERROR_SUCCESS) {
  1572. ClRtlLogPrint(LOG_UNUSUAL,
  1573. "[NMJOIN] Failed to read definition for node %1!ws! from the "
  1574. "cluster database, status %2!u!.\n",
  1575. NewNodeName,
  1576. status
  1577. );
  1578. goto error_exit;
  1579. }
  1580. //
  1581. // If a node happens to be joining right now, flag the fact that
  1582. // it is now out of synch with the cluster config.
  1583. //
  1584. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  1585. ClRtlLogPrint(LOG_NOISE,
  1586. "[NMJOIN] Joiner (ID %1!u!) is now out of sync due to add of "
  1587. "node %2!ws!.\n",
  1588. NmpJoinerNodeId,
  1589. NewNodeName
  1590. );
  1591. NmpJoinerOutOfSynch = TRUE;
  1592. }
  1593. //
  1594. // Create the node object
  1595. //
  1596. NmpReleaseLock();
  1597. node = NmpCreateNodeObject(&nodeInfo);
  1598. ClNetFreeNodeInfo(&nodeInfo);
  1599. NmpAcquireLock();
  1600. if (node == NULL) {
  1601. status = GetLastError();
  1602. ClRtlLogPrint(LOG_UNUSUAL,
  1603. "[NMJOIN] Failed to create object for node %1!ws!, "
  1604. "status %2!u!.\n",
  1605. NewNodeName,
  1606. status
  1607. );
  1608. goto error_exit;
  1609. }
  1610. ClusterEvent(CLUSTER_EVENT_NODE_ADDED, node);
  1611. CsLogEvent1(LOG_NOISE, NM_EVENT_NEW_NODE, NewNodeName);
  1612. //
  1613. // Remove the reference that NmpCreateNodeObject left on the node.
  1614. //
  1615. OmDereferenceObject(node);
  1616. //
  1617. // Reset the cluster version and node limit
  1618. //
  1619. NmpResetClusterVersion(FALSE);
  1620. NmpResetClusterNodeLimit();
  1621. ClRtlLogPrint(LOG_NOISE,
  1622. "[NMJOIN] Successfully added node %1!ws! to the cluster.\n",
  1623. NewNodeName
  1624. );
  1625. error_exit:
  1626. if (lockAcquired) {
  1627. NmpLockedLeaveApi();
  1628. NmpReleaseLock();
  1629. }
  1630. else {
  1631. NmpLeaveApi();
  1632. }
  1633. if (xaction != NULL) {
  1634. if (status == ERROR_SUCCESS) {
  1635. DmCommitLocalUpdate(xaction); xaction = NULL;
  1636. }
  1637. else {
  1638. DmAbortLocalUpdate(xaction);
  1639. }
  1640. }
  1641. if (nodeKey != NULL) {
  1642. DmCloseKey(nodeKey);
  1643. }
  1644. return(status);
  1645. } // NmpUpdateAddNode
  1646. DWORD
  1647. NmpUpdateCreateNode(
  1648. IN BOOL SourceNode,
  1649. IN LPDWORD NodeId
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. GUM update handler for dynamically creating a new node
  1654. Arguments:
  1655. SourceNode - Specifies whether or not this is the source node for the update
  1656. NodeId - Specifies the ID of the node.
  1657. Return Value:
  1658. ERROR_SUCCESS if successful
  1659. Win32 error code otherwise.
  1660. Notes:
  1661. This handler was used by NT4 nodes. Since it is not possible to add
  1662. an NT4 node to a cluster containing an NT5 node, this handler should
  1663. never be called in an NT5 system.
  1664. --*/
  1665. {
  1666. CL_ASSERT(FALSE);
  1667. return(ERROR_CLUSTER_INCOMPATIBLE_VERSIONS);
  1668. } // NmpUpdateCreateNode
  1669. DWORD
  1670. NmpUpdatePauseNode(
  1671. IN BOOL SourceNode,
  1672. IN LPWSTR NodeId
  1673. )
  1674. /*++
  1675. Routine Description:
  1676. GUM update handler for pausing a node
  1677. Arguments:
  1678. SourceNode - Specifies whether or not this is the source node for the update
  1679. NodeId - Specifies the name of the node.
  1680. Return Value:
  1681. ERROR_SUCCESS if successful
  1682. Win32 error code otherwise.
  1683. --*/
  1684. {
  1685. DWORD status = ERROR_SUCCESS;
  1686. HLOCALXSACTION xaction = NULL;
  1687. PNM_NODE node = NULL;
  1688. BOOLEAN lockAcquired = FALSE;
  1689. if (!NmpEnterApi(NmStateOnline)) {
  1690. ClRtlLogPrint(LOG_NOISE,
  1691. "[NM] Not in valid state to process PauseNode update.\n"
  1692. );
  1693. return(ERROR_NODE_NOT_AVAILABLE);
  1694. }
  1695. ClRtlLogPrint(LOG_NOISE,
  1696. "[NM] Received update to pause node %1!ws!\n",
  1697. NodeId
  1698. );
  1699. xaction = DmBeginLocalUpdate();
  1700. if (xaction == NULL) {
  1701. status = GetLastError();
  1702. ClRtlLogPrint(LOG_CRITICAL,
  1703. "[NM] Failed to start a transaction, status %1!u!\n",
  1704. status
  1705. );
  1706. goto error_exit;
  1707. }
  1708. node = OmReferenceObjectById(ObjectTypeNode, NodeId);
  1709. if (node == NULL) {
  1710. status = ERROR_CLUSTER_NODE_NOT_FOUND;
  1711. ClRtlLogPrint(LOG_UNUSUAL,
  1712. "[NM] Node %1!ws! does not exist\n",
  1713. NodeId
  1714. );
  1715. goto error_exit;
  1716. }
  1717. NmpAcquireLock(); lockAcquired = TRUE;
  1718. if (node->NodeId == NmpJoinerNodeId) {
  1719. status = ERROR_CLUSTER_NODE_DOWN;
  1720. ClRtlLogPrint(LOG_UNUSUAL,
  1721. "[NM] Cannot pause node %1!ws! because it is in the process "
  1722. "of joining the cluster.\n",
  1723. NodeId
  1724. );
  1725. goto error_exit;
  1726. }
  1727. if (node->State == ClusterNodeUp) {
  1728. //
  1729. // Update the registry to reflect the new state.
  1730. //
  1731. HDMKEY nodeKey = DmOpenKey(DmNodesKey, NodeId, KEY_WRITE);
  1732. if (nodeKey != NULL) {
  1733. DWORD isPaused = 1;
  1734. status = DmLocalSetValue(
  1735. xaction,
  1736. nodeKey,
  1737. CLUSREG_NAME_NODE_PAUSED,
  1738. REG_DWORD,
  1739. (CONST BYTE *)&isPaused,
  1740. sizeof(isPaused)
  1741. );
  1742. #ifdef CLUSTER_TESTPOINT
  1743. TESTPT(TpFailNmPauseNode) {
  1744. status = 999999;
  1745. }
  1746. #endif
  1747. if (status == ERROR_SUCCESS) {
  1748. node->State = ClusterNodePaused;
  1749. ClusterEvent(CLUSTER_EVENT_NODE_CHANGE, node);
  1750. //
  1751. // If a node happens to be joining right now, flag the
  1752. // fact that it is now out of synch with the cluster config.
  1753. //
  1754. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  1755. ClRtlLogPrint(LOG_NOISE,
  1756. "[NMJOIN] Joiner (ID %1!u!) is now out of sync due "
  1757. "to pause operation on node %2!ws!.\n",
  1758. NmpJoinerNodeId,
  1759. NodeId
  1760. );
  1761. NmpJoinerOutOfSynch = TRUE;
  1762. }
  1763. }
  1764. else {
  1765. ClRtlLogPrint(LOG_UNUSUAL,
  1766. "[NM] Failed to set Paused value for node %1!ws!, "
  1767. "status %2!u!.\n",
  1768. NodeId,
  1769. status
  1770. );
  1771. }
  1772. DmCloseKey(nodeKey);
  1773. }
  1774. else {
  1775. status = GetLastError();
  1776. ClRtlLogPrint(LOG_UNUSUAL,
  1777. "[NM] Failed to open key for node %1!ws!, status %2!u!.\n",
  1778. NodeId,
  1779. status
  1780. );
  1781. }
  1782. }
  1783. else if (node->State != ClusterNodePaused) {
  1784. status = ERROR_CLUSTER_NODE_DOWN;
  1785. }
  1786. error_exit:
  1787. if (lockAcquired) {
  1788. NmpLockedLeaveApi();
  1789. NmpReleaseLock();
  1790. }
  1791. else {
  1792. NmpLeaveApi();
  1793. }
  1794. if (xaction != NULL) {
  1795. if (status == ERROR_SUCCESS) {
  1796. DmCommitLocalUpdate(xaction);
  1797. }
  1798. else {
  1799. DmAbortLocalUpdate(xaction);
  1800. }
  1801. }
  1802. if (node != NULL) {
  1803. OmDereferenceObject(node);
  1804. }
  1805. return(status);
  1806. } // NmpUpdatePauseNode
  1807. DWORD
  1808. NmpUpdateResumeNode(
  1809. IN BOOL SourceNode,
  1810. IN LPWSTR NodeId
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. GUM update handler for resuming a node
  1815. Arguments:
  1816. SourceNode - Specifies whether or not this is the source node for the update
  1817. NodeId - Specifies the name of the node.
  1818. Return Value:
  1819. ERROR_SUCCESS if successful
  1820. Win32 error code otherwise.
  1821. --*/
  1822. {
  1823. DWORD status = ERROR_SUCCESS;
  1824. HLOCALXSACTION xaction = NULL;
  1825. PNM_NODE node = NULL;
  1826. BOOLEAN lockAcquired = FALSE;
  1827. if (!NmpEnterApi(NmStateOnline)) {
  1828. ClRtlLogPrint(LOG_NOISE,
  1829. "[NM] Not in valid state to process ResumeNode update.\n"
  1830. );
  1831. return(ERROR_NODE_NOT_AVAILABLE);
  1832. }
  1833. ClRtlLogPrint(LOG_NOISE,
  1834. "[NM] Received update to resume node %1!ws!\n",
  1835. NodeId
  1836. );
  1837. xaction = DmBeginLocalUpdate();
  1838. if (xaction == NULL) {
  1839. status = GetLastError();
  1840. ClRtlLogPrint(LOG_CRITICAL,
  1841. "[NM] Failed to start a transaction, status %1!u!\n",
  1842. status
  1843. );
  1844. goto error_exit;
  1845. }
  1846. node = OmReferenceObjectById(ObjectTypeNode, NodeId);
  1847. if (node == NULL) {
  1848. status = ERROR_CLUSTER_NODE_NOT_FOUND;
  1849. ClRtlLogPrint(LOG_UNUSUAL,
  1850. "[NM] Node %1!ws! does not exist\n",
  1851. NodeId
  1852. );
  1853. goto error_exit;
  1854. }
  1855. NmpAcquireLock(); lockAcquired = TRUE;
  1856. if (node->NodeId == NmpJoinerNodeId) {
  1857. status = ERROR_CLUSTER_NODE_DOWN;
  1858. ClRtlLogPrint(LOG_UNUSUAL,
  1859. "[NM] Cannot resume node %1!ws! because it is in the process "
  1860. "of joining the cluster.\n",
  1861. NodeId
  1862. );
  1863. goto error_exit;
  1864. }
  1865. if (node->State == ClusterNodePaused) {
  1866. //
  1867. // Update the registry to reflect the new state.
  1868. //
  1869. HDMKEY nodeKey = DmOpenKey(DmNodesKey, NodeId, KEY_WRITE);
  1870. if (nodeKey != NULL) {
  1871. status = DmLocalDeleteValue(
  1872. xaction,
  1873. nodeKey,
  1874. CLUSREG_NAME_NODE_PAUSED
  1875. );
  1876. #ifdef CLUSTER_TESTPOINT
  1877. TESTPT(TpFailNmResumeNode) {
  1878. status = 999999;
  1879. }
  1880. #endif
  1881. if (status == ERROR_SUCCESS) {
  1882. node->State = ClusterNodeUp;
  1883. ClusterEvent(CLUSTER_EVENT_NODE_CHANGE, node);
  1884. //
  1885. // If a node happens to be joining right now, flag the
  1886. // fact that it is now out of synch with the cluster config.
  1887. //
  1888. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  1889. ClRtlLogPrint(LOG_NOISE,
  1890. "[NMJOIN] Joiner (ID %1!u!) is now out of sync due "
  1891. "to resume operation on node %2!ws!.\n",
  1892. NmpJoinerNodeId,
  1893. NodeId
  1894. );
  1895. NmpJoinerOutOfSynch = TRUE;
  1896. }
  1897. }
  1898. else {
  1899. ClRtlLogPrint(LOG_UNUSUAL,
  1900. "[NM] Failed to delete Paused value for node %1!ws!, "
  1901. "status %2!u!.\n",
  1902. NodeId,
  1903. status
  1904. );
  1905. }
  1906. DmCloseKey(nodeKey);
  1907. }
  1908. else {
  1909. status = GetLastError();
  1910. ClRtlLogPrint(LOG_UNUSUAL,
  1911. "[NM] Failed to open key for node %1!ws!, status %2!u!.\n",
  1912. NodeId,
  1913. status
  1914. );
  1915. }
  1916. }
  1917. else {
  1918. status = ERROR_CLUSTER_NODE_NOT_PAUSED;
  1919. }
  1920. error_exit:
  1921. if (lockAcquired) {
  1922. NmpLockedLeaveApi();
  1923. NmpReleaseLock();
  1924. }
  1925. else {
  1926. NmpLeaveApi();
  1927. }
  1928. if (xaction != NULL) {
  1929. if (status == ERROR_SUCCESS) {
  1930. DmCommitLocalUpdate(xaction);
  1931. }
  1932. else {
  1933. DmAbortLocalUpdate(xaction);
  1934. }
  1935. }
  1936. if (node != NULL) {
  1937. OmDereferenceObject(node);
  1938. }
  1939. return(status);
  1940. } // NmpUpdateResumeNode
  1941. DWORD
  1942. NmpUpdateEvictNode(
  1943. IN BOOL SourceNode,
  1944. IN LPWSTR NodeId
  1945. )
  1946. /*++
  1947. Routine Description:
  1948. GUM update handler for evicting a node.
  1949. The specified node is deleted from the OM.
  1950. If the specified node is online, it is paused to prevent any other groups
  1951. from moving there.
  1952. If the specified node is the current node, it attempts to failover any
  1953. owned groups.
  1954. Arguments:
  1955. SourceNode - Specifies whether or not this is the source node for the update
  1956. NodeId - Specifies the name of the node.
  1957. Return Value:
  1958. ERROR_SUCCESS if successful
  1959. Win32 error code otherwise.
  1960. Notes:
  1961. It is very hard to make this operation abortable, so it isn't. If anything
  1962. goes wrong past a certain point, the node will halt.
  1963. Assumption: Since global updates are serialized, and local transactions
  1964. guarantee exclusive access to the registry, no other updates can be made in
  1965. parallel by the FM.
  1966. --*/
  1967. {
  1968. DWORD status = ERROR_SUCCESS;
  1969. PNM_NODE node = NULL;
  1970. HLOCALXSACTION xaction = NULL;
  1971. PNM_NETWORK network;
  1972. LPCWSTR networkId;
  1973. PNM_INTERFACE netInterface;
  1974. LPCWSTR interfaceId;
  1975. PLIST_ENTRY entry;
  1976. BOOLEAN lockAcquired = FALSE;
  1977. if (!NmpEnterApi(NmStateOnline)) {
  1978. ClRtlLogPrint(LOG_NOISE,
  1979. "[NM] Not in valid state to process EvictNode update.\n"
  1980. );
  1981. return(ERROR_NODE_NOT_AVAILABLE);
  1982. }
  1983. ClRtlLogPrint(LOG_NOISE,
  1984. "[NM] Received update to evict node %1!ws!\n",
  1985. NodeId
  1986. );
  1987. node = OmReferenceObjectById(ObjectTypeNode, NodeId);
  1988. if (node == NULL) {
  1989. ClRtlLogPrint(LOG_UNUSUAL,
  1990. "[NM] Node %1!ws! does not exist\n",
  1991. NodeId
  1992. );
  1993. status = ERROR_CLUSTER_NODE_NOT_FOUND;
  1994. goto error_exit;
  1995. }
  1996. //
  1997. // Begin a transaction
  1998. //
  1999. xaction = DmBeginLocalUpdate();
  2000. if (xaction == NULL) {
  2001. status = GetLastError();
  2002. ClRtlLogPrint(LOG_CRITICAL,
  2003. "[NM] Failed to start a transaction, status %1!u!\n",
  2004. status
  2005. );
  2006. goto error_exit;
  2007. }
  2008. NmpAcquireLock(); lockAcquired = TRUE;
  2009. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  2010. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  2011. ClRtlLogPrint(LOG_NOISE,
  2012. "[NM] Cannot evict node because a join is in progress.\n"
  2013. );
  2014. goto error_exit;
  2015. }
  2016. //
  2017. // Only continue if the node is down. Evicting a node while it
  2018. // is actively participating in the cluster is way too tricky.
  2019. //
  2020. if (node->State != ClusterNodeDown) {
  2021. status = ERROR_CANT_EVICT_ACTIVE_NODE;
  2022. ClRtlLogPrint(LOG_CRITICAL,
  2023. "[NM] Node %1!ws! cannot be evicted because it is not offline.\n",
  2024. NodeId
  2025. );
  2026. goto error_exit;
  2027. }
  2028. //
  2029. // Scrub the FM's portion of the registry of all references to this node.
  2030. //
  2031. status = NmpCleanseRegistry(NodeId, xaction);
  2032. if (status != ERROR_SUCCESS) {
  2033. ClRtlLogPrint(LOG_CRITICAL,
  2034. "[NM] Failed to remove all resource database references to "
  2035. "evicted node %1!ws!, status %2!u!\n",
  2036. NodeId,
  2037. status
  2038. );
  2039. goto error_exit;
  2040. }
  2041. //
  2042. // Delete the node's interfaces from the database.
  2043. //
  2044. for (entry = node->InterfaceList.Flink;
  2045. entry != &(node->InterfaceList);
  2046. entry = entry->Flink
  2047. )
  2048. {
  2049. netInterface = CONTAINING_RECORD(
  2050. entry,
  2051. NM_INTERFACE,
  2052. NodeLinkage
  2053. );
  2054. interfaceId = OmObjectId(netInterface);
  2055. network = netInterface->Network;
  2056. networkId = OmObjectId(network);
  2057. //
  2058. // Delete the interface definition from the database.
  2059. //
  2060. status = DmLocalDeleteTree(xaction, DmNetInterfacesKey, interfaceId);
  2061. if (status != ERROR_SUCCESS) {
  2062. ClRtlLogPrint(LOG_CRITICAL,
  2063. "[NM] Failed to delete definition for interface %1!ws!, "
  2064. "status %2!u!.\n",
  2065. interfaceId,
  2066. status
  2067. );
  2068. goto error_exit;
  2069. }
  2070. if (network->InterfaceCount == 1) {
  2071. //
  2072. // This is the last interface on the network.
  2073. // Delete the network too.
  2074. //
  2075. status = DmLocalDeleteTree(xaction, DmNetworksKey, networkId);
  2076. if (status != ERROR_SUCCESS) {
  2077. ClRtlLogPrint(LOG_CRITICAL,
  2078. "[NM] Failed to delete definition for network %1!ws!, "
  2079. "status %2!u!.\n",
  2080. networkId,
  2081. status
  2082. );
  2083. goto error_exit;
  2084. }
  2085. }
  2086. }
  2087. //
  2088. // Delete the node's database entry
  2089. //
  2090. status = DmLocalDeleteTree(xaction, DmNodesKey, NodeId);
  2091. #ifdef CLUSTER_TESTPOINT
  2092. TESTPT(TpFailNmEvictNodeAbort) {
  2093. status = 999999;
  2094. }
  2095. #endif
  2096. if (status != ERROR_SUCCESS) {
  2097. ClRtlLogPrint(LOG_CRITICAL,
  2098. "[NM] Failed to delete node's database key, status %1!u!\n",
  2099. status
  2100. );
  2101. goto error_exit;
  2102. }
  2103. //
  2104. // WARNING: From here on, operations cannot be reversed.
  2105. // If any one of them fails, this node must halt to avoid being
  2106. // inconsistent.
  2107. //
  2108. //
  2109. // Delete the interface objects associated with this node.
  2110. //
  2111. while (!IsListEmpty(&(node->InterfaceList))) {
  2112. entry = node->InterfaceList.Flink;
  2113. netInterface = CONTAINING_RECORD(
  2114. entry,
  2115. NM_INTERFACE,
  2116. NodeLinkage
  2117. );
  2118. network = netInterface->Network;
  2119. networkId = OmObjectId(network);
  2120. NmpDeleteInterfaceObject(netInterface, TRUE);
  2121. if (network->InterfaceCount == 0) {
  2122. //
  2123. // This is the last interface on the network.
  2124. // Delete the network too.
  2125. //
  2126. NmpDeleteNetworkObject(network, TRUE);
  2127. }
  2128. }
  2129. //
  2130. // Delete the node's object.
  2131. //
  2132. NmpDeleteNodeObject(node, TRUE);
  2133. //after the node is deleted, recalculate the operational version of
  2134. //the cluster
  2135. NmpResetClusterVersion(TRUE);
  2136. //calculate the operational limit on the number of nodes that
  2137. //can be a part of this cluster
  2138. NmpResetClusterNodeLimit();
  2139. NmpReleaseLock(); lockAcquired = FALSE;
  2140. #ifdef CLUSTER_TESTPOINT
  2141. TESTPT(TpFailNmEvictNodeHalt) {
  2142. status = 999999;
  2143. }
  2144. #endif
  2145. if (status != ERROR_SUCCESS ) {
  2146. WCHAR string[16];
  2147. wsprintfW(&(string[0]), L"%u", status);
  2148. ClRtlLogPrint(LOG_CRITICAL,
  2149. "[NM] FATAL ERROR: Failed to remove all resource references to evicted node %1!ws!, status %2!u!\n",
  2150. NodeId,
  2151. status
  2152. );
  2153. CsLogEvent3(
  2154. LOG_CRITICAL,
  2155. NM_EVENT_EVICTION_ERROR,
  2156. NmLocalNodeName,
  2157. OmObjectName(node),
  2158. string
  2159. );
  2160. CsInconsistencyHalt(status);
  2161. }
  2162. CL_ASSERT(status == ERROR_SUCCESS);
  2163. error_exit:
  2164. if (lockAcquired) {
  2165. NmpLockedLeaveApi();
  2166. NmpReleaseLock();
  2167. }
  2168. else {
  2169. NmpLeaveApi();
  2170. }
  2171. if (xaction != NULL) {
  2172. if (status == ERROR_SUCCESS) {
  2173. DmCommitLocalUpdate(xaction);
  2174. }
  2175. else {
  2176. DmAbortLocalUpdate(xaction);
  2177. }
  2178. }
  2179. if (node != NULL) {
  2180. OmDereferenceObject(node);
  2181. }
  2182. if (status != ERROR_SUCCESS) {
  2183. ClRtlLogPrint(LOG_CRITICAL,
  2184. "[NM] Failed to evict node %1!ws!.\n",
  2185. NodeId
  2186. );
  2187. }
  2188. return(status);
  2189. } // NmpUpdateEvictNode
  2190. /////////////////////////////////////////////////////////////////////////////
  2191. //
  2192. // Database management routines
  2193. //
  2194. /////////////////////////////////////////////////////////////////////////////
  2195. DWORD
  2196. NmpGetNodeDefinition(
  2197. IN OUT PNM_NODE_INFO2 NodeInfo
  2198. )
  2199. /*++
  2200. Routine Description:
  2201. Reads information about a defined cluster node from the cluster database
  2202. and stores the information in a supplied structure.
  2203. Arguments:
  2204. NodeInfo - A pointer to the structure into which to store the node
  2205. information. The NodeId field of the structure contains
  2206. the ID of the node for which to read information.
  2207. Return Value:
  2208. ERROR_SUCCESS if the routine succeeds.
  2209. A Win32 error code otherwise.
  2210. --*/
  2211. {
  2212. DWORD status;
  2213. HDMKEY nodeKey = NULL;
  2214. DWORD valueLength;
  2215. DWORD valueType;
  2216. LPWSTR string;
  2217. WCHAR errorString[12];
  2218. nodeKey = DmOpenKey(DmNodesKey, NodeInfo->NodeId, KEY_READ);
  2219. if (nodeKey == NULL) {
  2220. status = GetLastError();
  2221. wsprintfW(&(errorString[0]), L"%u", status);
  2222. CsLogEvent2(
  2223. LOG_CRITICAL,
  2224. CS_EVENT_REG_OPEN_FAILED,
  2225. NodeInfo->NodeId,
  2226. errorString
  2227. );
  2228. ClRtlLogPrint(LOG_CRITICAL,
  2229. "[NM] Failed to open node key, status %1!u!\n",
  2230. status
  2231. );
  2232. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2233. goto error_exit;
  2234. }
  2235. valueLength = sizeof(NodeInfo->NodeName);
  2236. string = CLUSREG_NAME_NODE_NAME;
  2237. status = DmQueryValue(
  2238. nodeKey,
  2239. string,
  2240. &valueType,
  2241. (LPBYTE) &(NodeInfo->NodeName[0]),
  2242. &valueLength
  2243. );
  2244. if (status != ERROR_SUCCESS) {
  2245. wsprintfW(&(errorString[0]), L"%u", status);
  2246. CsLogEvent2(
  2247. LOG_CRITICAL,
  2248. CS_EVENT_REG_QUERY_FAILED,
  2249. string,
  2250. errorString
  2251. );
  2252. ClRtlLogPrint(LOG_CRITICAL,
  2253. "[NM] Failed to read node name, status %1!u!\n",
  2254. status
  2255. );
  2256. goto error_exit;
  2257. }
  2258. if (valueType != REG_SZ) {
  2259. status = ERROR_INVALID_PARAMETER;
  2260. wsprintfW(&(errorString[0]), L"%u", status);
  2261. CsLogEvent2(
  2262. LOG_CRITICAL,
  2263. CS_EVENT_REG_QUERY_FAILED,
  2264. string,
  2265. errorString
  2266. );
  2267. goto error_exit;
  2268. }
  2269. //read the node's highest version
  2270. string = CLUSREG_NAME_NODE_HIGHEST_VERSION;
  2271. status = DmQueryDword(nodeKey, string, &NodeInfo->NodeHighestVersion,
  2272. NULL);
  2273. if (status != ERROR_SUCCESS)
  2274. {
  2275. wsprintfW(&(errorString[0]), L"%u", status);
  2276. CsLogEvent2(
  2277. LOG_CRITICAL,
  2278. CS_EVENT_REG_QUERY_FAILED,
  2279. string,
  2280. errorString
  2281. );
  2282. //this can happen on an upgrade from sp3 to nt5
  2283. //assume the node highest version is that of sp3
  2284. //the fixup function will get this fixed
  2285. NodeInfo->NodeHighestVersion = CLUSTER_MAKE_VERSION(1, 224);
  2286. }
  2287. //read the node's lowest version
  2288. string = CLUSREG_NAME_NODE_LOWEST_VERSION;
  2289. status = DmQueryDword(nodeKey, string, &NodeInfo->NodeLowestVersion,
  2290. NULL);
  2291. if (status != ERROR_SUCCESS)
  2292. {
  2293. wsprintfW(&(errorString[0]), L"%u", status);
  2294. CsLogEvent2(
  2295. LOG_CRITICAL,
  2296. CS_EVENT_REG_QUERY_FAILED,
  2297. string,
  2298. errorString
  2299. );
  2300. //this can happen on upgrade from sp3 to nt5
  2301. //if the nodelowestversion is not present assume it
  2302. //was an sp3 node(lowest version is 1.224)
  2303. NodeInfo->NodeLowestVersion = CLUSTER_MAKE_VERSION( 1, 224);
  2304. }
  2305. NodeInfo->State = ClusterNodeDown;
  2306. DmCloseKey(nodeKey);
  2307. return(ERROR_SUCCESS);
  2308. error_exit:
  2309. ClNetFreeNodeInfo(NodeInfo);
  2310. if (nodeKey != NULL) {
  2311. DmCloseKey(nodeKey);
  2312. }
  2313. return(status);
  2314. } // NmpGetNodeDefinition
  2315. DWORD
  2316. NmpGetNodeAuxInfo(
  2317. IN LPCWSTR NodeId,
  2318. IN OUT PNM_NODE_AUX_INFO pNodeAuxInfo
  2319. )
  2320. /*++
  2321. Routine Description:
  2322. Reads information about a defined cluster node from the cluster database
  2323. and stores the information in a supplied structure.
  2324. Arguments:
  2325. pNodeAuxInfo - A pointer to the structure into which to store the node
  2326. information. The NodeId field of the structure contains
  2327. the ID of the node for which to read information.
  2328. Return Value:
  2329. ERROR_SUCCESS if the routine succeeds.
  2330. A Win32 error code otherwise.
  2331. --*/
  2332. {
  2333. DWORD status;
  2334. HDMKEY nodeKey = NULL;
  2335. DWORD valueLength;
  2336. DWORD valueType;
  2337. LPWSTR string;
  2338. WCHAR errorString[12];
  2339. nodeKey = DmOpenKey(DmNodesKey, NodeId, KEY_READ);
  2340. if (nodeKey == NULL)
  2341. {
  2342. status = GetLastError();
  2343. wsprintfW(&(errorString[0]), L"%u", status);
  2344. CsLogEvent2(
  2345. LOG_CRITICAL,
  2346. CS_EVENT_REG_OPEN_FAILED,
  2347. NodeId,
  2348. errorString
  2349. );
  2350. ClRtlLogPrint(LOG_CRITICAL,
  2351. "[NM] NmpGetNodeAuxInfo : Failed to open node key, "
  2352. "status %1!u!\n",
  2353. status);
  2354. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2355. goto error_exit;
  2356. }
  2357. //read the node's product suite
  2358. string = CLUSREG_NAME_NODE_PRODUCT_SUITE;
  2359. status = DmQueryDword(
  2360. nodeKey,
  2361. string,
  2362. (LPDWORD)&(pNodeAuxInfo->ProductSuite),
  2363. NULL
  2364. );
  2365. if (status != ERROR_SUCCESS)
  2366. {
  2367. wsprintfW(&(errorString[0]), L"%u", status);
  2368. CsLogEvent2(
  2369. LOG_NOISE,
  2370. CS_EVENT_REG_QUERY_FAILED,
  2371. string,
  2372. errorString
  2373. );
  2374. //assume it is enterprise
  2375. pNodeAuxInfo->ProductSuite = Enterprise;
  2376. }
  2377. DmCloseKey(nodeKey);
  2378. return(ERROR_SUCCESS);
  2379. error_exit:
  2380. if (nodeKey != NULL)
  2381. {
  2382. DmCloseKey(nodeKey);
  2383. }
  2384. return(status);
  2385. } // NmpGetNodeAuxInfo
  2386. DWORD
  2387. NmpEnumNodeDefinitions(
  2388. PNM_NODE_ENUM2 * NodeEnum
  2389. )
  2390. /*++
  2391. Routine Description:
  2392. Reads information about all defined cluster nodes from the cluster
  2393. database and builds an enumeration structure containing the information.
  2394. Arguments:
  2395. NodeEnum - A pointer to the variable into which to place a pointer to
  2396. the allocated node enumeration.
  2397. Return Value:
  2398. ERROR_SUCCESS if the routine succeeds.
  2399. A Win32 error code otherwise.
  2400. Notes:
  2401. This routine MUST NOT be called with the NM lock held.
  2402. --*/
  2403. {
  2404. DWORD status;
  2405. PNM_NODE_ENUM2 nodeEnum = NULL;
  2406. DWORD i;
  2407. DWORD valueLength;
  2408. DWORD numNodes;
  2409. DWORD ignored;
  2410. FILETIME fileTime;
  2411. WCHAR errorString[12];
  2412. HLOCALXSACTION xaction;
  2413. BOOLEAN commitXaction = FALSE;
  2414. *NodeEnum = NULL;
  2415. //
  2416. // Begin a transaction - this must not be done while holding
  2417. // the NM lock.
  2418. //
  2419. xaction = DmBeginLocalUpdate();
  2420. if (xaction == NULL) {
  2421. status = GetLastError();
  2422. ClRtlLogPrint(LOG_UNUSUAL,
  2423. "[NM] Failed to begin a transaction, status %1!u!.\n",
  2424. status
  2425. );
  2426. }
  2427. NmpAcquireLock();
  2428. //
  2429. // First count the number of nodes.
  2430. //
  2431. status = DmQueryInfoKey(
  2432. DmNodesKey,
  2433. &numNodes,
  2434. &ignored, // MaxSubKeyLen
  2435. &ignored, // Values
  2436. &ignored, // MaxValueNameLen
  2437. &ignored, // MaxValueLen
  2438. &ignored, // lpcbSecurityDescriptor
  2439. &fileTime
  2440. );
  2441. if (status != ERROR_SUCCESS) {
  2442. wsprintfW(&(errorString[0]), L"%u", status);
  2443. CsLogEvent1(LOG_CRITICAL, CS_EVENT_REG_OPERATION_FAILED, errorString);
  2444. ClRtlLogPrint(LOG_CRITICAL,
  2445. "[NM] Failed to query Nodes key information, status %1!u!\n",
  2446. status
  2447. );
  2448. goto error_exit;
  2449. }
  2450. valueLength = sizeof(NM_NODE_ENUM2) +
  2451. (sizeof(NM_NODE_INFO2) * (numNodes - 1));
  2452. nodeEnum = MIDL_user_allocate(valueLength);
  2453. if (nodeEnum == NULL) {
  2454. status = ERROR_NOT_ENOUGH_MEMORY;
  2455. wsprintfW(&(errorString[0]), L"%u", status);
  2456. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  2457. ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory.\n");
  2458. goto error_exit;
  2459. }
  2460. ZeroMemory(nodeEnum, valueLength);
  2461. for (i=0; i < numNodes; i++) {
  2462. valueLength = sizeof(nodeEnum->NodeList[nodeEnum->NodeCount].NodeId);
  2463. status = DmEnumKey(
  2464. DmNodesKey,
  2465. i,
  2466. &(nodeEnum->NodeList[nodeEnum->NodeCount].NodeId[0]),
  2467. &valueLength,
  2468. NULL
  2469. );
  2470. if (status != ERROR_SUCCESS) {
  2471. wsprintfW(&(errorString[0]), L"%u", status);
  2472. CsLogEvent1(
  2473. LOG_CRITICAL,
  2474. CS_EVENT_REG_OPERATION_FAILED,
  2475. errorString
  2476. );
  2477. ClRtlLogPrint(LOG_CRITICAL,
  2478. "[NM] Failed to enumerate node key, status %1!u!\n",
  2479. status
  2480. );
  2481. goto error_exit;
  2482. }
  2483. status = NmpGetNodeDefinition(
  2484. &(nodeEnum->NodeList[nodeEnum->NodeCount])
  2485. );
  2486. if (status != ERROR_SUCCESS) {
  2487. if (status == ERROR_FILE_NOT_FOUND) {
  2488. //
  2489. // Partial node definition in the database.
  2490. // Probably from a failed AddNode operation.
  2491. //
  2492. LPWSTR nodeIdString =
  2493. nodeEnum->NodeList[nodeEnum->NodeCount].NodeId;
  2494. DWORD nodeId = wcstoul(
  2495. nodeIdString,
  2496. NULL,
  2497. 10
  2498. );
  2499. //
  2500. // Delete the key and ignore it in the enum struct if it
  2501. // is safe to do so.
  2502. //
  2503. if ( (NmpIdArray[nodeId] == NULL) &&
  2504. (nodeId != NmLocalNodeId)
  2505. )
  2506. {
  2507. if (xaction != NULL) {
  2508. DWORD status2;
  2509. ClRtlLogPrint(LOG_CRITICAL,
  2510. "[NM] Deleting partial definition for node "
  2511. "ID %1!ws!\n",
  2512. nodeIdString
  2513. );
  2514. status2 = DmLocalDeleteKey(
  2515. xaction,
  2516. DmNodesKey,
  2517. nodeIdString
  2518. );
  2519. if (status2 == ERROR_SUCCESS) {
  2520. commitXaction = TRUE;
  2521. }
  2522. }
  2523. }
  2524. continue;
  2525. }
  2526. goto error_exit;
  2527. }
  2528. nodeEnum->NodeCount++;
  2529. }
  2530. *NodeEnum = nodeEnum;
  2531. CL_ASSERT(status == ERROR_SUCCESS);
  2532. error_exit:
  2533. NmpReleaseLock();
  2534. if (xaction != NULL) {
  2535. if ((status == ERROR_SUCCESS) && commitXaction) {
  2536. DmCommitLocalUpdate(xaction);
  2537. }
  2538. else {
  2539. DmAbortLocalUpdate(xaction);
  2540. }
  2541. }
  2542. if ((status != ERROR_SUCCESS) && (nodeEnum != NULL)) {
  2543. ClNetFreeNodeEnum(nodeEnum);
  2544. }
  2545. return(status);
  2546. } // NmpEnumNodeDefinitions
  2547. /////////////////////////////////////////////////////////////////////////////
  2548. //
  2549. // Object management routines
  2550. //
  2551. /////////////////////////////////////////////////////////////////////////////
  2552. DWORD
  2553. NmpCreateNodeObjects(
  2554. IN PNM_NODE_ENUM2 NodeEnum
  2555. )
  2556. /*++
  2557. Routine Description:
  2558. Processes a node information enumeration and creates node objects.
  2559. Arguments:
  2560. NodeEnum - A pointer to a node information enumeration structure.
  2561. Return Value:
  2562. ERROR_SUCCESS if the routine completes successfully.
  2563. A Win32 error code otherwise.
  2564. --*/
  2565. {
  2566. DWORD status = ERROR_SUCCESS;
  2567. PNM_NODE_INFO2 nodeInfo;
  2568. DWORD i;
  2569. PNM_NODE node;
  2570. BOOLEAN foundLocalNode = FALSE;
  2571. for (i=0; i < NodeEnum->NodeCount; i++) {
  2572. nodeInfo = &(NodeEnum->NodeList[i]);
  2573. //
  2574. // The local node object was created during initialization.
  2575. // Skip it.
  2576. //
  2577. if (wcscmp(NmLocalNodeIdString, nodeInfo->NodeId) != 0) {
  2578. node = NmpCreateNodeObject(nodeInfo);
  2579. if (node == NULL) {
  2580. status = GetLastError();
  2581. break;
  2582. }
  2583. else {
  2584. OmDereferenceObject(node);
  2585. }
  2586. }
  2587. else {
  2588. foundLocalNode = TRUE;
  2589. }
  2590. }
  2591. if ( !foundLocalNode ) {
  2592. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2593. }
  2594. return(status);
  2595. } // NmpCreateNodeObjects
  2596. DWORD
  2597. NmpCreateLocalNodeObject(
  2598. IN PNM_NODE_INFO2 NodeInfo
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. Creates a node object for the local node given information about the node.
  2603. Arguments:
  2604. NodeInfo - A pointer to a structure containing a description of the node
  2605. to create.
  2606. Return Value:
  2607. ERROR_SUCCESS if the routine completes successfully.
  2608. A Win32 error code otherwise.
  2609. --*/
  2610. {
  2611. DWORD status;
  2612. LPWSTR string;
  2613. CL_ASSERT(NmLocalNode == NULL);
  2614. //
  2615. // Verify that the node name matches the local computername.
  2616. //
  2617. if (wcscmp(NodeInfo->NodeName, NmLocalNodeName) != 0) {
  2618. string = L"";
  2619. CsLogEvent2(
  2620. LOG_CRITICAL,
  2621. NM_EVENT_NODE_NOT_MEMBER,
  2622. NmLocalNodeName,
  2623. string
  2624. );
  2625. ClRtlLogPrint(LOG_CRITICAL,
  2626. "[NM] Computername does not match node name in database.\n"
  2627. );
  2628. return(ERROR_INVALID_PARAMETER);
  2629. }
  2630. NmLocalNode = NmpCreateNodeObject(NodeInfo);
  2631. if (NmLocalNode == NULL) {
  2632. status = GetLastError();
  2633. ClRtlLogPrint(LOG_CRITICAL,
  2634. "[NM] Failed to create local node (%1!ws!), status %2!u!.\n",
  2635. NodeInfo->NodeId,
  2636. status
  2637. );
  2638. return(status);
  2639. }
  2640. else {
  2641. NmLocalNode->ExtendedState = ClusterNodeJoining;
  2642. OmDereferenceObject(NmLocalNode);
  2643. }
  2644. return(ERROR_SUCCESS);
  2645. }
  2646. PNM_NODE
  2647. NmpCreateNodeObject(
  2648. IN PNM_NODE_INFO2 NodeInfo
  2649. )
  2650. /*++
  2651. Routine Description:
  2652. Creates a node object given information about the node.
  2653. Arguments:
  2654. NodeInfo - A pointer to a structure containing a description of the node
  2655. to create.
  2656. Return Value:
  2657. A pointer to the created node object if successful.
  2658. NULL if not successful. Extended error information is available
  2659. from GetLastError().
  2660. --*/
  2661. {
  2662. PNM_NODE node = NULL;
  2663. DWORD status = ERROR_SUCCESS;
  2664. BOOL created = FALSE;
  2665. DWORD eventCode = 0;
  2666. WCHAR errorString[12];
  2667. ClRtlLogPrint(LOG_NOISE,
  2668. "[NM] Creating object for node %1!ws! (%2!ws!)\n",
  2669. NodeInfo->NodeId,
  2670. NodeInfo->NodeName
  2671. );
  2672. //
  2673. // Make sure that the node doesn't already exist.
  2674. //
  2675. node = OmReferenceObjectById(ObjectTypeNode, NodeInfo->NodeId);
  2676. if (node == NULL) {
  2677. //
  2678. // Make sure that the node doesn't already exist, this time by name.
  2679. //
  2680. node = OmReferenceObjectByName(ObjectTypeNode, NodeInfo->NodeName);
  2681. }
  2682. if (node != NULL) {
  2683. OmDereferenceObject(node);
  2684. ClRtlLogPrint(LOG_CRITICAL,
  2685. "[NM] Object already exists for node %1!ws!\n",
  2686. NodeInfo->NodeId
  2687. );
  2688. SetLastError(ERROR_OBJECT_ALREADY_EXISTS);
  2689. return(NULL);
  2690. }
  2691. node = OmCreateObject(
  2692. ObjectTypeNode,
  2693. NodeInfo->NodeId,
  2694. NodeInfo->NodeName,
  2695. &created
  2696. );
  2697. if (node == NULL) {
  2698. status = GetLastError();
  2699. wsprintfW(&(errorString[0]), L"%u", status);
  2700. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  2701. ClRtlLogPrint(LOG_CRITICAL,
  2702. "[NM] Failed to create object for node %1!ws! (%2!ws!), status %3!u!\n",
  2703. NodeInfo->NodeId,
  2704. NodeInfo->NodeName,
  2705. status
  2706. );
  2707. SetLastError(status);
  2708. return(NULL);
  2709. }
  2710. CL_ASSERT(created == TRUE);
  2711. ZeroMemory(node, sizeof(NM_NODE));
  2712. node->NodeId = wcstoul(NodeInfo->NodeId, NULL, 10);
  2713. node->State = NodeInfo->State;
  2714. // Create the MM node state down event. This event tracks what MM thinks of the node state.
  2715. if (NM_NODE_UP(node)) {
  2716. node->MmNodeStateDownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  2717. }
  2718. else {
  2719. node->MmNodeStateDownEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  2720. }
  2721. if (node->MmNodeStateDownEvent == NULL) {
  2722. status = GetLastError();
  2723. ClRtlLogPrint(LOG_CRITICAL,
  2724. "[NM] Failed to create node down event for node=%1!u! status=%2!u!.\n",
  2725. node->NodeId,
  2726. status
  2727. );
  2728. goto error_exit;
  2729. }
  2730. // A join cannot proceed if any of the current node's ExtendedState is not up. But the State might be paused.
  2731. // So don't copy the State field into ExtendedState field. (#379170)
  2732. node->ExtendedState = ClusterNodeUp;
  2733. node->HighestVersion = NodeInfo->NodeHighestVersion;
  2734. node->LowestVersion = NodeInfo->NodeLowestVersion;
  2735. //for now assume enterprise
  2736. //NmpRefresh will fixup this information later..
  2737. node->ProductSuite = Enterprise;
  2738. InitializeListHead(&(node->InterfaceList));
  2739. CL_ASSERT(NmIsValidNodeId(node->NodeId));
  2740. if (node->NodeId != NmLocalNodeId) {
  2741. status = ClusnetRegisterNode(NmClusnetHandle, node->NodeId);
  2742. if (status != ERROR_SUCCESS) {
  2743. wsprintfW(&(errorString[0]), L"%u", status);
  2744. CsLogEvent2(
  2745. LOG_CRITICAL,
  2746. NM_EVENT_CLUSNET_REGISTER_NODE_FAILED,
  2747. NodeInfo->NodeId,
  2748. errorString
  2749. );
  2750. ClRtlLogPrint(LOG_CRITICAL,
  2751. "[NM] Failed to register node %1!ws! (%2!ws!) with the Cluster Network, status %3!u!\n",
  2752. NodeInfo->NodeId,
  2753. NodeInfo->NodeName,
  2754. status
  2755. );
  2756. goto error_exit;
  2757. }
  2758. }
  2759. //
  2760. // Put a reference on the object for the caller.
  2761. //
  2762. OmReferenceObject(node);
  2763. NmpAcquireLock();
  2764. if (NM_NODE_UP(node)) {
  2765. //
  2766. // Add this node to the up nodes set
  2767. //
  2768. BitsetAdd(NmpUpNodeSet, node->NodeId);
  2769. //
  2770. // Enable communication with this node during the
  2771. // join process.
  2772. //
  2773. ClRtlLogPrint(LOG_NOISE,
  2774. "[NM] Enabling communication for node %1!ws!\n",
  2775. NodeInfo->NodeId
  2776. );
  2777. status = ClusnetOnlineNodeComm(NmClusnetHandle, node->NodeId);
  2778. if (status != ERROR_SUCCESS) {
  2779. NmpReleaseLock();
  2780. OmDereferenceObject(node);
  2781. wsprintfW(&(errorString[0]), L"%u", status);
  2782. CsLogEvent2(
  2783. LOG_CRITICAL,
  2784. NM_EVENT_CLUSNET_ONLINE_COMM_FAILED,
  2785. NodeInfo->NodeId,
  2786. errorString
  2787. );
  2788. ClRtlLogPrint(LOG_CRITICAL,
  2789. "[NM] Failed to enable node %1!ws! (%2!ws!) for communication, status %3!u!\n",
  2790. NodeInfo->NodeId,
  2791. NodeInfo->NodeName,
  2792. status
  2793. );
  2794. goto error_exit;
  2795. }
  2796. }
  2797. CL_ASSERT(NmpIdArray != NULL);
  2798. CL_ASSERT(NmpIdArray[node->NodeId] == NULL);
  2799. NmpIdArray[node->NodeId] = node;
  2800. InsertTailList(&NmpNodeList, &(node->Linkage));
  2801. node->Flags |= NM_FLAG_OM_INSERTED;
  2802. OmInsertObject(node);
  2803. NmpNodeCount++;
  2804. NmpReleaseLock();
  2805. return(node);
  2806. error_exit:
  2807. ClRtlLogPrint(LOG_CRITICAL,
  2808. "[NM] Failed to create object for node %1!ws!, status %2!u!.\n",
  2809. NodeInfo->NodeId,
  2810. status
  2811. );
  2812. if (eventCode != 0) {
  2813. wsprintfW(&(errorString[0]), L"%u", status);
  2814. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  2815. }
  2816. if (node != NULL) {
  2817. NmpAcquireLock();
  2818. NmpDeleteNodeObject(node, FALSE);
  2819. NmpReleaseLock();
  2820. }
  2821. SetLastError(status);
  2822. return(NULL);
  2823. } // NmpCreateNodeObject
  2824. DWORD
  2825. NmpGetNodeObjectInfo(
  2826. IN PNM_NODE Node,
  2827. IN OUT PNM_NODE_INFO2 NodeInfo
  2828. )
  2829. /*++
  2830. Routine Description:
  2831. Reads information about a defined cluster node from the its cluster
  2832. object and stores the information in a supplied structure.
  2833. Arguments:
  2834. Node - A pointer to the node object to query.
  2835. NodeInfo - A pointer to the structure into which to store the node
  2836. information.
  2837. Return Value:
  2838. ERROR_SUCCESS if the routine succeeds.
  2839. A Win32 error code otherwise.
  2840. Notes:
  2841. Called with the NmpLock held.
  2842. --*/
  2843. {
  2844. DWORD status;
  2845. lstrcpyW(&(NodeInfo->NodeId[0]), OmObjectId(Node));
  2846. lstrcpyW(&(NodeInfo->NodeName[0]), OmObjectName(Node));
  2847. NodeInfo->State = Node->State;
  2848. NodeInfo->NodeHighestVersion = Node->HighestVersion;
  2849. NodeInfo->NodeLowestVersion = Node->LowestVersion;
  2850. return(ERROR_SUCCESS);
  2851. } // NmpGetNodeObjectInfo
  2852. VOID
  2853. NmpDeleteNodeObject(
  2854. IN PNM_NODE Node,
  2855. IN BOOLEAN IssueEvent
  2856. )
  2857. /*++
  2858. Notes:
  2859. Called with NM lock held.
  2860. --*/
  2861. {
  2862. DWORD status;
  2863. PNM_INTERFACE netInterface;
  2864. PLIST_ENTRY entry;
  2865. LPWSTR nodeId = (LPWSTR) OmObjectId(Node);
  2866. if (NM_DELETE_PENDING(Node)) {
  2867. CL_ASSERT(!NM_OM_INSERTED(Node));
  2868. return;
  2869. }
  2870. ClRtlLogPrint(LOG_NOISE,
  2871. "[NM] Deleting object for node %1!ws!.\n",
  2872. nodeId
  2873. );
  2874. Node->Flags |= NM_FLAG_DELETE_PENDING;
  2875. //
  2876. // Remove from the various object lists.
  2877. //
  2878. if (NM_OM_INSERTED(Node)) {
  2879. status = OmRemoveObject(Node);
  2880. CL_ASSERT(status == ERROR_SUCCESS);
  2881. Node->Flags &= ~NM_FLAG_OM_INSERTED;
  2882. RemoveEntryList(&(Node->Linkage));
  2883. NmpIdArray[Node->NodeId] = NULL;
  2884. CL_ASSERT(NmpNodeCount > 0);
  2885. NmpNodeCount--;
  2886. }
  2887. //
  2888. // Delete all of the interfaces on this node
  2889. //
  2890. while (!IsListEmpty(&(Node->InterfaceList))) {
  2891. entry = Node->InterfaceList.Flink;
  2892. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NodeLinkage);
  2893. NmpDeleteInterfaceObject(netInterface, IssueEvent);
  2894. }
  2895. status = ClusnetDeregisterNode(NmClusnetHandle, Node->NodeId);
  2896. CL_ASSERT( (status == ERROR_SUCCESS) ||
  2897. (status == ERROR_NOT_READY) ||
  2898. (status == ERROR_CLUSTER_NODE_NOT_FOUND)
  2899. );
  2900. if (IssueEvent) {
  2901. ClRtlLogPrint(LOG_NOISE,
  2902. "[NM] Issuing delete event for node %1!ws!.\n",
  2903. nodeId
  2904. );
  2905. ClusterEvent(CLUSTER_EVENT_NODE_DELETED, Node);
  2906. }
  2907. OmDereferenceObject(Node);
  2908. return;
  2909. } // NmpDeleteNodeObject
  2910. BOOL
  2911. NmpDestroyNodeObject(
  2912. PNM_NODE Node
  2913. )
  2914. {
  2915. DWORD status;
  2916. ClRtlLogPrint(LOG_NOISE,
  2917. "[NM] destroying node %1!ws!\n",
  2918. OmObjectId(Node)
  2919. );
  2920. CL_ASSERT(NM_DELETE_PENDING(Node));
  2921. CL_ASSERT(!NM_OM_INSERTED(Node));
  2922. ClMsgDeleteDefaultRpcBinding(Node, Node->DefaultRpcBindingGeneration);
  2923. ClMsgDeleteRpcBinding(Node->ReportRpcBinding);
  2924. ClMsgDeleteRpcBinding(Node->IsolateRpcBinding);
  2925. // Delete the Node down event.
  2926. if (Node->MmNodeStateDownEvent != NULL) {
  2927. CloseHandle(Node->MmNodeStateDownEvent);
  2928. Node->MmNodeStateDownEvent = NULL;
  2929. }
  2930. return(TRUE);
  2931. } // NmpDestroyNodeObject
  2932. DWORD
  2933. NmpEnumNodeObjects(
  2934. PNM_NODE_ENUM2 * NodeEnum
  2935. )
  2936. /*++
  2937. Routine Description:
  2938. Reads information about all defined cluster nodes from the cluster
  2939. object manager and builds an enumeration structure containing
  2940. the information.
  2941. Arguments:
  2942. NodeEnum - A pointer to the variable into which to place a pointer to
  2943. the allocated node enumeration.
  2944. Return Value:
  2945. ERROR_SUCCESS if the routine succeeds.
  2946. A Win32 error code otherwise.
  2947. Notes:
  2948. Called with the NmpLock held.
  2949. --*/
  2950. {
  2951. DWORD status = ERROR_SUCCESS;
  2952. PNM_NODE_ENUM2 nodeEnum = NULL;
  2953. DWORD i;
  2954. DWORD valueLength;
  2955. PLIST_ENTRY entry;
  2956. PNM_NODE node;
  2957. *NodeEnum = NULL;
  2958. if (NmpNodeCount == 0) {
  2959. valueLength = sizeof(NM_NODE_ENUM2);
  2960. }
  2961. else {
  2962. valueLength = sizeof(NM_NODE_ENUM2) +
  2963. (sizeof(NM_NODE_INFO2) * (NmpNodeCount - 1));
  2964. }
  2965. nodeEnum = MIDL_user_allocate(valueLength);
  2966. if (nodeEnum == NULL) {
  2967. return(ERROR_NOT_ENOUGH_MEMORY);
  2968. }
  2969. ZeroMemory(nodeEnum, valueLength);
  2970. for (entry = NmpNodeList.Flink, i=0;
  2971. entry != &NmpNodeList;
  2972. entry = entry->Flink, i++
  2973. )
  2974. {
  2975. node = CONTAINING_RECORD(entry, NM_NODE, Linkage);
  2976. status = NmpGetNodeObjectInfo(
  2977. node,
  2978. &(nodeEnum->NodeList[i])
  2979. );
  2980. if (status != ERROR_SUCCESS) {
  2981. ClNetFreeNodeEnum(nodeEnum);
  2982. return(status);
  2983. }
  2984. }
  2985. nodeEnum->NodeCount = NmpNodeCount;
  2986. *NodeEnum = nodeEnum;
  2987. nodeEnum = NULL;
  2988. return(ERROR_SUCCESS);
  2989. } // NmpEnumNodeObjects
  2990. DWORD
  2991. NmpSetNodeInterfacePriority(
  2992. IN PNM_NODE Node,
  2993. IN DWORD Priority,
  2994. IN PNM_INTERFACE TargetInterface OPTIONAL,
  2995. IN DWORD TargetInterfacePriority OPTIONAL
  2996. )
  2997. /*++
  2998. Called with the NmpLock held.
  2999. --*/
  3000. {
  3001. PNM_INTERFACE netInterface;
  3002. PNM_NETWORK network;
  3003. DWORD status = ERROR_SUCCESS;
  3004. PLIST_ENTRY entry;
  3005. for (entry = Node->InterfaceList.Flink;
  3006. entry != &Node->InterfaceList;
  3007. entry = entry->Flink
  3008. )
  3009. {
  3010. netInterface = CONTAINING_RECORD( entry, NM_INTERFACE, NodeLinkage );
  3011. network = netInterface->Network;
  3012. if ( NmpIsNetworkForInternalUse(network) &&
  3013. NmpIsInterfaceRegistered(netInterface)
  3014. )
  3015. {
  3016. if ( netInterface == TargetInterface ) {
  3017. status = ClusnetSetInterfacePriority(
  3018. NmClusnetHandle,
  3019. netInterface->Node->NodeId,
  3020. netInterface->Network->ShortId,
  3021. TargetInterfacePriority
  3022. );
  3023. } else {
  3024. status = ClusnetSetInterfacePriority(
  3025. NmClusnetHandle,
  3026. netInterface->Node->NodeId,
  3027. netInterface->Network->ShortId,
  3028. Priority
  3029. );
  3030. }
  3031. }
  3032. if ( status != ERROR_SUCCESS ) {
  3033. break;
  3034. }
  3035. }
  3036. return(status);
  3037. } // NmpSetNodeInterfacePriority
  3038. /////////////////////////////////////////////////////////////////////////////
  3039. //
  3040. // Node eviction utilities
  3041. //
  3042. /////////////////////////////////////////////////////////////////////////////
  3043. DWORD
  3044. NmpCleanseRegistry(
  3045. IN LPCWSTR NodeId,
  3046. IN HLOCALXSACTION Xaction
  3047. )
  3048. /*++
  3049. Routine Description:
  3050. Removes all references to the specified node from the cluster
  3051. registry.
  3052. Arguments:
  3053. Node - Supplies the node that is being evicted.
  3054. Return Value:
  3055. ERROR_SUCCESS if successful
  3056. Win32 error code otherwise
  3057. --*/
  3058. {
  3059. NM_EVICTION_CONTEXT context;
  3060. context.NodeId = NodeId;
  3061. context.Xaction = Xaction;
  3062. context.Status = ERROR_SUCCESS;
  3063. //
  3064. // Remove this node from the possible owner list of
  3065. // each resource type.
  3066. //
  3067. OmEnumObjects(
  3068. ObjectTypeResType,
  3069. NmpCleanseResTypeCallback,
  3070. &context,
  3071. NULL
  3072. );
  3073. if (context.Status == ERROR_SUCCESS) {
  3074. //
  3075. // Remove this node from the preferred owner list of
  3076. // each group.
  3077. //
  3078. OmEnumObjects(
  3079. ObjectTypeGroup,
  3080. NmpCleanseGroupCallback,
  3081. &context,
  3082. NULL
  3083. );
  3084. }
  3085. if (context.Status == ERROR_SUCCESS) {
  3086. //
  3087. // Remove this node from the possible owner list of
  3088. // each resource.
  3089. //
  3090. OmEnumObjects(
  3091. ObjectTypeResource,
  3092. NmpCleanseResourceCallback,
  3093. &context,
  3094. NULL
  3095. );
  3096. }
  3097. return(context.Status);
  3098. } // NmpCleanseRegistry
  3099. BOOL
  3100. NmpCleanseGroupCallback(
  3101. IN PNM_EVICTION_CONTEXT Context,
  3102. IN PVOID Context2,
  3103. IN PFM_GROUP Group,
  3104. IN LPCWSTR GroupName
  3105. )
  3106. /*++
  3107. Routine Description:
  3108. Group enumeration callback for removing an evicted node from the
  3109. group's preferred owners list.
  3110. Arguments:
  3111. Context - Supplies the node ID of the evicted node and other context info.
  3112. Context2 - Not used
  3113. Group - Supplies the group.
  3114. GroupName - Supplies the group's name.
  3115. Return Value:
  3116. TRUE - to indicate that the enumeration should continue.
  3117. --*/
  3118. {
  3119. HDMKEY groupKey;
  3120. DWORD status;
  3121. //
  3122. // Open the group's key.
  3123. //
  3124. groupKey = DmOpenKey(DmGroupsKey, GroupName, KEY_READ | KEY_WRITE);
  3125. if (groupKey != NULL) {
  3126. status = DmLocalRemoveFromMultiSz(
  3127. Context->Xaction,
  3128. groupKey,
  3129. CLUSREG_NAME_GRP_PREFERRED_OWNERS,
  3130. Context->NodeId
  3131. );
  3132. if (status == ERROR_FILE_NOT_FOUND) {
  3133. status = ERROR_SUCCESS;
  3134. }
  3135. DmCloseKey(groupKey);
  3136. }
  3137. else {
  3138. status = GetLastError();
  3139. }
  3140. Context->Status = status;
  3141. if (status != ERROR_SUCCESS) {
  3142. return(FALSE);
  3143. }
  3144. else {
  3145. return(TRUE);
  3146. }
  3147. } // NmpCleanseGroupCallback
  3148. BOOL
  3149. NmpCleanseResourceCallback(
  3150. IN PNM_EVICTION_CONTEXT Context,
  3151. IN PVOID Context2,
  3152. IN PFM_RESOURCE Resource,
  3153. IN LPCWSTR ResourceName
  3154. )
  3155. /*++
  3156. Routine Description:
  3157. Group enumeration callback for removing an evicted node from the
  3158. resource's possible owner's list.
  3159. Also deletes any node-specific parameters from the resource's registry
  3160. key.
  3161. Arguments:
  3162. Context - Supplies the node ID of the evicted node and other context info.
  3163. Context2 - Not used
  3164. Resource - Supplies the resource.
  3165. ResourceName - Supplies the resource's name.
  3166. Return Value:
  3167. TRUE - to indicate that the enumeration should continue.
  3168. --*/
  3169. {
  3170. HDMKEY resourceKey;
  3171. HDMKEY paramKey;
  3172. HDMKEY subKey;
  3173. DWORD status;
  3174. //
  3175. // Open the resource's key.
  3176. //
  3177. resourceKey = DmOpenKey(
  3178. DmResourcesKey,
  3179. ResourceName,
  3180. KEY_READ | KEY_WRITE
  3181. );
  3182. if (resourceKey != NULL) {
  3183. status = DmLocalRemoveFromMultiSz(
  3184. Context->Xaction,
  3185. resourceKey,
  3186. CLUSREG_NAME_RES_POSSIBLE_OWNERS,
  3187. Context->NodeId
  3188. );
  3189. if ((status == ERROR_SUCCESS) || (status == ERROR_FILE_NOT_FOUND)) {
  3190. paramKey = DmOpenKey(
  3191. resourceKey,
  3192. CLUSREG_KEYNAME_PARAMETERS,
  3193. KEY_READ | KEY_WRITE
  3194. );
  3195. if (paramKey != NULL) {
  3196. status = DmLocalDeleteTree(
  3197. Context->Xaction,
  3198. paramKey,
  3199. Context->NodeId
  3200. );
  3201. DmCloseKey(paramKey);
  3202. }
  3203. else {
  3204. status = GetLastError();
  3205. }
  3206. }
  3207. DmCloseKey(resourceKey);
  3208. }
  3209. else {
  3210. status = GetLastError();
  3211. }
  3212. if (status == ERROR_FILE_NOT_FOUND) {
  3213. status = ERROR_SUCCESS;
  3214. }
  3215. Context->Status = status;
  3216. if (status != ERROR_SUCCESS) {
  3217. return(FALSE);
  3218. }
  3219. else {
  3220. return(TRUE);
  3221. }
  3222. } // NmpCleanseResourceCallback
  3223. BOOL
  3224. NmpCleanseResTypeCallback(
  3225. IN PNM_EVICTION_CONTEXT Context,
  3226. IN PVOID Context2,
  3227. IN PFM_RESTYPE pResType,
  3228. IN LPCWSTR pszResTypeName
  3229. )
  3230. /*++
  3231. Routine Description:
  3232. Group enumeration callback for removing an evicted node from the
  3233. resource type's possible owner's list.
  3234. Also deletes any node-specific parameters from the resource types's registry
  3235. key.
  3236. Arguments:
  3237. Context - Supplies the node ID of the evicted node and other context info.
  3238. Context2 - Not used
  3239. pResType - Supplies the resource type.
  3240. pszResTypeeName - Supplies the resource type's name.
  3241. Return Value:
  3242. TRUE - to indicate that the enumeration should continue.
  3243. --*/
  3244. {
  3245. HDMKEY hResTypeKey;
  3246. HDMKEY paramKey;
  3247. HDMKEY subKey;
  3248. DWORD status;
  3249. //
  3250. // Open the resource's key.
  3251. //
  3252. hResTypeKey = DmOpenKey(
  3253. DmResourceTypesKey,
  3254. pszResTypeName,
  3255. KEY_READ | KEY_WRITE
  3256. );
  3257. if (hResTypeKey != NULL) {
  3258. status = DmLocalRemoveFromMultiSz(
  3259. Context->Xaction,
  3260. hResTypeKey,
  3261. CLUSREG_NAME_RESTYPE_POSSIBLE_NODES,
  3262. Context->NodeId
  3263. );
  3264. if ((status == ERROR_SUCCESS) || (status == ERROR_FILE_NOT_FOUND)) {
  3265. paramKey = DmOpenKey(
  3266. hResTypeKey,
  3267. CLUSREG_KEYNAME_PARAMETERS,
  3268. KEY_READ | KEY_WRITE
  3269. );
  3270. if (paramKey != NULL) {
  3271. status = DmLocalDeleteTree(
  3272. Context->Xaction,
  3273. paramKey,
  3274. Context->NodeId
  3275. );
  3276. DmCloseKey(paramKey);
  3277. }
  3278. else {
  3279. status = GetLastError();
  3280. }
  3281. }
  3282. DmCloseKey(hResTypeKey);
  3283. }
  3284. else {
  3285. status = GetLastError();
  3286. }
  3287. if (status == ERROR_FILE_NOT_FOUND) {
  3288. status = ERROR_SUCCESS;
  3289. }
  3290. Context->Status = status;
  3291. if (status != ERROR_SUCCESS) {
  3292. return(FALSE);
  3293. }
  3294. else {
  3295. return(TRUE);
  3296. }
  3297. } // NmpCleanseResTypeCallback
  3298. /////////////////////////////////////////////////////////////////////////////
  3299. //
  3300. // Node failure handler
  3301. //
  3302. /////////////////////////////////////////////////////////////////////////////
  3303. VOID
  3304. NmpNodeFailureHandler(
  3305. CL_NODE_ID NodeId,
  3306. LPVOID NodeFailureContext
  3307. )
  3308. {
  3309. return;
  3310. }
  3311. /////////////////////////////////////////////////////////////////////////////
  3312. //
  3313. // Miscellaneous routines
  3314. //
  3315. /////////////////////////////////////////////////////////////////////////////
  3316. //SS: when the node objects are created, their product suite is
  3317. //assumed to be Enterprise(aka Advanced Server) - This is because
  3318. //the joining interface doesnt allow the joiner to provide the node
  3319. //suite type and we didnt want to muck with it at a late state in
  3320. //shipping because it affects mixed mode clusters.
  3321. //SO, we fixup the structures after NmPerformFixups is called
  3322. //and calculate the cluster node limit
  3323. DWORD NmpRefreshNodeObjects(
  3324. )
  3325. {
  3326. NM_NODE_AUX_INFO NodeAuxInfo;
  3327. PLIST_ENTRY pListEntry;
  3328. PNM_NODE pNmNode;
  3329. WCHAR szNodeId[6];
  3330. DWORD dwStatus = ERROR_SUCCESS;
  3331. NmpAcquireLock();
  3332. for ( pListEntry = NmpNodeList.Flink;
  3333. pListEntry != &NmpNodeList;
  3334. pListEntry = pListEntry->Flink )
  3335. {
  3336. pNmNode = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  3337. wsprintf(szNodeId, L"%u", pNmNode->NodeId);
  3338. //read the information from the registry
  3339. NmpGetNodeAuxInfo(szNodeId, &NodeAuxInfo);
  3340. //update the node structure
  3341. pNmNode->ProductSuite = NodeAuxInfo.ProductSuite;
  3342. //SS: This is ugly---we should pass in the product suits early on.
  3343. //we dont know that the versions have changed, so should we generate
  3344. //a cluster_change_node_property event?
  3345. //Also the fixup interface needs to to be richer so that the postcallback
  3346. //function knows whether it is a form fixup or a join fixup and if it
  3347. //is a join fixup, which node is joining. This could certainly optimize
  3348. //some of the fixup processing
  3349. ClusterEvent(CLUSTER_EVENT_NODE_PROPERTY_CHANGE, pNmNode);
  3350. }
  3351. NmpReleaseLock();
  3352. return(dwStatus);
  3353. }
  3354. BOOLEAN
  3355. NmpIsAddNodeAllowed(
  3356. IN DWORD NewNodeProductSuite,
  3357. IN DWORD RegistryNodeLimit,
  3358. OUT LPDWORD EffectiveNodeLimit OPTIONAL
  3359. )
  3360. /*++
  3361. Routine Description:
  3362. Determines whether a new node can be added to the cluste membership.
  3363. The membership size limit decision is based on the product suites
  3364. of the cluster and the new node. If the registry override exists,
  3365. we will use that limit instead.
  3366. Arguments:
  3367. NewNodeProductSuite - The product suite identifier for the proposed
  3368. new member node.
  3369. RegistryNodeLimit - The membership size override value stored in the
  3370. cluster database.
  3371. EffectiveNodeLimit - On output, contains the membership size limit
  3372. that was calculated for this cluster.
  3373. Return Value:
  3374. TRUE if the new node may be added to the cluster. FALSE otherwise.
  3375. Notes:
  3376. Called with NmpLock held.
  3377. --*/
  3378. {
  3379. DWORD nodeLimit;
  3380. DWORD newNodeProductLimit;
  3381. DWORD currentNodeCount;
  3382. //
  3383. // Check if we already have the maximum number of nodes allowed in
  3384. // this cluster, based on the the product suites of the cluster and
  3385. // the joiner. If the registry override exists, we will use that
  3386. // limit instead.
  3387. //
  3388. newNodeProductLimit = ClRtlGetDefaultNodeLimit(NewNodeProductSuite);
  3389. currentNodeCount = NmGetCurrentNumberOfNodes();
  3390. nodeLimit = RegistryNodeLimit;
  3391. if (nodeLimit == 0) {
  3392. //
  3393. // No override in the registry.
  3394. // Limit is minimum of cluster's limit and new node's limit
  3395. //
  3396. nodeLimit = min(CsClusterNodeLimit, newNodeProductLimit);
  3397. }
  3398. //
  3399. // The runtime limit cannot exceed the compile time limit.
  3400. //
  3401. if (nodeLimit > NmMaxNodeId) {
  3402. nodeLimit = NmMaxNodeId;
  3403. }
  3404. if (currentNodeCount >= nodeLimit) {
  3405. return(FALSE);
  3406. }
  3407. if (EffectiveNodeLimit != NULL) {
  3408. *EffectiveNodeLimit = nodeLimit;
  3409. }
  3410. return(TRUE);
  3411. } // NmpIsAddNodeAllowed
  3412. DWORD
  3413. NmpAddNode(
  3414. IN LPCWSTR NewNodeName,
  3415. IN DWORD NewNodeHighestVersion,
  3416. IN DWORD NewNodeLowestVersion,
  3417. IN DWORD NewNodeProductSuite,
  3418. IN DWORD RegistryNodeLimit
  3419. )
  3420. /*++
  3421. Routine Description:
  3422. Adds a new node to the cluster by selecting an ID and
  3423. issuing a global update.
  3424. Arguments:
  3425. NewNodeName - A pointer to a string containing the name of the
  3426. new node.
  3427. NewNodeHighestVersion - The highest cluster version number that the
  3428. new node can support.
  3429. NewNodeLowestVersion - The lowest cluster version number that the
  3430. new node can support.
  3431. NewNodeProductSuite - The product suite identifier for the new node.
  3432. Return Value:
  3433. A Win32 status code.
  3434. Notes:
  3435. Called with NmpLock held.
  3436. --*/
  3437. {
  3438. DWORD status;
  3439. DWORD nodeId;
  3440. DWORD nodeLimit;
  3441. ClRtlLogPrint(LOG_NOISE,
  3442. "[NMJOIN] Processing request to add node '%1!ws!' to "
  3443. "the cluster.\n",
  3444. NewNodeName
  3445. );
  3446. if (NmpAddNodeId != ClusterInvalidNodeId) {
  3447. //
  3448. // An add is already in progress. Return an error.
  3449. //
  3450. ClRtlLogPrint(LOG_UNUSUAL,
  3451. "[NMJOIN] Cannot add node '%1!ws!' to the cluster because "
  3452. "another add node operation is in progress. Retry later.\n",
  3453. NewNodeName
  3454. );
  3455. return(ERROR_CLUSTER_JOIN_IN_PROGRESS);
  3456. }
  3457. if (!NmpIsAddNodeAllowed(
  3458. NewNodeProductSuite,
  3459. RegistryNodeLimit,
  3460. &nodeLimit
  3461. )
  3462. )
  3463. {
  3464. ClRtlLogPrint(LOG_UNUSUAL,
  3465. "[NMJOIN] Cannot add node '%1!ws!' to the cluster. "
  3466. "The cluster already contains the maximum number of nodes "
  3467. "allowed by the product licenses of the current member nodes "
  3468. "and the proposed new node.\n",
  3469. NewNodeName
  3470. );
  3471. return(ERROR_LICENSE_QUOTA_EXCEEDED);
  3472. }
  3473. //
  3474. // Find a free node ID.
  3475. //
  3476. for (nodeId=ClusterMinNodeId; nodeId<=nodeLimit; nodeId++) {
  3477. if (NmpIdArray[nodeId] == NULL) {
  3478. //
  3479. // Found an available node ID.
  3480. //
  3481. NmpAddNodeId = nodeId;
  3482. ClRtlLogPrint(LOG_NOISE,
  3483. "[NMJOIN] Allocated node ID '%1!u!' for new node '%2!ws!'\n",
  3484. NmpAddNodeId,
  3485. NewNodeName
  3486. );
  3487. break;
  3488. }
  3489. }
  3490. //
  3491. // Since the license test passed, it should be impossible for us to
  3492. // find no free slots in the node table.
  3493. //
  3494. CL_ASSERT(NmpAddNodeId != ClusterInvalidNodeId);
  3495. if (NmpAddNodeId == ClusterInvalidNodeId) {
  3496. ClRtlLogPrint(LOG_UNUSUAL,
  3497. "[NMJOIN] Cannot add node '%1!ws!' to the cluster because "
  3498. "no slots are available in the node table.\n",
  3499. NewNodeName
  3500. );
  3501. return(ERROR_LICENSE_QUOTA_EXCEEDED);
  3502. }
  3503. NmpReleaseLock();
  3504. status = GumSendUpdateEx(
  3505. GumUpdateMembership,
  3506. NmUpdateAddNode,
  3507. 5,
  3508. sizeof(NmpAddNodeId),
  3509. &NmpAddNodeId,
  3510. NM_WCSLEN(NewNodeName),
  3511. NewNodeName,
  3512. sizeof(NewNodeHighestVersion),
  3513. &NewNodeHighestVersion,
  3514. sizeof(NewNodeLowestVersion),
  3515. &NewNodeLowestVersion,
  3516. sizeof(NewNodeProductSuite),
  3517. &NewNodeProductSuite
  3518. );
  3519. NmpAcquireLock();
  3520. //
  3521. // Reset the global serialization variable.
  3522. //
  3523. CL_ASSERT(NmpAddNodeId == nodeId);
  3524. NmpAddNodeId = ClusterInvalidNodeId;
  3525. return(status);
  3526. } // NmpAddNode
  3527. VOID
  3528. NmpTerminateRpcsToNode(
  3529. DWORD NodeId
  3530. )
  3531. /*++
  3532. Routine Description:
  3533. Cancels all outstanding RPCs to the specified node.
  3534. Arguments:
  3535. NodeId - The ID of the node for which calls should be cancelled.
  3536. Return Value:
  3537. None
  3538. --*/
  3539. {
  3540. LIST_ENTRY *pEntry, *pStart;
  3541. PNM_INTRACLUSTER_RPC_THREAD pRpcTh;
  3542. RPC_STATUS status;
  3543. #if DBG
  3544. BOOLEAN startTimer = FALSE;
  3545. #endif // DBG
  3546. CL_ASSERT((NodeId >= ClusterMinNodeId) && (NodeId <= NmMaxNodeId));
  3547. CL_ASSERT(NmpIntraClusterRpcArr != NULL);
  3548. NmpAcquireRPCLock();
  3549. pEntry = pStart = &NmpIntraClusterRpcArr[NodeId];
  3550. pEntry = pEntry->Flink;
  3551. while(pEntry != pStart) {
  3552. pRpcTh = CONTAINING_RECORD(pEntry, NM_INTRACLUSTER_RPC_THREAD, Linkage);
  3553. status = RpcCancelThreadEx(pRpcTh->Thread, 0);
  3554. pRpcTh->Cancelled = TRUE;
  3555. if(status != RPC_S_OK) {
  3556. ClRtlLogPrint(LOG_UNUSUAL,
  3557. "[NM] Failed to cancel RPC to node %1!u! by thread "
  3558. "x%2!x!, status %3!u!.\n",
  3559. NodeId,
  3560. pRpcTh->ThreadId,
  3561. status
  3562. );
  3563. }
  3564. else {
  3565. ClRtlLogPrint(LOG_NOISE,
  3566. "[NM] Cancelled RPC to node %1!u! by thread x%2!x!.\n",
  3567. NodeId,
  3568. pRpcTh->ThreadId
  3569. );
  3570. #if DBG
  3571. startTimer = TRUE;
  3572. #endif // DBG
  3573. }
  3574. pEntry = pEntry->Flink;
  3575. }
  3576. #if DBG
  3577. //
  3578. // Now start a timer to make sure that all cancelled RPCs return to
  3579. // their callers within a reasonable amount of time.
  3580. //
  3581. if (startTimer) {
  3582. NmpRpcTimer = NM_RPC_TIMEOUT;
  3583. }
  3584. #endif // DBG
  3585. NmpReleaseRPCLock();
  3586. return;
  3587. } // NmTerminateRpcsToNode
  3588. #if DBG
  3589. VOID
  3590. NmpRpcTimerTick(
  3591. DWORD MsTickInterval
  3592. )
  3593. /*++
  3594. Routine Description:
  3595. Decrements a timer used to ensure that all cancelled RPCs to a dead
  3596. node return to their callers within a reasonable amount of time.
  3597. Arguments:
  3598. MsTickInterval - The time, in milliseconds, that has elapsed since this
  3599. routine was last invoked.
  3600. Return Value:
  3601. None
  3602. --*/
  3603. {
  3604. DWORD ndx;
  3605. LIST_ENTRY *pEntry, *pStart;
  3606. PNM_INTRACLUSTER_RPC_THREAD pRpcTh;
  3607. if(NmpRpcTimer == 0)
  3608. return;
  3609. NmpAcquireRPCLock();
  3610. if (NmpRpcTimer > MsTickInterval) {
  3611. NmpRpcTimer -= MsTickInterval;
  3612. }
  3613. else {
  3614. BOOLEAN stopClusSvc=FALSE;
  3615. NmpRpcTimer = 0;
  3616. for(ndx=0;ndx<=NmMaxNodeId;ndx++) {
  3617. pStart = pEntry = &NmpIntraClusterRpcArr[ndx];
  3618. pEntry = pEntry->Flink;
  3619. while(pEntry != pStart) {
  3620. pRpcTh = CONTAINING_RECORD(
  3621. pEntry,
  3622. NM_INTRACLUSTER_RPC_THREAD,
  3623. Linkage
  3624. );
  3625. if(pRpcTh->Cancelled == TRUE) {
  3626. ClRtlLogPrint( LOG_CRITICAL,
  3627. "[NM] Cancelled RPC to node %1!u! by thread x%2!x! "
  3628. "is still lingering after %3!u! seconds.\n",
  3629. ndx,
  3630. pRpcTh->ThreadId,
  3631. (NM_RPC_TIMEOUT/1000)
  3632. );
  3633. stopClusSvc = TRUE;
  3634. }
  3635. pEntry = pEntry->Flink;
  3636. }
  3637. }
  3638. if(stopClusSvc) {
  3639. DebugBreak();
  3640. }
  3641. }
  3642. NmpReleaseRPCLock();
  3643. return;
  3644. } // NmpRpcTimerTick
  3645. #endif // DBG