Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1030 lines
31 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. nmver.c
  5. Abstract:
  6. Version management functions used by rolling upgrade.
  7. Author:
  8. Sunita Shrivastava (sunitas)
  9. Revision History:
  10. 1/29/98 Created.
  11. --*/
  12. #include "nmp.h"
  13. error_status_t
  14. s_CsRpcGetJoinVersionData(
  15. handle_t handle,
  16. DWORD JoiningNodeId,
  17. DWORD JoinerHighestVersion,
  18. DWORD JoinerLowestVersion,
  19. LPDWORD SponsorNodeId,
  20. LPDWORD ClusterHighestVersion,
  21. LPDWORD ClusterLowestVersion,
  22. LPDWORD JoinStatus
  23. )
  24. /*++
  25. Routine Description:
  26. Get from and supply to the joiner, version information about the
  27. sponsor. Mostly a no-op for first version.
  28. Arguments:
  29. A pile...
  30. Return Value:
  31. None
  32. --*/
  33. {
  34. *SponsorNodeId = NmLocalNodeId;
  35. NmpAcquireLock();
  36. if (JoiningNodeId == 0)
  37. {
  38. //called by setup join
  39. *ClusterHighestVersion = CsClusterHighestVersion;
  40. *ClusterLowestVersion = CsClusterLowestVersion;
  41. //dont exclude any node for version calculation and checking
  42. *JoinStatus = NmpIsNodeVersionAllowed(ClusterInvalidNodeId, JoinerHighestVersion,
  43. JoinerLowestVersion, TRUE);
  44. }
  45. else
  46. {
  47. //called by regular join
  48. //SS: we should verify this against the cluster version
  49. NmpCalcClusterVersion(
  50. JoiningNodeId,
  51. ClusterHighestVersion,
  52. ClusterLowestVersion
  53. );
  54. *JoinStatus = NmpIsNodeVersionAllowed(JoiningNodeId, JoinerHighestVersion,
  55. JoinerLowestVersion, TRUE);
  56. }
  57. NmpReleaseLock();
  58. return ERROR_SUCCESS;
  59. }
  60. /****
  61. @func HLOG | NmGetClusterOperationalVersion| This returns the
  62. operational version for the cluster.
  63. @parm LPDWORD | pdwClusterHighestVersion | A pointer to a DWORD where
  64. the Cluster Highest Version is returned.
  65. @parm LPDWORD | pdwClusterHighestVersion | A pointer to a DWORD where
  66. the Cluster Lowest Version is returned.
  67. @parm LPDWORD | pdwFlags | A pointer to a DWORD where the flags
  68. describing the cluster mode(pure vs fixed version etc) are
  69. returned.
  70. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  71. @comm
  72. @xref <>
  73. ****/
  74. DWORD NmGetClusterOperationalVersion(
  75. OUT LPDWORD pdwClusterHighestVersion, OPTIONAL
  76. OUT LPDWORD pdwClusterLowestVersion, OPTIONAL
  77. OUT LPDWORD pdwFlags OPTIONAL
  78. )
  79. {
  80. DWORD dwStatus = ERROR_SUCCESS;
  81. DWORD flags = 0;
  82. //acquire the lock, we are going to be messing with the operational
  83. //versions for the cluster
  84. NmpAcquireLock();
  85. if (pdwClusterHighestVersion != NULL) {
  86. *pdwClusterHighestVersion = CsClusterHighestVersion;
  87. }
  88. if (pdwClusterLowestVersion != NULL) {
  89. *pdwClusterLowestVersion = CsClusterLowestVersion;
  90. }
  91. if (CsClusterHighestVersion == CsClusterLowestVersion) {
  92. //this is a mixed mode cluster, with the possible exception of
  93. //nt 4 release(which didnt quite understand anything about rolling
  94. //upgrades
  95. flags = CLUSTER_VERSION_FLAG_MIXED_MODE;
  96. }
  97. NmpReleaseLock();
  98. if (pdwFlags != NULL) {
  99. *pdwFlags = flags;
  100. }
  101. return (ERROR_SUCCESS);
  102. }
  103. /****
  104. @func HLOG | NmpResetClusterVersion| An operational version of the
  105. cluster is maintained in the service. This function recalculates
  106. the operation version. The operational version describes the mode
  107. in which the cluster is running and prevents nodes which are two
  108. versions away from running in the same cluster.
  109. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  110. @comm This function is called when a node forms a cluster(to initialize
  111. the operational version) OR when a node joins a cluster (to
  112. initialize its version) OR when a node is ejected from a
  113. cluster(to recalculate the clusterversion).
  114. @xref <>
  115. ****/
  116. VOID
  117. NmpResetClusterVersion(
  118. BOOL ProcessChanges
  119. )
  120. {
  121. PNM_NODE pNmNode;
  122. //acquire the lock, we are going to be messing with the operational
  123. //versions for the cluster
  124. NmpAcquireLock();
  125. //initialize the clusterhighestverion and clusterlowest version
  126. NmpCalcClusterVersion(
  127. ClusterInvalidNodeId,
  128. &CsClusterHighestVersion,
  129. &CsClusterLowestVersion
  130. );
  131. ClRtlLogPrint(LOG_NOISE,
  132. "[NM] [NmpResetClusterVersion] ClusterHighestVer=0x%1!08lx! ClusterLowestVer=0x%2!08lx!\r\n",
  133. CsClusterHighestVersion,
  134. CsClusterLowestVersion
  135. );
  136. if (ProcessChanges) {
  137. //
  138. // If the cluster operational version changed, adjust
  139. // algorithms and data as needed.
  140. //
  141. NmpProcessClusterVersionChange();
  142. }
  143. NmpReleaseLock();
  144. return;
  145. }
  146. /****
  147. @func HLOG | NmpValidateNodeVersion| The sponsor validates that the
  148. version of the joiner is still the same as before.
  149. @parm IN LPWSTR| NodeJoinerId | The Id of the node that is trying to
  150. join.
  151. @parm IN DWORD | NodeHighestVersion | The highest version with which
  152. this node can communicate.
  153. @parm IN DWORD | NodeLowestVersion | The lowest version with which this
  154. node can communicate.
  155. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  156. @comm This function is called at join time to make sure that the
  157. joiner's version is still the same as when he last joined. Due
  158. to uninstalls/upgrade, the cluster service version may change on
  159. a node. Usually on a complete uninstall, one is expected to
  160. evict the node out before it may join again.
  161. @xref <>
  162. ****/
  163. DWORD NmpValidateNodeVersion(
  164. IN LPCWSTR NodeId,
  165. IN DWORD dwHighestVersion,
  166. IN DWORD dwLowestVersion
  167. )
  168. {
  169. DWORD dwStatus = ERROR_SUCCESS;
  170. PNM_NODE pNmNode = NULL;
  171. ClRtlLogPrint(LOG_NOISE,
  172. "[NM] NmpValidateNodeVersion: Node=%1!ws!, HighestVersion=0x%2!08lx!, LowestVersion=0x%3!08lx!\r\n",
  173. NodeId, dwHighestVersion, dwLowestVersion);
  174. //acquire the NmpLocks, we will be examining the node structure for
  175. // the joiner node
  176. NmpAcquireLock();
  177. pNmNode = OmReferenceObjectById(ObjectTypeNode, NodeId);
  178. if (!pNmNode)
  179. {
  180. dwStatus = ERROR_CLUSTER_NODE_NOT_MEMBER;
  181. goto FnExit;
  182. }
  183. if ((pNmNode->HighestVersion != dwHighestVersion) ||
  184. (pNmNode->LowestVersion != dwLowestVersion))
  185. {
  186. dwStatus = ERROR_REVISION_MISMATCH;
  187. goto FnExit;
  188. }
  189. FnExit:
  190. if (pNmNode) OmDereferenceObject(pNmNode);
  191. ClRtlLogPrint(LOG_NOISE, "[NM] NmpValidateNodeVersion: returns %1!u!\r\n",
  192. dwStatus);
  193. NmpReleaseLock();
  194. return(dwStatus);
  195. }
  196. /****
  197. @func DWORD | NmpFormFixupNodeVersion| This may be called by a node
  198. when it is forming a cluster to fix the registry reflect its
  199. correct version.
  200. @parm IN LPCWSTR| NodeId | The Id of the node that is trying to join.
  201. @parm IN DWORD | dwHighestVersion | The highest version of the cluster
  202. s/w running on this code.
  203. @parm IN DWORD | dwLowestVersion | The lowest version of the cluster
  204. s/w running on this node.
  205. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  206. @comm If on a form, there is a mismatch between the versions of the
  207. cluster s/w and what is recorded as the version in the cluster
  208. database, the forming node checks to see if the version of
  209. its current s/w is compatible with the operational version of the
  210. cluster. If so, it resets the registry to reflect the correct
  211. version. Else, the form is aborted.
  212. @xref <f NmpIsNodeVersionAllowed>
  213. ****/
  214. DWORD NmpFormFixupNodeVersion(
  215. IN LPCWSTR NodeId,
  216. IN DWORD dwHighestVersion,
  217. IN DWORD dwLowestVersion
  218. )
  219. {
  220. DWORD dwStatus = ERROR_SUCCESS;
  221. PNM_NODE pNmNode = NULL;
  222. HDMKEY hNodeKey = NULL;
  223. //acquire the NmpLocks, we will be fixing up the node structure for
  224. // the joiner node
  225. NmpAcquireLock();
  226. ClRtlLogPrint(LOG_NOISE,
  227. "[NM] NmpFormFixupNodeVersion: Node=%1!ws! to HighestVer=0x%2!08lx!, LowestVer=0x%3!08lx!\r\n",
  228. NodeId, dwHighestVersion, dwLowestVersion);
  229. pNmNode = OmReferenceObjectById(ObjectTypeNode, NodeId);
  230. if (!pNmNode)
  231. {
  232. dwStatus = ERROR_CLUSTER_NODE_NOT_MEMBER;
  233. goto FnExit;
  234. }
  235. hNodeKey = DmOpenKey(DmNodesKey, NodeId, KEY_WRITE);
  236. if (hNodeKey == NULL)
  237. {
  238. dwStatus = GetLastError();
  239. ClRtlLogPrint(LOG_CRITICAL,
  240. "[NM] NmpFormFixupNodeVersion: Failed to open node key, status %1!u!\n",
  241. dwStatus);
  242. CL_LOGFAILURE(dwStatus);
  243. goto FnExit;
  244. }
  245. //set the node's highest version
  246. dwStatus = DmSetValue(hNodeKey, CLUSREG_NAME_NODE_HIGHEST_VERSION,
  247. REG_DWORD, (LPBYTE)&dwHighestVersion, sizeof(DWORD));
  248. if (dwStatus != ERROR_SUCCESS)
  249. {
  250. ClRtlLogPrint(LOG_CRITICAL,
  251. "[NM] NmpFormFixupNodeVersion: Failed to set the highest version\r\n");
  252. CL_LOGFAILURE(dwStatus);
  253. goto FnExit;
  254. }
  255. //set the node's lowest version
  256. dwStatus = DmSetValue(hNodeKey, CLUSREG_NAME_NODE_LOWEST_VERSION,
  257. REG_DWORD, (LPBYTE)&dwLowestVersion, sizeof(DWORD));
  258. if (dwStatus != ERROR_SUCCESS)
  259. {
  260. ClRtlLogPrint(LOG_CRITICAL,
  261. "[NM] NmpFormFixupNodeVersion: Failed to set the lowest version\r\n");
  262. CL_LOGFAILURE(dwStatus);
  263. goto FnExit;
  264. }
  265. pNmNode->HighestVersion = dwHighestVersion;
  266. pNmNode->LowestVersion = dwLowestVersion;
  267. FnExit:
  268. NmpReleaseLock();
  269. if (pNmNode)
  270. OmDereferenceObject(pNmNode);
  271. if (hNodeKey != NULL)
  272. DmCloseKey(hNodeKey);
  273. return(dwStatus);
  274. }
  275. /****
  276. @func DWORD | NmpJoinFixupNodeVersion| This may be called by a node
  277. when it is forming a cluster to fix the registry reflect its
  278. correct version.
  279. @parm IN LPCWSTR| NodeId | The Id of the node that is trying to join.
  280. @parm IN DWORD | dwHighestVersion | The highest version of this cluster
  281. s/w running on this code.
  282. @parm IN DWORD | dwLowestVersion | The lowest version of the cluster
  283. s/w running on this node.
  284. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  285. @comm If on a form, their is a mismatch between the versions of the
  286. cluster s/w and what is recorded as the version in the cluster
  287. database, the forming node checks to see if the version of
  288. its current s/w compatible with the operational version of the
  289. cluster. If so, it resets the registry to reflect the correct
  290. version. Else, the form is aborted.
  291. @xref <f NmpIsNodeVersionAllowed>
  292. ****/
  293. DWORD NmpJoinFixupNodeVersion(
  294. IN HLOCALXSACTION hXsaction,
  295. IN LPCWSTR szNodeId,
  296. IN DWORD dwHighestVersion,
  297. IN DWORD dwLowestVersion
  298. )
  299. {
  300. DWORD dwStatus = ERROR_SUCCESS;
  301. PNM_NODE pNmNode = NULL;
  302. HDMKEY hNodeKey = NULL;
  303. //acquire the NmpLocks, we will be fixing up the node structure for
  304. // the joiner node
  305. NmpAcquireLock();
  306. ClRtlLogPrint(LOG_NOISE,
  307. "[NM] NmpJoinFixupNodeVersion: Node=%1!ws! to HighestVer=0x%2!08lx!, LowestVer=0x%3!08lx!\r\n",
  308. szNodeId, dwHighestVersion, dwLowestVersion);
  309. pNmNode = OmReferenceObjectById(ObjectTypeNode, szNodeId);
  310. if (!pNmNode)
  311. {
  312. dwStatus = ERROR_CLUSTER_NODE_NOT_MEMBER;
  313. goto FnExit;
  314. }
  315. hNodeKey = DmOpenKey(DmNodesKey, szNodeId, KEY_WRITE);
  316. if (hNodeKey == NULL)
  317. {
  318. dwStatus = GetLastError();
  319. ClRtlLogPrint(LOG_CRITICAL,
  320. "[NM] NmpJoinFixupNodeVersion: Failed to open node key, status %1!u!\n",
  321. dwStatus);
  322. CL_LOGFAILURE(dwStatus);
  323. goto FnExit;
  324. }
  325. //set the node's highest version
  326. dwStatus = DmLocalSetValue(
  327. hXsaction,
  328. hNodeKey,
  329. CLUSREG_NAME_NODE_HIGHEST_VERSION,
  330. REG_DWORD,
  331. (LPBYTE)&dwHighestVersion,
  332. sizeof(DWORD)
  333. );
  334. if (dwStatus != ERROR_SUCCESS)
  335. {
  336. ClRtlLogPrint(LOG_CRITICAL,
  337. "[NM] NmpJoinFixupNodeVersion: Failed to set the highest version\r\n"
  338. );
  339. CL_LOGFAILURE(dwStatus);
  340. goto FnExit;
  341. }
  342. //set the node's lowest version
  343. dwStatus = DmLocalSetValue(
  344. hXsaction,
  345. hNodeKey,
  346. CLUSREG_NAME_NODE_LOWEST_VERSION,
  347. REG_DWORD,
  348. (LPBYTE)&dwLowestVersion,
  349. sizeof(DWORD)
  350. );
  351. if (dwStatus != ERROR_SUCCESS)
  352. {
  353. ClRtlLogPrint(LOG_CRITICAL,
  354. "[NM] NmpJoinFixupNodeVersion: Failed to set the lowest version\r\n"
  355. );
  356. CL_LOGFAILURE(dwStatus);
  357. goto FnExit;
  358. }
  359. //if written to the registry successfully, update the in-memory structures
  360. pNmNode->HighestVersion = dwHighestVersion;
  361. pNmNode->LowestVersion = dwLowestVersion;
  362. if (dwStatus == ERROR_SUCCESS)
  363. {
  364. ClusterEvent(CLUSTER_EVENT_NODE_PROPERTY_CHANGE, pNmNode);
  365. }
  366. FnExit:
  367. NmpReleaseLock();
  368. if (pNmNode)
  369. OmDereferenceObject(pNmNode);
  370. if (hNodeKey != NULL)
  371. DmCloseKey(hNodeKey);
  372. return(dwStatus);
  373. }
  374. /****
  375. @func HLOG | NmpIsNodeVersionAllowed| This is called at join time
  376. (not setup join) e sponsor validates if a joiner
  377. should be allowed to join a cluster at this time. In a mixed
  378. mode cluster, a node may not be able to join a cluster if another
  379. node that is two versions away is already a part of the cluster.
  380. @parm IN DWORD | dwExcludeNodeId | The node Id to exclude while
  381. evaluating the cluster operational version.
  382. @parm IN DWORD | NodeHighestVersion | The highest version with which
  383. this node can communicate.
  384. @parm IN DWORD | NodeLowestVersion | The lowest version with which this
  385. node can communicate.
  386. @parm IN BOOL |bJoin| If this is being invoked at join or form time.
  387. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  388. @comm This function is called when a node requests a sponsor to allow
  389. it to join a cluster.
  390. @xref <>
  391. ****/
  392. DWORD NmpIsNodeVersionAllowed(
  393. IN DWORD dwExcludeNodeId,
  394. IN DWORD dwNodeHighestVersion,
  395. IN DWORD dwNodeLowestVersion,
  396. IN BOOL bJoin
  397. )
  398. {
  399. DWORD dwStatus = ERROR_SUCCESS;
  400. DWORD ClusterHighestVersion;
  401. DWORD ClusterLowestVersion;
  402. PLIST_ENTRY pListEntry;
  403. DWORD dwCnt;
  404. PNM_NODE pNmNode;
  405. ClRtlLogPrint(LOG_UNUSUAL,
  406. "[NM] NmpIsNodeVersionAllowed: Entry\r\n");
  407. //acquire the NmpLocks, we will be examining the node structures
  408. NmpAcquireLock();
  409. //if NoVersionCheckOption is true
  410. if (CsNoVersionCheck)
  411. goto FnExit;
  412. //if this is a single node cluster, and this is being called at form
  413. //the count of nodes is zero.
  414. //this will happen when the registry versions dont match with
  415. //cluster service exe version numbers and we need to allow the single
  416. //node to form
  417. for (dwCnt=0, pListEntry = NmpNodeList.Flink;
  418. pListEntry != &NmpNodeList; pListEntry = pListEntry->Flink )
  419. {
  420. pNmNode = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  421. if (NmGetNodeId(pNmNode) == dwExcludeNodeId)
  422. continue;
  423. dwCnt++;
  424. }
  425. if (!dwCnt)
  426. {
  427. //allow the node to form
  428. goto FnExit;
  429. }
  430. dwStatus = NmpCalcClusterVersion(
  431. dwExcludeNodeId,
  432. &ClusterHighestVersion,
  433. &ClusterLowestVersion
  434. );
  435. if (dwStatus != ERROR_SUCCESS)
  436. {
  437. goto FnExit;
  438. }
  439. //if the node is forming and this node has just upgraded
  440. //allow the node to form as long as its minor(or build number)
  441. //is greater than or equal to all other nodes with the same
  442. //major number in the cluster
  443. if (!bJoin && CsUpgrade)
  444. {
  445. DWORD dwMinorVersion = 0x00000000;
  446. for (pListEntry = NmpNodeList.Flink; pListEntry != &NmpNodeList;
  447. pListEntry = pListEntry->Flink )
  448. {
  449. pNmNode = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  450. if (NmGetNodeId(pNmNode) == dwExcludeNodeId)
  451. continue;
  452. if (CLUSTER_GET_MAJOR_VERSION(pNmNode->HighestVersion) ==
  453. CLUSTER_GET_MAJOR_VERSION(dwNodeHighestVersion))
  454. {
  455. //the minor version to check is the maximum of the
  456. //build numbers amongst the nodes with the same major
  457. //version
  458. dwMinorVersion = max(dwMinorVersion,
  459. CLUSTER_GET_MINOR_VERSION(pNmNode->HighestVersion));
  460. }
  461. }
  462. //dont allow a lower build on a node to regress the cluster version
  463. // if other nodes have already upgraded to higher builds
  464. if ((dwMinorVersion != 0) &&
  465. (CLUSTER_GET_MINOR_VERSION(dwNodeHighestVersion) < dwMinorVersion))
  466. {
  467. dwStatus = ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  468. goto FnExit;
  469. }
  470. else
  471. {
  472. //ISSUE ::for now we allow double jumps(from n-1 to n+1)
  473. // on upgrades
  474. //skip checking versioning
  475. goto FnExit;
  476. }
  477. }
  478. //if the joiners lowest version is equal the clusters highest
  479. //For instance 3/2, 2/1 and 4/3 can all join 3/2
  480. if ((dwNodeHighestVersion == ClusterHighestVersion) ||
  481. (dwNodeHighestVersion == ClusterLowestVersion) ||
  482. (dwNodeLowestVersion == ClusterHighestVersion))
  483. {
  484. PNM_NODE pNmNode= NULL;
  485. DWORD dwMinorVersion;
  486. //since the version numbers include build number as the minor part
  487. // and we disallow a node from operating with a cluster if its
  488. // major number is equal but its minor number is different from
  489. // any of the nodes in the cluster.
  490. // The CsClusterHighestVersion doesnt encapsulate this since it just
  491. // remembers the highest version that the cluster as a whole can talk
  492. // to.
  493. // E.g 1.
  494. // 3.2003 should be able to join a cluster with nodes
  495. // 3.2002(not running and not upgraded as yet but a part of the cluster)and
  496. // 3.2003(running).
  497. // E.g 2
  498. // 3.2002 will not be able to join a cluster with nodes 3.2003(running)and
  499. // 3.2002 (not running but a part of the cluster)
  500. // E.g 3.
  501. // 3.2003 will not able to join a cluster with nodes 3.2002(running) and
  502. // 3.2002(running)
  503. dwMinorVersion = 0x00000000;
  504. for (pListEntry = NmpNodeList.Flink; pListEntry != &NmpNodeList;
  505. pListEntry = pListEntry->Flink )
  506. {
  507. pNmNode = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  508. if (NmGetNodeId(pNmNode) == dwExcludeNodeId)
  509. continue;
  510. if (CLUSTER_GET_MAJOR_VERSION(pNmNode->HighestVersion) ==
  511. CLUSTER_GET_MAJOR_VERSION(dwNodeHighestVersion))
  512. {
  513. //the minor version to check is the maximum of the
  514. //build numbers amongst the nodes with the same major
  515. //version
  516. dwMinorVersion = max(dwMinorVersion,
  517. CLUSTER_GET_MINOR_VERSION(pNmNode->HighestVersion));
  518. }
  519. }
  520. // if the joining node's build number is the same as max of build
  521. //number of all nodes within the cluster with the same major version
  522. //allow it to participate in this cluster, else dont allow it to participate in this cluster
  523. //take care of a single node case by checking the minor number against
  524. //0
  525. if ((dwMinorVersion != 0) &&
  526. (CLUSTER_GET_MINOR_VERSION(dwNodeHighestVersion) != dwMinorVersion))
  527. {
  528. dwStatus = ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  529. }
  530. }
  531. else
  532. {
  533. dwStatus = ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  534. }
  535. FnExit:
  536. NmpReleaseLock();
  537. ClRtlLogPrint(LOG_UNUSUAL,
  538. "[NM] NmpIsNodeVersionAllowed: Exit, Status=%1!u!\r\n",
  539. dwStatus);
  540. return(dwStatus);
  541. }
  542. /****
  543. @func HLOG | NmpCalcClusterVersion| This is called to calculate the
  544. operational cluster version.
  545. @parm IN DWORD | dwExcludeNodeId | The node Id to exclude while evaluating
  546. the cluster operational version.
  547. @parm OUT LPDWORD | pdwClusterHighestVersion | The highest version with which this node
  548. can communicate.
  549. @parm IN LPDWORD | pdwClusterLowestVersion | The lowest version with which this node can
  550. communicate.
  551. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  552. @comm This function must be called with the NmpLock held.
  553. @xref <f NmpResetClusterVersion> <f NmpIsNodeVersionAllowed>
  554. ****/
  555. DWORD NmpCalcClusterVersion(
  556. IN DWORD dwExcludeNodeId,
  557. OUT LPDWORD pdwClusterHighestVersion,
  558. OUT LPDWORD pdwClusterLowestVersion
  559. )
  560. {
  561. WCHAR Buffer[4];
  562. PNM_NODE pExcludeNode=NULL;
  563. PNM_NODE pNmNode;
  564. DWORD dwStatus = ERROR_SUCCESS;
  565. PLIST_ENTRY pListEntry;
  566. DWORD dwCnt = 0;
  567. //initialize the values such that min/max do the right thing
  568. *pdwClusterHighestVersion = 0xFFFFFFFF;
  569. *pdwClusterLowestVersion = 0x00000000;
  570. if (dwExcludeNodeId != ClusterInvalidNodeId)
  571. {
  572. wsprintfW(Buffer, L"%d", dwExcludeNodeId);
  573. pExcludeNode = OmReferenceObjectById(ObjectTypeNode, Buffer);
  574. if (!pExcludeNode)
  575. {
  576. dwStatus = ERROR_INVALID_PARAMETER;
  577. ClRtlLogPrint(LOG_UNUSUAL,
  578. "[NM] NmpCalcClusterVersion :Node=%1!ws! to be excluded not found\r\n",
  579. Buffer);
  580. goto FnExit;
  581. }
  582. }
  583. for ( pListEntry = NmpNodeList.Flink;
  584. pListEntry != &NmpNodeList;
  585. pListEntry = pListEntry->Flink )
  586. {
  587. pNmNode = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  588. if ((pExcludeNode) && (pExcludeNode->NodeId == pNmNode->NodeId))
  589. continue;
  590. //Actually to fix upgrade scenarios, we must fix the cluster
  591. //version such that the node with the highest minor version
  592. //is able to form/join but others arent
  593. // This is needed for multinode clusters
  594. if (CLUSTER_GET_MAJOR_VERSION(pNmNode->HighestVersion) ==
  595. CLUSTER_GET_MAJOR_VERSION(*pdwClusterHighestVersion))
  596. {
  597. if (CLUSTER_GET_MINOR_VERSION(pNmNode->HighestVersion) >
  598. CLUSTER_GET_MINOR_VERSION(*pdwClusterHighestVersion))
  599. {
  600. *pdwClusterHighestVersion = pNmNode->HighestVersion;
  601. }
  602. }
  603. else
  604. {
  605. *pdwClusterHighestVersion = min(
  606. *pdwClusterHighestVersion,
  607. pNmNode->HighestVersion
  608. );
  609. }
  610. *pdwClusterLowestVersion = max(
  611. *pdwClusterLowestVersion,
  612. pNmNode->LowestVersion
  613. );
  614. dwCnt++;
  615. }
  616. if (dwCnt == 0)
  617. {
  618. ClRtlLogPrint(LOG_NOISE,
  619. "[NM] NmpCalcClusterVersion: Single node version. Setting cluster version to node version\r\n"
  620. );
  621. //single node cluster, even though the we were requested to
  622. //exclude this node, the cluster version must be calculated
  623. //using that node's version
  624. *pdwClusterHighestVersion = pExcludeNode->HighestVersion;
  625. *pdwClusterLowestVersion = pExcludeNode->LowestVersion;
  626. }
  627. CL_ASSERT(*pdwClusterHighestVersion != 0xFFFFFFFF);
  628. CL_ASSERT(*pdwClusterLowestVersion != 0x00000000);
  629. FnExit:
  630. ClRtlLogPrint(LOG_NOISE,
  631. "[NM] NmpCalcClusterVersion: status = %1!u! ClusHighestVer=0x%2!08lx!, ClusLowestVer=0x%3!08lx!\r\n",
  632. dwStatus, *pdwClusterHighestVersion, *pdwClusterLowestVersion);
  633. if (pExcludeNode) OmDereferenceObject(pExcludeNode);
  634. return(dwStatus);
  635. }
  636. VOID
  637. NmpProcessClusterVersionChange(
  638. VOID
  639. )
  640. /*++
  641. Notes:
  642. Called with the NmpLock held.
  643. --*/
  644. {
  645. DWORD status;
  646. LPWSTR szClusterName=NULL;
  647. DWORD dwSize=0;
  648. NmpMulticastProcessClusterVersionChange();
  649. //rjain: issue CLUSTER_EVENT_PROPERTY_CHANGE to propagate new
  650. //cluster version info
  651. DmQuerySz( DmClusterParametersKey,
  652. CLUSREG_NAME_CLUS_NAME,
  653. &szClusterName,
  654. &dwSize,
  655. &dwSize);
  656. if(szClusterName)
  657. ClusterEventEx(
  658. CLUSTER_EVENT_PROPERTY_CHANGE,
  659. EP_FREE_CONTEXT,
  660. szClusterName
  661. );
  662. return;
  663. } // NmpProcessClusterVersionChange
  664. /****
  665. @func DWORD | NmpBuildVersionInfo| Its a callback function used by
  666. NmPerformFixups to build a property list of the Major Version,
  667. Minor version, Build Number and CSDVersionInfo, This propertylist
  668. is used by NmUpdatePerformFixups Update type to store this info
  669. in registry.
  670. @parm IN DWORD | dwFixupType| JoinFixup or FormFixup
  671. @parm OUT PVOID* | ppPropertyList| Pointer to the pointer to the property list
  672. @parm OUT LPDWORD | pdwProperyListSize | Pointer to the property list size
  673. @param OUT LPWSTR* | pszKeyName. The name of registry key for which this
  674. property list is being constructed.
  675. @rdesc Returns a result code. ERROR_SUCCESS on success.
  676. @xref <f NmpUpdatePerformFixups2>
  677. ****/
  678. DWORD NmpBuildVersionInfo(
  679. IN DWORD dwFixUpType,
  680. OUT PVOID * ppPropertyList,
  681. OUT LPDWORD pdwPropertyListSize,
  682. OUT LPWSTR * pszKeyName
  683. )
  684. {
  685. DWORD dwStatus=ERROR_SUCCESS;
  686. LPBYTE pInParams=NULL;
  687. DWORD Required,Returned;
  688. HDMKEY hdmKey;
  689. DWORD dwTemp;
  690. CLUSTERVERSIONINFO ClusterVersionInfo;
  691. LPWSTR szTemp=NULL;
  692. *ppPropertyList = NULL;
  693. *pdwPropertyListSize = 0;
  694. //check we if need to send this information
  695. dwTemp=(lstrlenW(CLUSREG_KEYNAME_NODES) + lstrlenW(L"\\")+lstrlenW(NmLocalNodeIdString)+1)*sizeof(WCHAR);
  696. *pszKeyName=(LPWSTR)LocalAlloc(LMEM_FIXED,dwTemp);
  697. if(*pszKeyName==NULL)
  698. {
  699. dwStatus =GetLastError();
  700. goto FnExit;
  701. }
  702. lstrcpyW(*pszKeyName,CLUSREG_KEYNAME_NODES);
  703. lstrcatW(*pszKeyName,L"\\");
  704. lstrcatW(*pszKeyName,NmLocalNodeIdString);
  705. // Build the parameter list
  706. pInParams=(LPBYTE)LocalAlloc(LMEM_FIXED,4*sizeof(DWORD)+sizeof(LPWSTR));
  707. if(pInParams==NULL)
  708. {
  709. dwStatus =GetLastError();
  710. goto FnExit;
  711. }
  712. CsGetClusterVersionInfo(&ClusterVersionInfo);
  713. dwTemp=(DWORD)ClusterVersionInfo.MajorVersion;
  714. CopyMemory(pInParams,&dwTemp,sizeof(DWORD));
  715. dwTemp=(DWORD)ClusterVersionInfo.MinorVersion;
  716. CopyMemory(pInParams+sizeof(DWORD),&dwTemp,sizeof(DWORD));
  717. dwTemp=(DWORD)ClusterVersionInfo.BuildNumber;
  718. CopyMemory(pInParams+2*sizeof(DWORD),&dwTemp,sizeof(DWORD));
  719. if(ClusterVersionInfo.szCSDVersion==NULL)
  720. szTemp=NULL;
  721. else
  722. {
  723. szTemp=(LPWSTR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,(lstrlenW(ClusterVersionInfo.szCSDVersion) +1)*sizeof(WCHAR));
  724. if (szTemp==NULL)
  725. {
  726. dwStatus=GetLastError();
  727. goto FnExit;
  728. }
  729. lstrcpyW(szTemp,ClusterVersionInfo.szCSDVersion);
  730. szTemp[lstrlenW(ClusterVersionInfo.szCSDVersion)]=L'\0';
  731. }
  732. CopyMemory(pInParams+3*sizeof(DWORD),&szTemp,sizeof(LPWSTR));
  733. //copy the suite information
  734. CopyMemory(pInParams+3*sizeof(DWORD)+sizeof(LPWSTR*),
  735. &CsMyProductSuite, sizeof(DWORD));
  736. Required=sizeof(DWORD);
  737. AllocMem:
  738. *ppPropertyList=(LPBYTE)LocalAlloc(LMEM_FIXED, Required);
  739. if(*ppPropertyList==NULL)
  740. {
  741. dwStatus=GetLastError();
  742. goto FnExit;
  743. }
  744. *pdwPropertyListSize=Required;
  745. dwStatus = ClRtlPropertyListFromParameterBlock(
  746. NmFixupVersionInfo,
  747. *ppPropertyList,
  748. pdwPropertyListSize,
  749. (LPBYTE)pInParams,
  750. &Returned,
  751. &Required
  752. );
  753. *pdwPropertyListSize=Returned;
  754. if (dwStatus==ERROR_MORE_DATA)
  755. {
  756. LocalFree(*ppPropertyList);
  757. *ppPropertyList=NULL;
  758. goto AllocMem;
  759. }
  760. else
  761. if (dwStatus != ERROR_SUCCESS)
  762. {
  763. ClRtlLogPrint(LOG_CRITICAL,"[NM] NmBuildVersionInfo - error = %1!u!\r\n",dwStatus);
  764. goto FnExit;
  765. }
  766. FnExit:
  767. // Cleanup
  768. if (szTemp)
  769. LocalFree(szTemp);
  770. if(pInParams)
  771. LocalFree(pInParams);
  772. return dwStatus;
  773. }//NmpBuildVersionInfo
  774. /****
  775. @func HLOG | NmpCalcClusterNodeLimit|This is called to calculate the
  776. operational cluster node limit.
  777. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  778. @comm This acquires/releases NmpLock.
  779. @xref <f NmpResetClusterVersion> <f NmpIsNodeVersionAllowed>
  780. ****/
  781. DWORD NmpCalcClusterNodeLimit(
  782. )
  783. {
  784. PNM_NODE pNmNode;
  785. DWORD dwStatus = ERROR_SUCCESS;
  786. PLIST_ENTRY pListEntry;
  787. //acquire the lock, we are going to be messing with the operational
  788. //versions for the cluster
  789. NmpAcquireLock();
  790. CsClusterNodeLimit = NmMaxNodeId;
  791. for ( pListEntry = NmpNodeList.Flink;
  792. pListEntry != &NmpNodeList;
  793. pListEntry = pListEntry->Flink )
  794. {
  795. pNmNode = CONTAINING_RECORD(pListEntry, NM_NODE, Linkage);
  796. CsClusterNodeLimit = min(
  797. CsClusterNodeLimit,
  798. ClRtlGetDefaultNodeLimit(
  799. pNmNode->ProductSuite
  800. )
  801. );
  802. }
  803. ClRtlLogPrint(LOG_NOISE,
  804. "[NM] Calculated cluster node limit = %1!u!\r\n",
  805. CsClusterNodeLimit);
  806. NmpReleaseLock();
  807. return (dwStatus);
  808. }
  809. /****
  810. @func VOID| NmpResetClusterNodeLimit| An operational node limit
  811. on the number of nodes that can join this cluster is maintained.
  812. @rdesc Returns ERROR_SUCCESS on success or a win32 error code on failure.
  813. @comm This function is called when a node forms a cluster(to initialize
  814. the operational version) OR when a node joins a cluster (to
  815. initialize its version) OR when a node is ejected from a
  816. cluster(to recalculate the clusterversion).
  817. @xref <>
  818. ****/
  819. VOID
  820. NmpResetClusterNodeLimit(
  821. )
  822. {
  823. NmpCalcClusterNodeLimit();
  824. }
  825.