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.

1704 lines
48 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. grouparb.c
  5. Abstract:
  6. Cluster group arbitration and sorting routines.
  7. Author:
  8. Rod Gamache (rodga) 8-Mar-1996
  9. Revision History:
  10. --*/
  11. #include "fmp.h"
  12. #define LOG_MODULE GROUPARB
  13. //
  14. // Global data
  15. //
  16. //
  17. // Local function prototypes
  18. //
  19. typedef struct FM_GROUP_ENUM_DATA {
  20. DWORD Allocated;
  21. PNM_NODE OwnerNode;
  22. BOOL QuorumGroup;
  23. } FM_GROUP_ENUM_DATA, *PFM_GROUP_ENUM_DATA;
  24. BOOL
  25. FmpEnumGroups(
  26. IN OUT PGROUP_ENUM *Enum,
  27. IN PFM_GROUP_ENUM_DATA EnumData,
  28. IN PFM_GROUP Group,
  29. IN LPCWSTR Name
  30. );
  31. BOOL
  32. FmpEqualGroupLists(
  33. IN PGROUP_ENUM Group1,
  34. IN PGROUP_ENUM Group2
  35. );
  36. int
  37. _cdecl
  38. SortCompare(
  39. IN const void * Elem1,
  40. IN const void * Elem2
  41. );
  42. DWORD
  43. FmpEnumSortGroups(
  44. OUT PGROUP_ENUM *ReturnEnum,
  45. IN OPTIONAL PNM_NODE OwnerNode,
  46. OUT PBOOL QuorumGroup
  47. )
  48. /*++
  49. Routine Description:
  50. Enumerates and sorts the list of Groups.
  51. Arguments:
  52. ReturnEnum - Returns the requested objects.
  53. OwnerNode - If present, supplies the owner node to filter
  54. the list of groups. (i.e. if you supply this, you
  55. get a list of groups owned by that node)
  56. If not present, all groups are returned.
  57. QuorumGroup - Returns TRUE if the quorum resource in one of the groups
  58. returned in the ENUM.
  59. Return Value:
  60. ERROR_SUCCESS if successful.
  61. Win32 error code on error.
  62. --*/
  63. {
  64. DWORD status;
  65. PGROUP_ENUM groupEnum = NULL;
  66. FM_GROUP_ENUM_DATA EnumData;
  67. EnumData.Allocated = ENUM_GROW_SIZE;
  68. EnumData.OwnerNode = OwnerNode;
  69. EnumData.QuorumGroup = FALSE;
  70. groupEnum = LocalAlloc(LMEM_FIXED, GROUP_SIZE(ENUM_GROW_SIZE));
  71. if ( groupEnum == NULL ) {
  72. status = ERROR_NOT_ENOUGH_MEMORY;
  73. goto error_exit;
  74. }
  75. groupEnum->EntryCount = 0;
  76. //
  77. // Enumerate all groups, sort with Quorum Group first in the list.
  78. //
  79. OmEnumObjects(ObjectTypeGroup,
  80. FmpEnumGroups,
  81. &groupEnum,
  82. &EnumData);
  83. *ReturnEnum = groupEnum;
  84. *QuorumGroup = EnumData.QuorumGroup;
  85. return(ERROR_SUCCESS);
  86. error_exit:
  87. if ( groupEnum != NULL ) {
  88. LocalFree( groupEnum );
  89. }
  90. *ReturnEnum = NULL;
  91. *QuorumGroup = FALSE;
  92. return(status);
  93. } // FmpEnumSortGroups
  94. DWORD
  95. FmpGetGroupListState(
  96. PGROUP_ENUM GroupEnum
  97. )
  98. /*++
  99. Routine Description:
  100. This routine gets the Group state for each of the Groups in the list.
  101. Arguments:
  102. GroupEnum - The list of Groups we now own.
  103. Returns:
  104. ERROR_SUCCESS if successful.
  105. Win32 error code on failure.
  106. --*/
  107. {
  108. PFM_GROUP group;
  109. DWORD i;
  110. for ( i = 0; i < GroupEnum->EntryCount; i++ ) {
  111. group = OmReferenceObjectById( ObjectTypeGroup,
  112. GroupEnum->Entry[i].Id );
  113. if ( group == NULL ) {
  114. return(ERROR_GROUP_NOT_FOUND);
  115. }
  116. ClRtlLogPrint( LOG_NOISE,
  117. "[FM] GetGroupListState, Group <%1!ws!> state = %2!d!\n",
  118. OmObjectName(group), group->State );
  119. if ( (group->State == ClusterGroupFailed) ||
  120. (group->State == ClusterGroupPartialOnline) ) {
  121. GroupEnum->Entry[i].State = ClusterGroupOnline;
  122. } else {
  123. GroupEnum->Entry[i].State = group->State;
  124. }
  125. OmDereferenceObject( group );
  126. }
  127. return(ERROR_SUCCESS);
  128. } // FmpGetGroupListState
  129. DWORD
  130. FmpOnlineGroupList(
  131. IN PGROUP_ENUM GroupEnum,
  132. IN BOOL bPrepareQuoForOnline
  133. )
  134. /*++
  135. Routine Description:
  136. Brings online all Groups in the Enum list. If the quorum group
  137. is present in the list, then it must be first.
  138. Arguments:
  139. GroupEnum - The list of Groups to bring online.
  140. bPrepareQuoForOnline - Indicates whether the quorum resource should be
  141. forced prepared for onlining
  142. Returns:
  143. ERROR_SUCCESS if successful.
  144. Win32 error code on failure.
  145. --*/
  146. {
  147. PFM_GROUP group;
  148. DWORD status = ERROR_SUCCESS;
  149. int i;
  150. int iQuoGroup=-1;
  151. //
  152. // see if the quorum group is present in the list.
  153. //
  154. for ( i = 0; (DWORD)i < GroupEnum->EntryCount; i++ )
  155. {
  156. if (NmGetNodeId(NmLocalNode) !=
  157. NmGetNodeId(gpQuoResource->Group->OwnerNode)) {
  158. continue;
  159. }
  160. if (!lstrcmpW(OmObjectId(gpQuoResource->Group),
  161. GroupEnum->Entry[i].Id))
  162. {
  163. iQuoGroup = i;
  164. break;
  165. }
  166. }
  167. //if quorum group was found, bring it online first. It would normally
  168. //be first in the list.
  169. //the quorum group online must return success, or invalid state
  170. //because of the online pending quorum resource.
  171. //if the quorum resource needs to be brought online, it must
  172. //be brought into online or online pending state. This is
  173. // not required in fix quorum mode.
  174. if (iQuoGroup != -1)
  175. {
  176. ClRtlLogPrint(LOG_NOISE,
  177. "[FM] FmpOnlineGroupList: bring quorum group online\n");
  178. status = FmpOnlineGroupFromList(GroupEnum, iQuoGroup, bPrepareQuoForOnline);
  179. if ( status != ERROR_SUCCESS && status != ERROR_IO_PENDING)
  180. {
  181. ClRtlLogPrint(LOG_NOISE,
  182. "[FM] FmpOnlineGroupFromList: quorum online returned %1!u!.\n",
  183. status );
  184. CL_LOGFAILURE(status);
  185. }
  186. }
  187. // bring the non-quorum groups online
  188. for ( i = 0; (DWORD)i < GroupEnum->EntryCount; i++ )
  189. {
  190. //quorum resource should be online now
  191. if (i != iQuoGroup)
  192. FmpOnlineGroupFromList(GroupEnum, i, bPrepareQuoForOnline);
  193. }
  194. return(status);
  195. } // FmpOnlineGroupList
  196. DWORD FmpOnlineGroupFromList(
  197. IN PGROUP_ENUM GroupEnum,
  198. IN DWORD Index,
  199. IN BOOL bPrepareQuoForOnline
  200. )
  201. {
  202. PFM_GROUP group;
  203. DWORD status=ERROR_SUCCESS; //assume success
  204. PLIST_ENTRY listEntry;
  205. PFM_RESOURCE resource;
  206. group = OmReferenceObjectById( ObjectTypeGroup,
  207. GroupEnum->Entry[Index].Id );
  208. //
  209. // If we fail to find a group, then just continue.
  210. //
  211. if ( group == NULL ) {
  212. status = ERROR_GROUP_NOT_FOUND;
  213. return(status);
  214. }
  215. FmpAcquireLocalGroupLock( group );
  216. if (group->OwnerNode != NmLocalNode) {
  217. FmpReleaseLocalGroupLock( group );
  218. OmDereferenceObject(group);
  219. return (ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  220. }
  221. ClRtlLogPrint(LOG_NOISE,
  222. "[FM] FmpOnlineGroupFromList: Previous group state for %1!ws! is %2!u!\r\n",
  223. OmObjectId(group), GroupEnum->Entry[Index].State);
  224. //
  225. // First make sure the group has completed initialization.
  226. //
  227. FmpCompleteInitGroup( group );
  228. //
  229. // First check if the Group failed to initialize. If so,
  230. // then attempt a failover immediately.
  231. //
  232. if ( GroupEnum->Entry[Index].State == ClusterGroupPartialOnline ) {
  233. GroupEnum->Entry[Index].State = ClusterGroupOnline;
  234. }
  235. if (!bPrepareQuoForOnline)
  236. {
  237. //
  238. // Normalize the state of each resource within the group.
  239. // except the quorum resource - this is because at initialization
  240. // we dont want to touch the quorum resource
  241. //
  242. for ( listEntry = group->Contains.Flink;
  243. listEntry != &(group->Contains);
  244. listEntry = listEntry->Flink ) {
  245. resource = CONTAINING_RECORD(listEntry, FM_RESOURCE, ContainsLinkage);
  246. if ( !resource->QuorumResource ) {
  247. // don't touch the quorum resource
  248. switch ( resource->State ) {
  249. // all active resources should be brought online.
  250. case ClusterResourceOnlinePending:
  251. case ClusterResourceOfflinePending:
  252. case ClusterResourceOnline:
  253. resource->State = ClusterResourceOffline;
  254. break;
  255. default:
  256. // otherwise do nothing
  257. break;
  258. }
  259. }
  260. }
  261. }
  262. FmpSignalGroupWaiters( group );
  263. if ( group->InitFailed ) {
  264. //
  265. // Bring the Group online... and then fail it!
  266. //
  267. ClRtlLogPrint(LOG_NOISE,
  268. "[FM] FmpOnlineGroupFromList: group->InitFailed is true for %1!ws!\n",
  269. OmObjectId(group));
  270. status = FmpOnlineGroup( group, FALSE );
  271. ClusterEvent( CLUSTER_EVENT_GROUP_FAILED, group );
  272. } else if ((group->PersistentState == ClusterGroupOnline) ||
  273. (GroupEnum->Entry[Index].State == ClusterGroupOnline) ||
  274. FmpIsAnyResourcePersistentStateOnline( group ) ) {
  275. //
  276. // Chittur Subbaraman (chitturs) - 01/07/2001
  277. //
  278. // Now bring the Group online if that is it's current state or if any one of the
  279. // resources in the group has an online persistent state. The third check is
  280. // required since it is possible for a group to have a persistent state of ClusterGroupOffline,
  281. // a state of ClusterGroupOffline and yet one or more resources in the group has a persistent
  282. // state of ClusterResourceOnline. This happens for a group in which the client never ever
  283. // calls OnlineGroup but calls OnlineResource for one or more resources in the group and you
  284. // reached this call either at the cluster service startup time or as a part of node down
  285. // processing when the source node died just after the group became ClusterGroupOffline
  286. // and before the destination node brought the appropriate resources within the group online.
  287. // In such a case, we still want to bring each resource that has a persistent state of
  288. // ClusterResourceOnline to online state. Note that it is tricky to muck with the group
  289. // persistent state in an OnlineResource call due to atomicity issues (we really need a
  290. // transaction to update both group and resource persistent states in one shot) and also
  291. // due to the fuzzy definition of group persistent state when the group has some resources
  292. // online and some offline.
  293. //
  294. ClRtlLogPrint(LOG_NOISE,
  295. "[FM] FmpOnlineGroupFromList: trying to bring group %1!ws! online\n",
  296. OmObjectId(group));
  297. status = FmpOnlineGroup( group, FALSE );
  298. if (status == ERROR_QUORUM_RESOURCE_ONLINE_FAILED)
  299. {
  300. PRESOURCE_ENUM pResourceEnum;
  301. // This fn is either called at startup or during
  302. // a node down event on claiming a group - so we must
  303. // try our darn best to bring resources
  304. // online after a quorum resource failure
  305. // With quorum resource failure the failure policy is
  306. // not invoked for resources so something must try to bring
  307. // these resources online. This is why we are adding this
  308. // here
  309. //
  310. // Get the list of resources in the group and their states.
  311. //
  312. status = FmpGetResourceList( &pResourceEnum, group );
  313. if ( status == ERROR_SUCCESS )
  314. {
  315. //submit a timer callback to try and bring these resources
  316. //online
  317. //the worker thread will clean up the resource list
  318. FmpSubmitRetryOnline(pResourceEnum);
  319. }
  320. }
  321. }
  322. FmpReleaseLocalGroupLock( group );
  323. OmDereferenceObject( group );
  324. return(status);
  325. } // FmpOnlineGroupFromList
  326. DWORD
  327. FmpOnlineResourceFromList(
  328. IN PRESOURCE_ENUM ResourceEnum
  329. )
  330. /*++
  331. Routine Description:
  332. Brings online all resources in the Enum list.
  333. Arguments:
  334. ResourceEnum - The list of resources to bring online.
  335. Comments : This function is called from the worker thread. We
  336. dont assume that the resource hasnt changed groups since the
  337. work item was posted. The local resource lock is acquired and
  338. released for each resource.
  339. Returns:
  340. ERROR_SUCCESS if successful.
  341. Win32 error code on failure.
  342. --*/
  343. {
  344. PFM_RESOURCE resource;
  345. DWORD status;
  346. DWORD returnStatus = ERROR_SUCCESS;
  347. DWORD i;
  348. if ( !FmpFMOnline ||
  349. FmpShutdown ) {
  350. return(ERROR_INVALID_STATE);
  351. }
  352. // if the quorum resource is contained in here, bring it online first
  353. if (ResourceEnum->ContainsQuorum >= 0)
  354. {
  355. CL_ASSERT((DWORD)ResourceEnum->ContainsQuorum < ResourceEnum->EntryCount);
  356. resource = OmReferenceObjectById( ObjectTypeResource,
  357. ResourceEnum->Entry[ResourceEnum->ContainsQuorum].Id );
  358. // the resource should not vanish, we are holding the group lock after all
  359. CL_ASSERT(resource != NULL);
  360. //
  361. // If we fail to find a resource, then just continue
  362. //
  363. if ( resource != NULL ) {
  364. //acquire the local resource lock
  365. FmpAcquireLocalResourceLock(resource);
  366. ClRtlLogPrint(LOG_NOISE,
  367. "[FM] FmpOnlineResourceFromList: Previous quorum resource state for %1!ws! is %2!u!\r\n",
  368. OmObjectId(resource), ResourceEnum->Entry[ResourceEnum->ContainsQuorum].State);
  369. if ( (ResourceEnum->Entry[ResourceEnum->ContainsQuorum].State == ClusterResourceOnline) ||
  370. (ResourceEnum->Entry[ResourceEnum->ContainsQuorum].State == ClusterResourceFailed) ) {
  371. //
  372. // Now bring the resource online if that is it's current state.
  373. //
  374. ClRtlLogPrint(LOG_NOISE,
  375. "[FM] FmpOnlineResourceFromList: trying to bring quorum resource %1!ws! online, state %2!u!\n",
  376. OmObjectId(resource),
  377. resource->State);
  378. status = FmpOnlineResource( resource, FALSE );
  379. if ( status != ERROR_SUCCESS ) {
  380. returnStatus = status;
  381. }
  382. }
  383. OmDereferenceObject( resource );
  384. FmpReleaseLocalResourceLock(resource);
  385. }
  386. }
  387. // SS::: TODO what happens to the persistent state of the
  388. // other resources - is it handled correctly - note that this is
  389. // called on moving a group
  390. // Will the restart policy do the right thing in terms of bringing
  391. // them online
  392. // if the quorum resource has failed, dont bother trying
  393. // to bring the rest of the resourcess online
  394. if ((returnStatus != ERROR_SUCCESS) && (returnStatus != ERROR_IO_PENDING))
  395. {
  396. FmpSubmitRetryOnline(ResourceEnum);
  397. goto FnExit;
  398. }
  399. // bring online all of the other resources
  400. for ( i = 0; i < ResourceEnum->EntryCount; i++ ) {
  401. resource = OmReferenceObjectById( ObjectTypeResource,
  402. ResourceEnum->Entry[i].Id );
  403. //
  404. // If we fail to find a resource, then just continue.
  405. //
  406. if ( resource == NULL ) {
  407. status = ERROR_RESOURCE_NOT_FOUND;
  408. continue;
  409. }
  410. FmpAcquireLocalResourceLock(resource);
  411. //if the resource has been marked for delete, then dont let
  412. //it be brought online
  413. if (!IS_VALID_FM_RESOURCE(resource))
  414. {
  415. FmpReleaseLocalResourceLock( resource );
  416. OmDereferenceObject(resource);
  417. continue;
  418. }
  419. //quorum resource has already been handled
  420. if (resource->QuorumResource)
  421. {
  422. FmpReleaseLocalResourceLock( resource );
  423. OmDereferenceObject(resource);
  424. continue;
  425. }
  426. ClRtlLogPrint(LOG_NOISE,
  427. "[FM] FmpOnlineResourceFromList: Previous resource state for %1!ws! is %2!u!\r\n",
  428. OmObjectId(resource), ResourceEnum->Entry[i].State);
  429. if ( (ResourceEnum->Entry[i].State == ClusterResourceOnline) ||
  430. (ResourceEnum->Entry[i].State == ClusterResourceFailed) )
  431. {
  432. //
  433. // Now bring the resource online if that is it's current state.
  434. //
  435. ClRtlLogPrint(LOG_NOISE,
  436. "[FM] FmpOnlineResourceFromList: trying to bring resource %1!ws! online\n",
  437. OmObjectId(resource));
  438. status = FmpOnlineResource( resource, FALSE );
  439. if ( returnStatus == ERROR_SUCCESS )
  440. {
  441. returnStatus = status;
  442. }
  443. //if this resource didnt come online because the quorum resource
  444. //didnt come online, dont bother bringing the other resources online
  445. //just a waste of time
  446. if (status == ERROR_QUORUM_RESOURCE_ONLINE_FAILED)
  447. {
  448. //submit a timer callback to try and bring these resources
  449. //online
  450. FmpReleaseLocalResourceLock( resource );
  451. OmDereferenceObject( resource );
  452. FmpSubmitRetryOnline(ResourceEnum);
  453. break;
  454. }
  455. }
  456. FmpReleaseLocalResourceLock( resource );
  457. OmDereferenceObject( resource );
  458. }
  459. FnExit:
  460. ClRtlLogPrint(LOG_NOISE,
  461. "[FM] FmpOnlineResourceFromList: Exit, status=%1!u!\r\n",
  462. returnStatus);
  463. return(returnStatus);
  464. } // FmpOnlineResourceFromList
  465. BOOL
  466. FmpEqualGroupLists(
  467. IN PGROUP_ENUM Group1,
  468. IN PGROUP_ENUM Group2
  469. )
  470. /*++
  471. Routine Description:
  472. This routine verifies that two group lists are equal.
  473. Arguments:
  474. Group1 - The first group to compare.
  475. Group2 - The second group to compare.
  476. Returns:
  477. TRUE - if the two lists are equal.
  478. FALSE - otherwise.
  479. --*/
  480. {
  481. DWORD i;
  482. if ( (Group1 == NULL) ||
  483. (Group2 == NULL) ) {
  484. ClRtlLogPrint(LOG_NOISE,"[FM] One of the Group lists is NULL for equality check\n");
  485. return(FALSE);
  486. }
  487. if ( Group1->EntryCount != Group2->EntryCount ) {
  488. ClRtlLogPrint(LOG_NOISE,"[FM] Group entry counts not equal! Left: %1!u!, Right: %2!u!.\n",
  489. Group1->EntryCount, Group2->EntryCount);
  490. return(FALSE);
  491. }
  492. for ( i = 0; i < Group1->EntryCount; i++ ) {
  493. if ( lstrcmpiW(Group1->Entry[i].Id, Group2->Entry[i].Id) != 0 ) {
  494. ClRtlLogPrint(LOG_NOISE,"[FM] Group Lists do not have same names!\n");
  495. return(FALSE);
  496. }
  497. }
  498. return(TRUE);
  499. } // FmpEqualGroupLists
  500. BOOL
  501. FmpEnumGroups(
  502. IN OUT PGROUP_ENUM *Enum,
  503. IN PFM_GROUP_ENUM_DATA EnumData,
  504. IN PFM_GROUP Group,
  505. IN LPCWSTR Id
  506. )
  507. /*++
  508. Routine Description:
  509. Worker callback routine for the enumeration of Groups.
  510. This routine adds the specified Group to the list that is being
  511. generated.
  512. Arguments:
  513. Enum - The Group Enumeration list. Can be an output if a new list is
  514. allocated.
  515. EnumData - Supplies the current enumeration data structure.
  516. Group - The Group object being enumerated.
  517. Id - The Id of the Group object being enumerated.
  518. Returns:
  519. TRUE - to indicate that the enumeration should continue.
  520. Side Effects:
  521. Makes the quorum group first in the list.
  522. --*/
  523. {
  524. PGROUP_ENUM groupEnum;
  525. PGROUP_ENUM newEnum;
  526. DWORD newAllocated;
  527. DWORD index;
  528. LPWSTR newId;
  529. LPWSTR tmpId;
  530. DWORD status;
  531. PFM_RESOURCE quorumResource;
  532. //HACKHACK::
  533. //SS: Since this is invoked from within a gum call and
  534. // the owner node is changed only within a gum call
  535. // we wont acquire locks.
  536. // there is a window if the dead node is the source of a
  537. // move and if it does a move after it is declared dead by
  538. // other nodes, the target of move and the fmpassignownerstogroup
  539. // might both land up bringing the group online on two nodes
  540. // However, if we could be guaranteed virtual synchrony, then
  541. // the target of move wouldnt accept calls from a dead node and
  542. // we wont land up in this soup. Now, it is upto the xport layer
  543. // to provide this guarantee.
  544. // For now we acquire no locks
  545. //FmpAcquireLocalGroupLock( Group );
  546. if ((EnumData->OwnerNode != NULL) &&
  547. (EnumData->OwnerNode != Group->OwnerNode) &&
  548. (EnumData->OwnerNode != Group->pIntendedOwner)) {
  549. //
  550. // This group does not match the owner criteria
  551. //
  552. //FmpReleaseLocalGroupLock( Group );
  553. return(TRUE);
  554. }
  555. //FmpReleaseLocalGroupLock( Group );
  556. groupEnum = *Enum;
  557. if ( groupEnum->EntryCount >= EnumData->Allocated ) {
  558. //
  559. // Time to grow the GROUP_ENUM
  560. //
  561. newAllocated = EnumData->Allocated + ENUM_GROW_SIZE;
  562. newEnum = LocalAlloc(LMEM_FIXED, GROUP_SIZE(newAllocated));
  563. if ( newEnum == NULL ) {
  564. return(FALSE);
  565. }
  566. CopyMemory(newEnum, groupEnum, GROUP_SIZE(EnumData->Allocated));
  567. EnumData->Allocated = newAllocated;
  568. *Enum = newEnum;
  569. LocalFree(groupEnum);
  570. groupEnum = newEnum;
  571. }
  572. //
  573. // Initialize new entry
  574. //
  575. newId = LocalAlloc(LMEM_FIXED, (lstrlenW(Id)+1) * sizeof(WCHAR));
  576. if ( newId == NULL ) {
  577. CsInconsistencyHalt(ERROR_NOT_ENOUGH_MEMORY);
  578. }
  579. lstrcpyW(newId, Id);
  580. //
  581. // Find the quorum resource, and see if it is this group.
  582. //
  583. status = FmFindQuorumResource( &quorumResource );
  584. if ( status != ERROR_SUCCESS ) {
  585. CsInconsistencyHalt(status);
  586. }
  587. groupEnum->Entry[groupEnum->EntryCount].Id = newId;
  588. if ( quorumResource->Group == Group ) {
  589. // found the quorum resource group, put it first in the list.
  590. tmpId = groupEnum->Entry[0].Id;
  591. groupEnum->Entry[0].Id = newId;
  592. groupEnum->Entry[groupEnum->EntryCount].Id = tmpId;
  593. EnumData->QuorumGroup = TRUE;
  594. }
  595. ++groupEnum->EntryCount;
  596. OmDereferenceObject( quorumResource );
  597. return(TRUE);
  598. } // FmpEnumGroups
  599. #if 0
  600. int
  601. _cdecl
  602. SortCompare(
  603. IN const PVOID Elem1,
  604. IN const PVOID Elem2
  605. )
  606. {
  607. PGROUP_ENUM_ENTRY El1 = (PGROUP_ENUM_ENTRY)Elem1;
  608. PGROUP_ENUM_ENTRY El2 = (PGROUP_ENUM_ENTRY)Elem2;
  609. return(lstrcmpiW( El1->Id, El2->Id ));
  610. } // SortCompare
  611. #endif
  612. DWORD
  613. FmpClaimAllGroups(
  614. PGROUP_ENUM MyGroups
  615. )
  616. /*++
  617. Routine Description:
  618. Takes ownership of all the groups defined in the cluster. This
  619. is used when a new cluster is being formed.
  620. Arguments:
  621. None.
  622. Return Value:
  623. ERROR_SUCCESS if successful
  624. Win32 errorcode otherwise
  625. --*/
  626. {
  627. //
  628. // Bring online any Group that needs to be online.
  629. //
  630. FmpOnlineGroupList( MyGroups, FALSE );
  631. return(ERROR_SUCCESS);
  632. }
  633. VOID
  634. FmpDeleteEnum(
  635. IN PGROUP_ENUM Enum
  636. )
  637. /*++
  638. Routine Description:
  639. This routine deletes an GROUP_ENUM and associated name strings.
  640. Arguments:
  641. Enum - The GROUP_ENUM to delete. This pointer can be NULL.
  642. Returns:
  643. None.
  644. Notes:
  645. This routine will take a NULL input pointer and just return.
  646. --*/
  647. {
  648. PGROUP_ENUM_ENTRY enumEntry;
  649. DWORD i;
  650. if ( Enum == NULL ) {
  651. return;
  652. }
  653. for ( i = 0; i < Enum->EntryCount; i++ ) {
  654. enumEntry = &Enum->Entry[i];
  655. LocalFree(enumEntry->Id);
  656. }
  657. LocalFree(Enum);
  658. return;
  659. } // FmpDeleteEnum
  660. /****
  661. @func VOID | FmpPrepareGroupForOnline| This routine sets the Group
  662. up for onlining it on this node post a failure of a node
  663. or at initialization.
  664. @parm IN PFM_GROUP | pGroup| A pointer to the group.
  665. @comm The group lock must be held. Except when called at bootstrapping
  666. by FmBringQuorumOnline.
  667. MUST BE CALLED ONLY BY THE OWNER NODE OF THE GROUP.
  668. @rdesc returns ERROR_SUCCESS if succesful else w32 error code.
  669. MUST BE CALLED ONLY BY THE OWNER NODE OF THE GROUP.
  670. ****/
  671. VOID FmpPrepareGroupForOnline(
  672. IN PFM_GROUP pGroup
  673. )
  674. {
  675. PLIST_ENTRY pListEntry;
  676. PFM_RESOURCE pResource;
  677. pGroup->State = ClusterGroupOffline;
  678. ++pGroup->StateSequence;
  679. //
  680. // Mark offline all of the resources contained within this group.
  681. //
  682. for (pListEntry = pGroup->Contains.Flink;
  683. pListEntry != &pGroup->Contains;
  684. pListEntry = pListEntry->Flink)
  685. {
  686. pResource = CONTAINING_RECORD(pListEntry, FM_RESOURCE, ContainsLinkage);
  687. pResource->State = ClusterResourceOffline;
  688. ++pResource->StateSequence;
  689. }
  690. }
  691. /****
  692. @func DWORD | FmpSetGroupEnumOwner| This routine sets the Group
  693. owner for all Groups in the list.
  694. @parm IN PGROUP_ENUM | pGroupEnum| The list of Groups.
  695. @parm IN PNM_NODE | pDefaultOwnerNode | A pointer to the default owner
  696. node.
  697. @parm IN PNM_NODE | pDeadNode | A pointed to the node that died. If
  698. this routine is being called other wise, this is set to NULL.
  699. @parm IN BOOL | bQuorumGroup | set to TRUE if the quorum group is
  700. on the list of groups.
  701. @parm IN PFM_GROUP_NODE_LIST | pGroupNodeList | The randomized suggested preferred
  702. owner for all groups.
  703. @comm If the group was in the process of moving and had an intended
  704. owner and the intended owner is not dead, the intended owner is
  705. allowed to take care of the group. Else, the first node on the
  706. preferred list that is up is chosen as the owner. If no such
  707. node exits, then the ownership is assigned to the default owner
  708. provided. This routine is called by the forming node at
  709. initialization to claimownership of all groups and by the gum
  710. update procedure FmpUpdateAssignOwnerToGroups.
  711. @rdesc returns ERROR_SUCCESS if succesful else w32 error code.
  712. ****/
  713. DWORD
  714. FmpSetGroupEnumOwner(
  715. IN PGROUP_ENUM pGroupEnum,
  716. IN PNM_NODE pDefaultOwnerNode,
  717. IN PNM_NODE pDeadNode,
  718. IN BOOL bQuorumGroup,
  719. IN PFM_GROUP_NODE_LIST pGroupNodeList
  720. )
  721. {
  722. PFM_GROUP pGroup;
  723. DWORD i;
  724. DWORD dwStatus = ERROR_SUCCESS;
  725. PNM_NODE pOwnerNode;
  726. for ( i = 0; i < pGroupEnum->EntryCount; i++ )
  727. {
  728. pGroup = OmReferenceObjectById( ObjectTypeGroup,
  729. pGroupEnum->Entry[i].Id );
  730. if ( pGroup == NULL )
  731. {
  732. ClRtlLogPrint(LOG_NOISE,
  733. "[FM] FmpSetGroupEnumOwner: Group %1!ws! not found\n",
  734. pGroupEnum->Entry[i].Id);
  735. dwStatus = ERROR_GROUP_NOT_FOUND;
  736. goto FnExit;
  737. }
  738. //
  739. // SS: HACKHACK : cant get the group lock within a gum update
  740. // FmpAcquireLocalGroupLock( pGroup );
  741. //
  742. // SS: In case of a node death, see if there was an intended owner
  743. // if the intended owner is set and if the intended owner is
  744. // not the one that died then we use the normal procedure
  745. // else we let the intended owner take care of the group.
  746. //
  747. // Chittur Subbaraman (chitturs) - 7/26/99
  748. //
  749. // Condition 2: Means the group was being moved and FmpTakeGroupRequest
  750. // has not taken 100% responsibility for the group.
  751. //
  752. // Condition 3: Means the source node crashed and NOT the destination node.
  753. //
  754. // Added condition 4 to cover the case in which the source node of
  755. // the move crashed AFTER setting the intended owner as the
  756. // destination node and BEFORE the FmpTakeGroupRequest has set
  757. // the group ownership to the destination node.
  758. //
  759. // If the group's owner node and the group's intended owner node are
  760. // not the same, then let this GUM handler take care of assigning
  761. // the group ownership. This means that the FmpTakeGroupRequest
  762. // has not yet set the ownership for the group to the destination
  763. // node of the move. Now, once this GUM handler sets the
  764. // ownership for the group and then resets the intended owner to
  765. // NULL, FmpTakeGroupRequest which could follow behind this GUM handler
  766. // will not succeed in setting the ownership to the local node and that
  767. // will just return doing nothing. This is TRUE only for an NT5 cluster.
  768. // For a mixed-mode cluster, all bets are off.
  769. //
  770. if ( (pDeadNode) &&
  771. (pGroup->pIntendedOwner != NULL) &&
  772. (pGroup->pIntendedOwner != pDeadNode) &&
  773. (pGroup->OwnerNode == pGroup->pIntendedOwner) )
  774. {
  775. //
  776. // Chittur Subbaraman (chitturs) - 7/27/99
  777. //
  778. // Looks like this code inside "if" will never ever be
  779. // executed. Keeping it so as to make the changes minimal.
  780. //
  781. ClRtlLogPrint(LOG_NOISE,
  782. "[FM] FmpSetGroupEnumOwner: Group %1!ws! will be handled by node %2!ws!\n",
  783. OmObjectId(pGroup), OmObjectId(pGroup->pIntendedOwner));
  784. continue;
  785. }
  786. //
  787. // Find first preferred node that is UP, if we can't find any use
  788. // default OwnerNode
  789. //
  790. //
  791. // If this is the quorum group, then use the node that was selected
  792. // by the MM layer. The quorum group is the first entry in the list
  793. // and the Boolean QuorumGroup must be TRUE!
  794. //
  795. if ( (i == 0) && bQuorumGroup )
  796. {
  797. DWORD dwOwnerNodeId;
  798. //for the quorum group find the node that had last
  799. //arbitrated for it.
  800. //We do this by asking MM about it.
  801. //If there was no arbitration during the last regroup
  802. //but there was one in the one before that one, the
  803. //node that arbitrated is returned.
  804. //This node should be able to online the group.
  805. //We use MMApproxArbitrationWinner instead if
  806. // MMGetArbitrationWinner() since multiple-regroups
  807. // might occur before the FM handles the node down
  808. // event for this node.
  809. MMApproxArbitrationWinner( &dwOwnerNodeId );
  810. ClRtlLogPrint(LOG_NOISE,
  811. "[FM] FmpSetGroupEnumOwner:: MM suggests node %1!u! for quorum owner\r\n",
  812. dwOwnerNodeId);
  813. if ( dwOwnerNodeId != MM_INVALID_NODE )
  814. {
  815. pOwnerNode = NmReferenceNodeById( dwOwnerNodeId );
  816. }
  817. else
  818. {
  819. ClRtlLogPrint(LOG_CRITICAL,
  820. "[FM] FmpSetGroupEnumOwner:: MM returned MM_INVALID_NODE, chose the default target\r\n");
  821. //else just use the default target
  822. pOwnerNode = pDefaultOwnerNode;
  823. }
  824. }
  825. else
  826. {
  827. pOwnerNode = FmpGetPreferredNode(pGroup);
  828. if ( pOwnerNode == NULL )
  829. {
  830. pOwnerNode = pDefaultOwnerNode;
  831. }
  832. //
  833. // If the caller (GUM) has supplied a randomized preferred owner of the group, then
  834. // see if it can be used.
  835. //
  836. if ( pGroupNodeList != NULL )
  837. {
  838. pOwnerNode = FmpParseGroupNodeListForPreferredOwner( pGroup,
  839. pGroupNodeList,
  840. pOwnerNode );
  841. }
  842. }
  843. if ( pGroup->OwnerNode != NULL )
  844. {
  845. OmDereferenceObject( pGroup->OwnerNode );
  846. }
  847. OmReferenceObject( pOwnerNode );
  848. pGroup->OwnerNode = pOwnerNode;
  849. ClRtlLogPrint(LOG_NOISE,
  850. "[FM] FmpSetGroupEnumOwner: Group's %1!ws! new owner is node %2!ws!\n",
  851. OmObjectId(pGroup), OmObjectId(pOwnerNode));
  852. //FmpReleaseLocalGroupLock( pGroup );
  853. OmDereferenceObject(pGroup);
  854. }
  855. FnExit:
  856. return(dwStatus);
  857. } // FmpSetGroupEnumOwner
  858. DWORD
  859. FmpAssignOwnersToGroups(
  860. IN PNM_NODE pDeadNode,
  861. IN PFM_GROUP pGroup,
  862. IN PFM_GROUP_NODE_LIST pGroupNodeList
  863. )
  864. /*++
  865. Routine Description:
  866. Takes ownership of all the groups defined in the cluster that
  867. are owned by another node. This is used when a node fails.
  868. The current algorithm is very dumb and simple. Node with the
  869. lowest ID gets all the groups.
  870. Arguments:
  871. pDeadNode - Supplies the node that all the groups should be taken
  872. from.
  873. pGroup - Supplies the group which alone is to be claimed.
  874. pGroupNodeList - The randomized suggested preferred owner for all groups.
  875. Return Value:
  876. ERROR_SUCCESS if successful
  877. Win32 errorcode otherwise
  878. --*/
  879. {
  880. DWORD i;
  881. DWORD dwStatus;
  882. PGROUP_ENUM pNodeGroups = NULL;
  883. PNM_NODE pDefaultTarget = NULL;
  884. PNM_NODE pPausedTarget = NULL;
  885. BOOL bQuorumGroup;
  886. //
  887. // Acquire the global group lock
  888. //
  889. FmpAcquireGroupLock();
  890. //
  891. // Check if groups are initialized
  892. //
  893. if ( !FmpFMGroupsInited )
  894. {
  895. dwStatus = ERROR_SUCCESS;
  896. goto FnExit;
  897. }
  898. //
  899. // Find and sort all known groups
  900. //
  901. if ( pGroup == NULL )
  902. {
  903. dwStatus = FmpEnumSortGroups(&pNodeGroups, pDeadNode, &bQuorumGroup);
  904. } else
  905. {
  906. //
  907. // Chittur Subbaraman (chitturs) - 6/7/99
  908. //
  909. // This means you got here due to an RPC exception raised in
  910. // FmpTakeGroupRequest. So, see where this sole group goes.
  911. //
  912. dwStatus = FmpGetGroupInNodeGroupList(&pNodeGroups, pGroup, pDeadNode, &bQuorumGroup);
  913. }
  914. if (dwStatus != ERROR_SUCCESS)
  915. {
  916. CL_ASSERT(pNodeGroups == NULL);
  917. goto FnExit;
  918. }
  919. CL_ASSERT(pNodeGroups != NULL);
  920. //if no nodes were owned by this node, just return
  921. if (pNodeGroups->EntryCount == 0)
  922. {
  923. FmpDeleteEnum(pNodeGroups);
  924. goto FnExit;
  925. }
  926. //
  927. // Find the state of the Groups.
  928. //
  929. FmpGetGroupListState( pNodeGroups );
  930. //
  931. // Find the active node with the lowest ID to be the default
  932. // owner of these groups.
  933. //
  934. // If we can't find an active node then select the lowest node id for
  935. // a node that is paused.
  936. //
  937. CL_ASSERT(NmMaxNodeId != ClusterInvalidNodeId);
  938. CL_ASSERT(Session != NULL);
  939. for (i=ClusterMinNodeId; i<=NmMaxNodeId; i++)
  940. {
  941. pDefaultTarget = NmReferenceNodeById(i);
  942. if ( pDefaultTarget != NULL )
  943. {
  944. //if this node is up, there is no need to use a paused target
  945. if ( NmGetNodeState(pDefaultTarget) == ClusterNodeUp )
  946. {
  947. if ( pPausedTarget )
  948. {
  949. OmDereferenceObject(pPausedTarget);
  950. pPausedTarget = NULL;
  951. }
  952. //found a node, leave this loop
  953. break;
  954. }
  955. //node is not up, check if it paused
  956. //if is is paused and no other paused node has been found
  957. //set this one to be the lowest paused node
  958. if ( !pPausedTarget &&
  959. (NmGetNodeState(pDefaultTarget) == ClusterNodePaused) )
  960. {
  961. pPausedTarget = pDefaultTarget;
  962. }
  963. else
  964. {
  965. OmDereferenceObject(pDefaultTarget);
  966. }
  967. pDefaultTarget = NULL;
  968. }
  969. }
  970. if ( (pDefaultTarget == NULL) && (pPausedTarget == NULL) ) {
  971. //
  972. // There are no online/paused nodes, this node must be paused,
  973. // so don't do anything.
  974. //
  975. ClRtlLogPrint(LOG_CRITICAL,
  976. "[FM] FmpAssignOwnersToGroups - no online/paused nodes remaining\n");
  977. //SS: then what are we doing here
  978. FmpDeleteEnum(pNodeGroups);
  979. goto FnExit;
  980. }
  981. //if no node is up, use the lowest paused node as the default owner for
  982. //the groups
  983. if ( pDefaultTarget == NULL )
  984. {
  985. pDefaultTarget = pPausedTarget;
  986. }
  987. ClRtlLogPrint(LOG_NOISE,
  988. "[FM] FmpAssignOwnersToGroups - DefaultTarget is %1!ws!\n",
  989. OmObjectId(pDefaultTarget));
  990. //
  991. // Chittur Subbaraman (chitturs) - 7/20/99
  992. //
  993. // Prepare the entire group list for subsequent online. You have
  994. // to do this here to have a consistent resource state view
  995. // among different nodes in the cluster since this is the GUM
  996. // handler. Also, the DM node down handler which follows this
  997. // GUM handler may think that the quorum resource is owned by
  998. // this node and its state is online while it has not been
  999. // brought online on this node. Note also the order of this
  1000. // call and the call to set the group ownership. THIS ORDER
  1001. // MUST BE FOLLOWED since we don't hold any groups lock here
  1002. // (since we are paranoid about deadlocks) and we don't want
  1003. // the FmCheckQuorumState function called as a part of the
  1004. // DM node down handler to think that the group is owned by
  1005. // this node and is also online on this node.
  1006. //
  1007. FmpPrepareGroupEnumForOnline( pNodeGroups );
  1008. //
  1009. // Set the Group owner.
  1010. //
  1011. FmpSetGroupEnumOwner( pNodeGroups,
  1012. pDefaultTarget,
  1013. pDeadNode,
  1014. bQuorumGroup,
  1015. pGroupNodeList );
  1016. //
  1017. // Chittur Subbaraman (chitturs) - 5/26/99
  1018. //
  1019. // Clear the intended owner fields of all the groups. This is done
  1020. // since there is no guarantee that FmpTakeGroupRequest will do this.
  1021. //
  1022. FmpResetGroupIntendedOwner( pNodeGroups );
  1023. //
  1024. // Chittur Subbaraman (chitturs) - 7/14/99
  1025. //
  1026. // Handle the online of group list containing the quorum resource with
  1027. // a separate thread and let the worker thread handle group lists
  1028. // not containing the quorum resource. This is necessary since it is
  1029. // possible that this node can take ownership at roughly the same
  1030. // time of a quorum group and a non-quorum group each resident
  1031. // in a different node due to back-to-back node crashes. In such a
  1032. // case, we can't order these groups for online globally with the
  1033. // quorum group first in the list. So, we don't want the worker thread
  1034. // to be "stuck" in FmpRmOnlineResource for the non-quorum group's
  1035. // resource waiting for the quorum group to be brought online since
  1036. // the quorum group online work item is queued behind the non-quorum
  1037. // group online work item.
  1038. //
  1039. if ( bQuorumGroup )
  1040. {
  1041. HANDLE hThread = NULL;
  1042. DWORD dwThreadId;
  1043. ClRtlLogPrint(LOG_NOISE,
  1044. "[FM] FmpAssignOwnersToGroups - Create thread to handle group list containing quorum group....\n"
  1045. );
  1046. hThread = CreateThread( NULL,
  1047. 0,
  1048. FmpBringQuorumGroupListOnline,
  1049. pNodeGroups,
  1050. 0,
  1051. &dwThreadId );
  1052. if ( hThread == NULL )
  1053. {
  1054. CL_UNEXPECTED_ERROR( GetLastError() );
  1055. OmDereferenceObject( pDefaultTarget );
  1056. goto FnExit;
  1057. }
  1058. CloseHandle( hThread );
  1059. } else
  1060. {
  1061. ClRtlLogPrint(LOG_NOISE,
  1062. "[FM] FmpAssignOwnersToGroups - Post work item to worker thread to handle group list containing non-quorum groups....\n"
  1063. );
  1064. FmpPostWorkItem(FM_EVENT_INTERNAL_ONLINE_GROUPLIST, pNodeGroups, 0);
  1065. }
  1066. OmDereferenceObject(pDefaultTarget);
  1067. FnExit:
  1068. //
  1069. // Release the global group lock
  1070. //
  1071. FmpReleaseGroupLock();
  1072. return(ERROR_SUCCESS);
  1073. }
  1074. /****
  1075. @func DWORD | FmpResetGroupIntendedOwner| This routine resets the
  1076. intended owner for all groups in the list.
  1077. @parm IN PGROUP_ENUM | pGroupEnum| The list of Groups.
  1078. @rdesc Returns ERROR_SUCCESS.
  1079. ****/
  1080. VOID
  1081. FmpResetGroupIntendedOwner(
  1082. IN PGROUP_ENUM pGroupEnum
  1083. )
  1084. {
  1085. DWORD i;
  1086. PFM_GROUP pGroup;
  1087. ClRtlLogPrint(LOG_NOISE,
  1088. "[FM] FmpResetGroupIntendedOwner: Entry.\n");
  1089. for ( i = 0; i < pGroupEnum->EntryCount; i++ )
  1090. {
  1091. pGroup = OmReferenceObjectById( ObjectTypeGroup,
  1092. pGroupEnum->Entry[i].Id );
  1093. if ( pGroup == NULL )
  1094. {
  1095. ClRtlLogPrint(LOG_UNUSUAL,
  1096. "[FM] FmpResetGroupIntendedOwner: Group %1!ws! not found\n");
  1097. continue;
  1098. }
  1099. pGroup->pIntendedOwner = NULL;
  1100. OmDereferenceObject( pGroup );
  1101. }
  1102. ClRtlLogPrint(LOG_NOISE,
  1103. "[FM] FmpResetGroupIntendedOwner: Exit.\n");
  1104. }
  1105. /****
  1106. @func DWORD | FmpGetGroupInNodeGroupList | This routine checks whether
  1107. the supplied group is to be included in the list to be brought
  1108. online.
  1109. @parm OUT PGROUP_ENUM | pReturnEnum | The group list possibly
  1110. containing the supplied group.
  1111. @parm IN PFM_GROUP | pGroup | The group which is to be brought online
  1112. possibly.
  1113. @parm IN PNM_NODE | pDeadNode | The node which is dead.
  1114. @parm OUT PBOOL | pbQuorumGroup | Does the group list contain the quorum group ?
  1115. @rdesc Returns ERROR_SUCCESS on success OR a Win32 error code on a
  1116. failure.
  1117. ****/
  1118. DWORD
  1119. FmpGetGroupInNodeGroupList(
  1120. OUT PGROUP_ENUM *pReturnEnum,
  1121. IN PFM_GROUP pGroup,
  1122. IN PNM_NODE pDeadNode,
  1123. OUT PBOOL pbQuorumGroup
  1124. )
  1125. {
  1126. DWORD dwStatus = ERROR_SUCCESS;
  1127. PGROUP_ENUM pGroupEnum = NULL;
  1128. PFM_RESOURCE pQuoResource = NULL;
  1129. //
  1130. // Chittur Subbaraman (chitturs) - 6/7/99
  1131. //
  1132. // This function is only called if an RPC exception is raised in
  1133. // FmpTakeGroupRequest. This function will check to see whether this
  1134. // group is to be brought online in this node.
  1135. //
  1136. ClRtlLogPrint(LOG_NOISE,
  1137. "[FM] FmpGetGroupInNodeGroupList: Entry for group <%1!ws!>\n",
  1138. OmObjectId(pGroup));
  1139. *pbQuorumGroup = FALSE;
  1140. pGroupEnum = LocalAlloc( LPTR,
  1141. sizeof( GROUP_ENUM_ENTRY ) + sizeof( GROUP_ENUM ) );
  1142. if ( pGroupEnum == NULL )
  1143. {
  1144. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  1145. goto FnExit;
  1146. }
  1147. pGroupEnum->Entry[0].Id = pGroupEnum->Entry[1].Id = NULL;
  1148. pGroupEnum->EntryCount = 0;
  1149. //
  1150. // Check whether this group was in the dead node or was in the
  1151. // process of moving to the dead node.
  1152. //
  1153. if( ( pDeadNode != NULL ) &&
  1154. ( pDeadNode != pGroup->OwnerNode ) &&
  1155. ( pDeadNode != pGroup->pIntendedOwner ) )
  1156. {
  1157. //
  1158. // This group does not match the owner criteria
  1159. //
  1160. dwStatus = ERROR_GROUP_NOT_AVAILABLE;
  1161. goto FnExit;
  1162. }
  1163. dwStatus = FmFindQuorumResource( &pQuoResource );
  1164. if ( dwStatus != ERROR_SUCCESS )
  1165. {
  1166. ClRtlLogPrint(LOG_CRITICAL,
  1167. "[FM] FmpGetGroupInNodeGroupList: Cannot find quorum resource, Status = %1!u!\n",
  1168. dwStatus);
  1169. CsInconsistencyHalt( dwStatus );
  1170. }
  1171. //
  1172. // Handle the quorum group first, if necessary. This is needed since
  1173. // otherwise you may not be able to bring the other group online.
  1174. //
  1175. if( ( pGroup != pQuoResource->Group ) &&
  1176. ( ( pDeadNode == NULL ) ||
  1177. ( pDeadNode == pQuoResource->Group->OwnerNode ) ||
  1178. ( pDeadNode == pQuoResource->Group->pIntendedOwner ) ) )
  1179. {
  1180. //
  1181. // The quorum group matches the owner criteria. Include it first
  1182. // in the list.
  1183. //
  1184. pGroupEnum->Entry[pGroupEnum->EntryCount].Id =
  1185. LocalAlloc( LMEM_FIXED, ( lstrlenW(OmObjectId(pQuoResource->Group)) + 1 ) * sizeof( WCHAR ) );
  1186. if ( pGroupEnum->Entry[pGroupEnum->EntryCount].Id == NULL )
  1187. {
  1188. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  1189. goto FnExit;
  1190. }
  1191. ClRtlLogPrint(LOG_NOISE,
  1192. "[FM] FmpGetGroupInNodeGroupList: Dead node contains quorum group also, including it...\n");
  1193. lstrcpyW( pGroupEnum->Entry[pGroupEnum->EntryCount].Id, OmObjectId( pQuoResource->Group ) );
  1194. pGroupEnum->EntryCount++;
  1195. *pbQuorumGroup = TRUE;
  1196. } else if ( pGroup == pQuoResource->Group )
  1197. {
  1198. *pbQuorumGroup = TRUE;
  1199. }
  1200. pGroupEnum->Entry[pGroupEnum->EntryCount].Id =
  1201. LocalAlloc( LMEM_FIXED, ( lstrlenW(OmObjectId(pGroup)) + 1 ) * sizeof( WCHAR ) );
  1202. if ( pGroupEnum->Entry[pGroupEnum->EntryCount].Id == NULL )
  1203. {
  1204. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  1205. goto FnExit;
  1206. }
  1207. lstrcpyW( pGroupEnum->Entry[pGroupEnum->EntryCount].Id, OmObjectId( pGroup ) );
  1208. pGroupEnum->EntryCount++;
  1209. *pReturnEnum = pGroupEnum;
  1210. OmDereferenceObject( pQuoResource );
  1211. ClRtlLogPrint(LOG_NOISE,
  1212. "[FM] FmpGetGroupInNodeGroupList: Exit with SUCCESS.\n");
  1213. return( ERROR_SUCCESS );
  1214. FnExit:
  1215. if ( pGroupEnum != NULL )
  1216. {
  1217. FmpDeleteEnum( pGroupEnum );
  1218. }
  1219. if ( pQuoResource != NULL )
  1220. {
  1221. OmDereferenceObject( pQuoResource );
  1222. }
  1223. *pReturnEnum = NULL;
  1224. ClRtlLogPrint(LOG_NOISE,
  1225. "[FM] FmpGetGroupInNodeGroupList: Exit, Status = %1!u!\n",
  1226. dwStatus);
  1227. return( dwStatus );
  1228. }
  1229. /****
  1230. @func VOID | FmpPrepareGroupEnumForOnline | Prepare a list of
  1231. groups for online.
  1232. @parm IN PGROUP_ENUM | pGroupEnum | The group list.
  1233. @rdesc None.
  1234. ****/
  1235. VOID
  1236. FmpPrepareGroupEnumForOnline(
  1237. IN PGROUP_ENUM pGroupEnum
  1238. )
  1239. {
  1240. PFM_GROUP pGroup = NULL;
  1241. DWORD i;
  1242. //
  1243. // Chittur Subbaraman (chitturs) - 6/21/99
  1244. //
  1245. // Prepare an entire group list for online.
  1246. //
  1247. ClRtlLogPrint(LOG_NOISE,
  1248. "[FM] FmpPrepareGroupEnumForOnline - Entry...\n");
  1249. for ( i=0; i<pGroupEnum->EntryCount; i++ )
  1250. {
  1251. pGroup = OmReferenceObjectById( ObjectTypeGroup,
  1252. pGroupEnum->Entry[i].Id );
  1253. //
  1254. // If we fail to find a group, then just continue.
  1255. //
  1256. if ( pGroup == NULL )
  1257. {
  1258. ClRtlLogPrint(LOG_UNUSUAL,
  1259. "[FM] FmpPrepareGroupEnumForOnline - Group %1!ws! cannot be found !\n",
  1260. pGroupEnum->Entry[i].Id);
  1261. continue;
  1262. }
  1263. ClRtlLogPrint(LOG_NOISE,
  1264. "[FM] FmpPrepareGroupEnumForOnline - Preparing group <%1!ws!> for online...\n",
  1265. pGroupEnum->Entry[i].Id);
  1266. FmpPrepareGroupForOnline( pGroup );
  1267. }
  1268. ClRtlLogPrint(LOG_NOISE,
  1269. "[FM] FmpPrepareGroupEnumForOnline - Exit...\n");
  1270. }
  1271. /****
  1272. @func DWORD | FmpBringQuorumGroupListOnline | Bring a list of groups
  1273. containing the quorum group online.
  1274. @parm IN LPVOID | pContext | A pointer to the group list to be brought
  1275. online.
  1276. @rdesc Returns ERROR_SUCCESS.
  1277. ****/
  1278. DWORD
  1279. FmpBringQuorumGroupListOnline(
  1280. IN LPVOID pContext
  1281. )
  1282. {
  1283. PGROUP_ENUM pGroupList = NULL;
  1284. //
  1285. // Chittur Subbaraman (chitturs) - 7/14/99
  1286. //
  1287. // This function tries to bring a list of groups containing the quorum
  1288. // group online. Note that if the group's owner turns out to be some
  1289. // other node, this function will not online the group.
  1290. //
  1291. ClRtlLogPrint(LOG_NOISE,
  1292. "[FM] FmpBringQuorumGroupListOnline - Entry: Trying to online group list containing quorum group....\n"
  1293. );
  1294. pGroupList = pContext;
  1295. CL_ASSERT( pGroupList != NULL );
  1296. FmpOnlineGroupList( pGroupList, TRUE );
  1297. FmpDeleteEnum( pGroupList );
  1298. ClRtlLogPrint(LOG_NOISE,
  1299. "[FM] FmpBringQuorumGroupListOnline - Exit ....\n"
  1300. );
  1301. return( ERROR_SUCCESS );
  1302. }
  1303. /****
  1304. @func BOOL | FmpIsAnyResourcePersistentStateOnline | Is the persistent state of any
  1305. resource in the group online ?
  1306. @parm IN PFM_GROUP | pGroup | The group which is to be checked.
  1307. @rdesc TRUE if at least one resource's persistent state is ClusterResourceOnline, FALSE otherwise.
  1308. ****/
  1309. BOOL
  1310. FmpIsAnyResourcePersistentStateOnline(
  1311. IN PFM_GROUP pGroup
  1312. )
  1313. {
  1314. PFM_RESOURCE pResource;
  1315. PLIST_ENTRY pListEntry;
  1316. if ( CsNoQuorum ) return FALSE;
  1317. for ( pListEntry = pGroup->Contains.Flink;
  1318. pListEntry != &( pGroup->Contains );
  1319. pListEntry = pListEntry->Flink )
  1320. {
  1321. pResource = CONTAINING_RECORD( pListEntry,
  1322. FM_RESOURCE,
  1323. ContainsLinkage );
  1324. if ( pResource->PersistentState == ClusterResourceOnline )
  1325. {
  1326. ClRtlLogPrint(LOG_NOISE,
  1327. "[FM] FmpIsAnyResourcePersistentStateOnline: Persistent state of resource %1!ws! in group %2!ws! is online...\r\n",
  1328. OmObjectId(pResource),
  1329. OmObjectId(pGroup));
  1330. return ( TRUE );
  1331. }
  1332. } // for
  1333. ClRtlLogPrint(LOG_NOISE,
  1334. "[FM] FmpIsAnyResourcePersistentStateOnline: No resource in group %1!ws! has persistent state online...\r\n",
  1335. OmObjectId(pGroup));
  1336. return( FALSE );
  1337. } // FmpIsAnyResourcePersistentStateOnline