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.

862 lines
22 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. group.c
  5. Abstract:
  6. Provides interface for managing cluster groups
  7. Author:
  8. John Vert (jvert) 30-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "clusapip.h"
  12. HGROUP
  13. WINAPI
  14. CreateClusterGroup(
  15. IN HCLUSTER hCluster,
  16. IN LPCWSTR lpszGroupName
  17. )
  18. /*++
  19. Routine Description:
  20. Creates a new cluster group.
  21. Arguments:
  22. hCluster - Supplies a handle to a previously opened cluster.
  23. lpszGroupName - Supplies the name of the group. If the specified
  24. group already exists, it is opened.
  25. Return Value:
  26. non-NULL - returns an open handle to the specified group.
  27. NULL - The operation failed. Extended error status is available
  28. using GetLastError()
  29. --*/
  30. {
  31. PCLUSTER Cluster;
  32. PCGROUP Group;
  33. error_status_t Status = ERROR_SUCCESS;
  34. Cluster = (PCLUSTER)hCluster;
  35. Group = LocalAlloc(LMEM_FIXED, sizeof(CGROUP));
  36. if (Group == NULL) {
  37. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  38. return(NULL);
  39. }
  40. Group->Name = LocalAlloc(LMEM_FIXED, (lstrlenW(lpszGroupName)+1)*sizeof(WCHAR));
  41. if (Group->Name == NULL) {
  42. LocalFree(Group);
  43. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  44. return(NULL);
  45. }
  46. lstrcpyW(Group->Name, lpszGroupName);
  47. Group->Cluster = Cluster;
  48. InitializeListHead(&Group->NotifyList);
  49. WRAP_NULL(Group->hGroup,
  50. (ApiCreateGroup(Cluster->RpcBinding,
  51. lpszGroupName,
  52. &Status)),
  53. &Status,
  54. Cluster);
  55. if ((Group->hGroup == NULL) ||
  56. (Status != ERROR_SUCCESS)) {
  57. LocalFree(Group->Name);
  58. LocalFree(Group);
  59. SetLastError(Status);
  60. return(NULL);
  61. }
  62. //
  63. // Link newly opened group onto the cluster structure.
  64. //
  65. EnterCriticalSection(&Cluster->Lock);
  66. InsertHeadList(&Cluster->GroupList, &Group->ListEntry);
  67. LeaveCriticalSection(&Cluster->Lock);
  68. return ((HGROUP)Group);
  69. }
  70. HGROUP
  71. WINAPI
  72. OpenClusterGroup(
  73. IN HCLUSTER hCluster,
  74. IN LPCWSTR lpszGroupName
  75. )
  76. /*++
  77. Routine Description:
  78. Opens a handle to the specified group
  79. Arguments:
  80. hCluster - Supplies a handle to the cluster
  81. lpszGroupName - Supplies the name of the group to be opened
  82. Return Value:
  83. non-NULL - returns an open handle to the specified group.
  84. NULL - The operation failed. Extended error status is available
  85. using GetLastError()
  86. --*/
  87. {
  88. PCLUSTER Cluster;
  89. PCGROUP Group;
  90. error_status_t Status = ERROR_SUCCESS;
  91. Cluster = (PCLUSTER)hCluster;
  92. Group = LocalAlloc(LMEM_FIXED, sizeof(CGROUP));
  93. if (Group == NULL) {
  94. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  95. return(NULL);
  96. }
  97. Group->Name = LocalAlloc(LMEM_FIXED, (lstrlenW(lpszGroupName)+1)*sizeof(WCHAR));
  98. if (Group->Name == NULL) {
  99. LocalFree(Group);
  100. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  101. return(NULL);
  102. }
  103. lstrcpyW(Group->Name, lpszGroupName);
  104. Group->Cluster = Cluster;
  105. InitializeListHead(&Group->NotifyList);
  106. WRAP_NULL(Group->hGroup,
  107. (ApiOpenGroup(Cluster->RpcBinding,
  108. lpszGroupName,
  109. &Status)),
  110. &Status,
  111. Cluster);
  112. if ((Group->hGroup == NULL) ||
  113. (Status != ERROR_SUCCESS)) {
  114. LocalFree(Group->Name);
  115. LocalFree(Group);
  116. SetLastError(Status);
  117. return(NULL);
  118. }
  119. //
  120. // Link newly opened group onto the cluster structure.
  121. //
  122. EnterCriticalSection(&Cluster->Lock);
  123. InsertHeadList(&Cluster->GroupList, &Group->ListEntry);
  124. LeaveCriticalSection(&Cluster->Lock);
  125. return ((HGROUP)Group);
  126. }
  127. BOOL
  128. WINAPI
  129. CloseClusterGroup(
  130. IN HGROUP hGroup
  131. )
  132. /*++
  133. Routine Description:
  134. Closes a group handle returned from OpenClusterGroup
  135. Arguments:
  136. hGroup - Supplies the group handle
  137. Return Value:
  138. TRUE - The operation was successful.
  139. FALSE - The operation failed. Extended error status is available
  140. using GetLastError()
  141. --*/
  142. {
  143. PCGROUP Group;
  144. PCLUSTER Cluster;
  145. Group = (PCGROUP)hGroup;
  146. Cluster = (PCLUSTER)Group->Cluster;
  147. //
  148. // Unlink group from cluster list.
  149. //
  150. EnterCriticalSection(&Cluster->Lock);
  151. RemoveEntryList(&Group->ListEntry);
  152. //
  153. // Remove any notifications posted against this group.
  154. //
  155. RundownNotifyEvents(&Group->NotifyList, Group->Name);
  156. //if the cluster is dead and the reconnect has failed,
  157. //the group->hgroup might be NULL if s_apiopengroup for
  158. //this group failed on a reconnect
  159. //the cluster may be dead and hgroup may be non null, say
  160. //if reconnectgroups succeeded but the reconnect networks
  161. //failed
  162. //At reconnect, the old context is saved in the obsolete
  163. //list for deletion when the cluster handle is closed or
  164. //when the next api call is made
  165. if ((Cluster->Flags & CLUS_DEAD) && (Group->hGroup))
  166. {
  167. RpcSmDestroyClientContext(&Group->hGroup);
  168. LeaveCriticalSection(&Cluster->Lock);
  169. goto FnExit;
  170. }
  171. LeaveCriticalSection(&Cluster->Lock);
  172. //SS :: If this fails, should we delete the client side context
  173. //there is a potential leak here since this client side context
  174. //will never get cleaned up since this context is not on the
  175. //obsolete list and the error here is simply igonored
  176. //
  177. // Close RPC context handle
  178. // If the server dies, we still clean up the client side
  179. // and rely on the rundown mechanism to clean up server side state
  180. //
  181. ApiCloseGroup(&Group->hGroup);
  182. FnExit:
  183. //
  184. // Free memory allocations
  185. //
  186. LocalFree(Group->Name);
  187. LocalFree(Group);
  188. //
  189. // Give the cluster a chance to clean up in case this
  190. // group was the only thing keeping it around.
  191. //
  192. CleanupCluster(Cluster);
  193. return(TRUE);
  194. }
  195. CLUSTER_GROUP_STATE
  196. WINAPI
  197. GetClusterGroupState(
  198. IN HGROUP hGroup,
  199. OUT LPWSTR lpszNodeName,
  200. IN OUT LPDWORD lpcchNodeName
  201. )
  202. /*++
  203. Routine Description:
  204. Returns the group's current state and the node where it is
  205. currently online.
  206. Arguments:
  207. hGroup - Supplies a handle to a cluster group
  208. lpszNodeName - Returns the name of the node in the cluster where the
  209. given group is currently online
  210. lpcchNodeName - Supplies a pointer to a DWORD containing the number of
  211. characters available in the lpszNodeName buffer
  212. Returns the number of characters (not including the terminating
  213. NULL character) written to the lpszNodeName buffer
  214. Return Value:
  215. Returns the current state of the group. Possible states are
  216. ClusterGroupOnline
  217. ClusterGroupOffline
  218. ClusterGroupFailed
  219. ClusterGroupPartialOnline
  220. ClusterGroupPending
  221. If the function fails, the return value is -1. Extended error
  222. status is available using GetLastError()
  223. --*/
  224. {
  225. PCGROUP Group;
  226. LPWSTR NodeName=NULL;
  227. CLUSTER_GROUP_STATE State;
  228. DWORD Status;
  229. DWORD Length;
  230. Group = (PCGROUP)hGroup;
  231. WRAP(Status,
  232. (ApiGetGroupState( Group->hGroup,
  233. (LPDWORD)&State, // cast for win64 warning
  234. &NodeName )),
  235. Group->Cluster);
  236. if (Status == ERROR_SUCCESS) {
  237. if (ARGUMENT_PRESENT(lpszNodeName)) {
  238. MylstrcpynW(lpszNodeName, NodeName, *lpcchNodeName);
  239. Length = lstrlenW(NodeName);
  240. if (Length >= *lpcchNodeName) {
  241. Status = ERROR_MORE_DATA;
  242. State = ClusterGroupStateUnknown; // -1
  243. }
  244. *lpcchNodeName = Length;
  245. }
  246. MIDL_user_free(NodeName);
  247. } else {
  248. State = ClusterGroupStateUnknown;
  249. }
  250. SetLastError(Status);
  251. return (State);
  252. }
  253. DWORD
  254. WINAPI
  255. SetClusterGroupName(
  256. IN HGROUP hGroup,
  257. IN LPCWSTR lpszGroupName
  258. )
  259. /*++
  260. Routine Description:
  261. Sets the friendly name of a cluster group
  262. Arguments:
  263. hGroup - Supplies a handle to a cluster group
  264. lpszGroupName - Supplies the new name of the cluster group
  265. Return Value:
  266. ERROR_SUCCESS if successful
  267. Win32 error code otherwise
  268. --*/
  269. {
  270. PCGROUP Group;
  271. DWORD Status;
  272. Group = (PCGROUP)hGroup;
  273. WRAP(Status,
  274. (ApiSetGroupName(Group->hGroup, lpszGroupName)),
  275. Group->Cluster);
  276. return(Status);
  277. }
  278. DWORD
  279. WINAPI
  280. SetClusterGroupNodeList(
  281. IN HGROUP hGroup,
  282. IN DWORD NodeCount,
  283. IN HNODE NodeList[]
  284. )
  285. /*++
  286. Routine Description:
  287. Sets the preferred node list of the specified cluster group
  288. Arguments:
  289. hGroup - Supplies the group whose preferred node list is to be set.
  290. NodeCount - Supplies the number of nodes in the preferred node list.
  291. NodeList - Supplies a pointer to an array of node handles. The number
  292. of nodes in the array is specified by the NodeCount parameter. The
  293. nodes in the array should be ordered by their preference. The first
  294. node in the array is the most preferred node.
  295. Return Value:
  296. ERROR_SUCCESS if successful
  297. Win32 error code otherwise
  298. --*/
  299. {
  300. PCGROUP Group = (PCGROUP)hGroup;
  301. DWORD i,j;
  302. LPWSTR *IdArray;
  303. DWORD Status;
  304. DWORD ListLength = sizeof(WCHAR);
  305. HKEY GroupKey = NULL;
  306. LPWSTR List = NULL;
  307. LPWSTR p;
  308. DWORD Length;
  309. PCNODE Node;
  310. //
  311. // First, iterate through all the nodes and obtain their IDs.
  312. //
  313. IdArray = LocalAlloc(LMEM_ZEROINIT, NodeCount*sizeof(LPWSTR));
  314. if (IdArray == NULL) {
  315. return( ERROR_NOT_ENOUGH_MEMORY );
  316. }
  317. for (i=0; i<NodeCount; i++) {
  318. Node = (PCNODE)NodeList[i];
  319. //
  320. // Make sure this isn't a handle to a node from a different
  321. // cluster
  322. //
  323. if (Node->Cluster != Group->Cluster) {
  324. Status = ERROR_INVALID_PARAMETER;
  325. goto error_exit;
  326. }
  327. WRAP(Status,
  328. (ApiGetNodeId(Node->hNode,
  329. &IdArray[i])),
  330. Group->Cluster);
  331. if (Status != ERROR_SUCCESS) {
  332. goto error_exit;
  333. }
  334. //
  335. // Make sure there are no duplicates
  336. //
  337. for (j=0; j<i; j++) {
  338. if (lstrcmpiW(IdArray[j],IdArray[i]) == 0) {
  339. //
  340. // A duplicate node is in the list
  341. //
  342. Status = ERROR_INVALID_PARAMETER;
  343. goto error_exit;
  344. }
  345. }
  346. ListLength += (lstrlenW(IdArray[i])+1)*sizeof(WCHAR);
  347. }
  348. GroupKey = GetClusterGroupKey(hGroup, KEY_READ | KEY_WRITE);
  349. if (GroupKey == NULL) {
  350. Status = GetLastError();
  351. goto error_exit;
  352. }
  353. //
  354. // Allocate a buffer to hold the REG_MULTI_SZ
  355. //
  356. List = LocalAlloc(LMEM_FIXED, ListLength);
  357. if (List == NULL) {
  358. Status = ERROR_NOT_ENOUGH_MEMORY;
  359. goto error_exit;
  360. }
  361. //
  362. // Copy all the strings into the buffer.
  363. //
  364. p = List;
  365. for (i=0; i<NodeCount; i++) {
  366. lstrcpyW(p, IdArray[i]);
  367. p += lstrlenW(IdArray[i])+1;
  368. }
  369. *p = L'\0'; // add the final NULL terminator to the MULTI_SZ
  370. //
  371. // Finally, tell the backend
  372. //
  373. WRAP(Status,
  374. (ApiSetGroupNodeList(Group->hGroup, (UCHAR *)List, ListLength)),
  375. Group->Cluster);
  376. error_exit:
  377. if (GroupKey != NULL) {
  378. ClusterRegCloseKey(GroupKey);
  379. }
  380. if (List != NULL) {
  381. LocalFree(List);
  382. }
  383. for (i=0; i<NodeCount; i++) {
  384. if (IdArray[i] != NULL) {
  385. MIDL_user_free(IdArray[i]);
  386. }
  387. }
  388. LocalFree(IdArray);
  389. return(Status);
  390. }
  391. DWORD
  392. WINAPI
  393. OnlineClusterGroup(
  394. IN HGROUP hGroup,
  395. IN OPTIONAL HNODE hDestinationNode
  396. )
  397. /*++
  398. Routine Description:
  399. Brings an offline group online.
  400. If hDestinationNode is specified, but the group is not capable
  401. of being brought online there, this API fails.
  402. If NULL is specified as the hDestinationNode, the best possible
  403. node is chosen by the cluster software.
  404. If NULL is specified but no node where this group
  405. can be brought online is currently available, this API fails.
  406. Arguments:
  407. hGroup - Supplies a handle to the group to be failed over
  408. hDestinationNode - If present, supplies the node where this group
  409. should be brought back online.
  410. Return Value:
  411. If the function succeeds, the return value is ERROR_SUCCESS.
  412. If the function fails, the return value is an error value. If a suitable
  413. host node is not available, the error value is
  414. ERROR_HOST_NODE_NOT_AVAILABLE.
  415. --*/
  416. {
  417. PCNODE Node;
  418. PCGROUP Group;
  419. DWORD Status;
  420. Group = (PCGROUP)hGroup;
  421. Node = (PCNODE)hDestinationNode;
  422. if (Node != NULL) {
  423. WRAP(Status,
  424. (ApiMoveGroupToNode( Group->hGroup,
  425. Node->hNode)),
  426. Group->Cluster);
  427. if (Status != ERROR_SUCCESS) {
  428. return(Status);
  429. }
  430. }
  431. WRAP(Status,
  432. (ApiOnlineGroup( Group->hGroup )),
  433. Group->Cluster);
  434. return(Status);
  435. }
  436. DWORD
  437. WINAPI
  438. MoveClusterGroup(
  439. IN HGROUP hGroup,
  440. IN OPTIONAL HNODE hDestinationNode
  441. )
  442. /*++
  443. Routine Description:
  444. Moves an entire group from one node to another.
  445. If hDestinationNode is specified, but the group is not capable
  446. of being brought online there, this API fails.
  447. If NULL is specified as the hDestinationNode, the best possible
  448. node is chosen by the cluster software.
  449. If NULL is specified but no node where this group
  450. can be brought online is currently available, this API fails.
  451. Arguments:
  452. hGroup - Supplies a handle to the group to be moved
  453. hDestinationNode - If present, supplies the node where this group
  454. should be brought back online.
  455. Return Value:
  456. If the function succeeds, the return value is ERROR_SUCCESS.
  457. If the function fails, the return value is an error value. If a suitable
  458. host node is not availabe, the error value is
  459. ERROR_HOST_NODE_NOT_AVAILABLE.
  460. --*/
  461. {
  462. PCGROUP Group;
  463. PCNODE Node;
  464. DWORD Status;
  465. DWORD MoveStatus;
  466. DWORD Generation;
  467. BOOL bReconnected = FALSE;
  468. Group = (PCGROUP)hGroup;
  469. Node = (PCNODE)hDestinationNode;
  470. //
  471. // This API is not as simple as it should be because it is not idempotent.
  472. // In the case where hDestinationNode == NULL, we don't know where the group
  473. // will end up. And it will move each time we call it. So the normal mechanism
  474. // of failing over the API will not work in the case where the group to be
  475. // moved contains the cluster name we are connected to. The RPC call to move
  476. // the group will "fail" because the connection is dropped, but the call really
  477. // succeeded. So we will reconnect, retry, and fail again as the group moves again.
  478. //
  479. // So the approach taken here if hDestinationNode is not specified is to find out
  480. // where the group is currently, then move the group (somewhere else). If
  481. // ApiMoveGroup fails, and ReconnectCluster succeeds, then find out where the
  482. // group is again. If it is different, return success. If it is the same, try again.
  483. //
  484. if (hDestinationNode != NULL) {
  485. //
  486. // Chittur Subbaraman (chitturs) - 10/13/99
  487. //
  488. // If ApiMoveGroupToNode returns ERROR_INVALID_STATE due to the
  489. // reissue of the move upon a reconnect, then tell the caller
  490. // that the move is pending.
  491. //
  492. Generation = Group->Cluster->Generation;
  493. WRAP(Status,
  494. (ApiMoveGroupToNode( Group->hGroup,
  495. Node->hNode)),
  496. Group->Cluster);
  497. if ((Status == ERROR_INVALID_STATE) &&
  498. (Generation < Group->Cluster->Generation)) {
  499. Status = ERROR_IO_PENDING;
  500. }
  501. } else {
  502. LPWSTR OldNodeName = NULL;
  503. CLUSTER_GROUP_STATE State;
  504. WRAP(Status,
  505. (ApiGetGroupState( Group->hGroup,
  506. (LPDWORD)&State, // cast for win64 warning
  507. &OldNodeName)),
  508. Group->Cluster);
  509. if (Status != ERROR_SUCCESS) {
  510. return(Status);
  511. }
  512. //
  513. // Chittur Subbaraman (chitturs) - 5/5/99
  514. //
  515. // Added logic to call ApiMoveGroup until it is successful or
  516. // until all possible candidates have been tried.
  517. //
  518. do {
  519. Status = MoveStatus = ApiMoveGroup(Group->hGroup);
  520. //
  521. // Get out if the move is successful
  522. //
  523. if ((Status == ERROR_IO_PENDING) ||
  524. (Status == ERROR_SUCCESS)) {
  525. break;
  526. }
  527. //
  528. // Chittur Subbaraman (chitturs) - 7/8/99
  529. //
  530. // If the group is not quiet and you have reconnected, then
  531. // just tell the client that the group state is pending.
  532. // This case happens if the node to which the client is
  533. // connected to crashes and this function reissues the move
  534. // "blindly" on a reconnect. In such a case, the group could
  535. // be in pending state and there is no point in returning an
  536. // error status. Note however that the group ownership may
  537. // not change in such a case and then the client has to figure
  538. // this out and reissue the move.
  539. //
  540. if ((Status == ERROR_INVALID_STATE) &&
  541. (bReconnected)) {
  542. Status = ERROR_IO_PENDING;
  543. break;
  544. }
  545. Generation = Group->Cluster->Generation;
  546. //
  547. // The above move attempt may have failed. So, try reconnecting.
  548. //
  549. Status = ReconnectCluster(Group->Cluster, Status, Generation);
  550. if (Status == ERROR_SUCCESS) {
  551. LPWSTR NewNodeName = NULL;
  552. //
  553. // Successfully reconnected, see where the group is now.
  554. //
  555. WRAP(Status,
  556. (ApiGetGroupState(Group->hGroup,
  557. (LPDWORD)&State, // cast for win64 warn
  558. &NewNodeName)),
  559. Group->Cluster);
  560. if (Status == ERROR_SUCCESS) {
  561. if (lstrcmpiW(NewNodeName, OldNodeName) != 0) {
  562. //
  563. // The group has already moved. Return ERROR_SUCCESS.
  564. //
  565. MIDL_user_free(NewNodeName);
  566. break;
  567. }
  568. bReconnected = TRUE;
  569. MIDL_user_free(NewNodeName);
  570. } else {
  571. //
  572. // Return status of the failed move operation.
  573. //
  574. Status = MoveStatus;
  575. break;
  576. }
  577. } else {
  578. //
  579. // Return status of the failed move operation.
  580. //
  581. Status = MoveStatus;
  582. break;
  583. }
  584. } while ( TRUE );
  585. MIDL_user_free(OldNodeName);
  586. }
  587. return(Status);
  588. }
  589. DWORD
  590. WINAPI
  591. OfflineClusterGroup(
  592. IN HGROUP hGroup
  593. )
  594. /*++
  595. Routine Description:
  596. Brings an online group offline
  597. Arguments:
  598. hGroup - Supplies a handle to the group to be taken offline
  599. Return Value:
  600. If the function succeeds, the return value is ERROR_SUCCESS.
  601. If the function fails, the return value is an error value.
  602. --*/
  603. {
  604. PCGROUP Group;
  605. DWORD Status;
  606. Group = (PCGROUP)hGroup;
  607. WRAP(Status,
  608. (ApiOfflineGroup( Group->hGroup )),
  609. Group->Cluster);
  610. return(Status);
  611. }
  612. DWORD
  613. WINAPI
  614. DeleteClusterGroup(
  615. IN HGROUP hGroup
  616. )
  617. /*++
  618. Routine Description:
  619. Deletes the specified cluster group from the cluster. The cluster
  620. group must contain no resources.
  621. Arguments:
  622. hGroup - Specifies the cluster group to be deleted.
  623. Return Value:
  624. If the function succeeds, the return value is ERROR_SUCCESS.
  625. If the function fails, the return value is an error value.
  626. --*/
  627. {
  628. PCGROUP Group;
  629. DWORD Status;
  630. Group = (PCGROUP)hGroup;
  631. WRAP(Status,
  632. (ApiDeleteGroup( Group->hGroup )),
  633. Group->Cluster);
  634. return(Status);
  635. }
  636. HCLUSTER
  637. WINAPI
  638. GetClusterFromGroup(
  639. IN HGROUP hGroup
  640. )
  641. /*++
  642. Routine Description:
  643. Returns the cluster handle from the associated group handle.
  644. Arguments:
  645. hGroup - Supplies the group.
  646. Return Value:
  647. Handle to the cluster associated with the group handle.
  648. --*/
  649. {
  650. DWORD nStatus;
  651. PCGROUP Group = (PCGROUP)hGroup;
  652. HCLUSTER hCluster = (HCLUSTER)Group->Cluster;
  653. nStatus = AddRefToClusterHandle( hCluster );
  654. if ( nStatus != ERROR_SUCCESS ) {
  655. SetLastError( nStatus );
  656. hCluster = NULL;
  657. }
  658. return( hCluster );
  659. } // GetClusterFromGroup()