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.

3034 lines
83 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. resource.c
  5. Abstract:
  6. Cluster resource management routines.
  7. Author:
  8. Mike Massa (mikemas) 1-Jan-1996
  9. Notes:
  10. WARNING: All of the routines in this file assume that the resource
  11. lock is held when they are called.
  12. Revision History:
  13. --*/
  14. #include "fmp.h"
  15. //globals
  16. #define LOG_MODULE RESOURCE
  17. //
  18. // Global Data
  19. //
  20. CRITICAL_SECTION FmpResourceLock;
  21. //
  22. // Local Data
  23. //
  24. typedef struct PENDING_CONTEXT {
  25. PFM_RESOURCE Resource;
  26. BOOL ForceOnline;
  27. } PENDING_CONTEXT, *PPENDING_CONTEXT;
  28. //
  29. // Local function prototypes
  30. //
  31. /////////////////////////////////////////////////////////////////////////////
  32. //
  33. // Resource List Maintenance Routines
  34. //
  35. /////////////////////////////////////////////////////////////////////////////
  36. BOOL
  37. FmpFindResourceByNotifyKeyWorker(
  38. IN RM_NOTIFY_KEY NotifyKey,
  39. IN PFM_RESOURCE *FoundResource,
  40. IN PFM_RESOURCE Resource,
  41. IN LPCWSTR Name
  42. )
  43. /*++
  44. Routine Description:
  45. Enumeration callback routine for finding a resource by notify key
  46. Arguments:
  47. FoundResource - Returns the found resource.
  48. Resource - Supplies the current resource.
  49. Name - Supplies the current resource's name.
  50. Return Value:
  51. TRUE - to continue searching
  52. FALSE - to stop the search. The matching resource is returned in
  53. *FoundResource
  54. --*/
  55. {
  56. if ((RM_NOTIFY_KEY)Resource == NotifyKey) {
  57. *FoundResource = Resource;
  58. return(FALSE);
  59. }
  60. return(TRUE);
  61. } // FmpFindResourceByNotifyKeyWorker
  62. PFM_RESOURCE
  63. FmpFindResourceByNotifyKey(
  64. RM_NOTIFY_KEY NotifyKey
  65. )
  66. /*++
  67. Routine Description:
  68. Arguments:
  69. Returns:
  70. --*/
  71. {
  72. PFM_RESOURCE resource = NULL;
  73. OmEnumObjects(ObjectTypeResource,
  74. (OM_ENUM_OBJECT_ROUTINE)FmpFindResourceByNotifyKeyWorker,
  75. (PVOID)NotifyKey,
  76. &resource);
  77. return(resource);
  78. } // FmpFindResourceByNotifyKey
  79. //////////////////////////////////////////////////////////////
  80. //
  81. // Interfaces for managing resources.
  82. //
  83. /////////////////////////////////////////////////////////////
  84. PFM_RESOURCE
  85. FmpCreateResource(
  86. IN PFM_GROUP Group,
  87. IN LPCWSTR ResourceId,
  88. IN LPCWSTR ResourceName,
  89. IN BOOL Initialize
  90. )
  91. /*++
  92. Routine Description:
  93. Create a resource in our list of resources.
  94. Arguments:
  95. Group - The Group in which this resource belongs.
  96. ResourceId - The id of the resource being created.
  97. ResourceName - The name of the resource being created.
  98. Initialize - TRUE if the resource should be initialized from the registry.
  99. FALSE if the resource should be left un-initialized.
  100. Returns:
  101. A pointer to the resource that was created or NULL.
  102. Notes:
  103. 1) The resource lock must be held when this routine is called.
  104. 2) If the resource was created, then the reference count on the resource
  105. is 2 when this routine returns. If the resource was not created, then
  106. the reference count on the resource is not incremented. That way, if
  107. the caller needs extra references on the resource, then it must place
  108. them itself. This can be done later, since the resource lock is held.
  109. --*/
  110. {
  111. DWORD mszStringIndex;
  112. PFM_RESOURCE resource = NULL;
  113. DWORD status;
  114. PDEPENDENCY dependency = NULL;
  115. DWORD resourceNameSize=
  116. (wcslen(ResourceId) * sizeof(WCHAR)) +
  117. sizeof(UNICODE_NULL);
  118. BOOL created;
  119. LPWSTR quorumId = NULL;
  120. DWORD quorumIdSize = 0;
  121. DWORD quorumIdMaxSize = 0;
  122. //
  123. // Open an existing resource or create a new one.
  124. //
  125. resource = OmCreateObject( ObjectTypeResource,
  126. ResourceId,
  127. ResourceName,
  128. &created);
  129. if ( resource == NULL ) {
  130. return(NULL);
  131. }
  132. //
  133. // If we did not create a new resource, then make sure the Groups match.
  134. //
  135. if ( !created )
  136. {
  137. ClRtlLogPrint(LOG_NOISE,
  138. "[FM] CreateResource, Opened existing resource %1!ws!\n",
  139. ResourceId);
  140. OmDereferenceObject( resource );
  141. //the quorum group may be created again recursively before phase 1
  142. //in this case we dont want to do the special processing for putting
  143. //it on the quorum group contains list
  144. if ( resource->Group == Group )
  145. {
  146. return(resource);
  147. }
  148. //the quorum group is destroyed at initialization but not the quorum resource
  149. if (!FmpFMOnline)
  150. {
  151. //the quorum group is being recreated for the second time
  152. //the quorum group state needs to be refigured
  153. // this is done after all groups are created in FmFormNewClusterPhase2()
  154. if (resource->QuorumResource)
  155. {
  156. ClRtlLogPrint(LOG_NOISE,"[FM] ReCreating quorum resource %1!ws!\n", ResourceId);
  157. Group->OwnerNode = NmLocalNode;
  158. InsertTailList( &Group->Contains,
  159. &resource->ContainsLinkage );
  160. //add a referenece to the resource object for being on the contains list
  161. OmReferenceObject( resource );
  162. resource->Group = Group;
  163. OmReferenceObject(Group);
  164. //SS: for now we dont use resource locks, so dont create it and leak it !
  165. //InitializeCriticalSection( &resource->Lock );
  166. FmpSetPreferredEntry( Group, NmLocalNode );
  167. return(resource);
  168. }
  169. }
  170. else
  171. {
  172. SetLastError(ERROR_RESOURCE_NOT_AVAILABLE);
  173. return(NULL);
  174. }
  175. }
  176. ClRtlLogPrint(LOG_NOISE,"[FM] Creating resource %1!ws!\n", ResourceId);
  177. resource->dwStructState = FM_RESOURCE_STRUCT_CREATED;
  178. //
  179. // Initialize the resource.
  180. //
  181. resource->Group = Group;
  182. resource->State = ClusterResourceOffline; // Initial value for state.
  183. // resource->Flags = 0; // Structure zeroed at creation
  184. // resource->Id = 0;
  185. // resource->FailureTime = 0;
  186. // resource->QuorumResource = FALSE;
  187. // resource->PossibleList = FALSE;
  188. //SS: for now we dont use resource locks, so dont create it and leak it !
  189. //InitializeCriticalSection( &resource->Lock );
  190. resource->hTimer=NULL;
  191. InitializeListHead( &(resource->ProvidesFor) );
  192. InitializeListHead( &(resource->DependsOn) );
  193. InitializeListHead( &(resource->PossibleOwners) );
  194. InitializeListHead( &(resource->DmRundownList) );
  195. //
  196. // Insert the new resource onto the Group's contains list.
  197. //
  198. InsertTailList( &Group->Contains,
  199. &resource->ContainsLinkage );
  200. //SS: there is already a reference to the object for being on the resource
  201. //list
  202. //add a referenece to the resource object for being on the contains list
  203. OmReferenceObject( resource );
  204. //add a reference to the group because the resource has a pointer to it
  205. OmReferenceObject(Group);
  206. //
  207. // Complete initialization if we were told to do so.
  208. //
  209. status = FmpInitializeResource( resource, Initialize );
  210. //
  211. // Check for distinguished error code to delete this resource.
  212. //
  213. if ( status == ERROR_INVALID_NAME ) {
  214. goto error_exit;
  215. }
  216. //
  217. // On other failures, we must be sure to come back through init later...
  218. //
  219. if ( Initialize &&
  220. (status != ERROR_SUCCESS) ) {
  221. CL_ASSERT( resource->Monitor == NULL );
  222. }
  223. //
  224. // Now insert this object into the tree... before the dependency
  225. // list is processed. That way, if there are circular dependencies
  226. // this will not loop forever. If we can be assured that there are
  227. // no circular dependencies, then we can do the insert after creating
  228. // the dependency tree.
  229. //
  230. // if this is being called during initialization, and the resource is
  231. // is already created it belonged to the group to which the quorum
  232. // resource belongs to and doesnt need to be inserted into the resource list
  233. if (FmpFMOnline || (created))
  234. {
  235. status = OmInsertObject( resource );
  236. if ( status != ERROR_SUCCESS )
  237. goto error_exit;
  238. }
  239. //
  240. // Check if this is the Quorum Resource.
  241. //
  242. status = DmQuerySz( DmQuorumKey,
  243. CLUSREG_NAME_QUORUM_RESOURCE,
  244. &quorumId,
  245. &quorumIdMaxSize,
  246. &quorumIdSize );
  247. if ( status != ERROR_SUCCESS) {
  248. ClRtlLogPrint(LOG_ERROR,
  249. "[FM] Failed to read quorum resource, error %1!u!.\n",
  250. status);
  251. }
  252. //
  253. // If we're creating the quorum resource, then indicate it.
  254. //
  255. if ( (quorumId != NULL) &&
  256. (lstrcmpiW( quorumId, ResourceId ) == 0) ) {
  257. ClRtlLogPrint(LOG_NOISE,
  258. "[FM] Found the quorum resource %1!ws!.\n",
  259. ResourceId);
  260. resource->QuorumResource = TRUE;
  261. }
  262. LocalFree(quorumId);
  263. //
  264. // Create Any Dependencies
  265. //
  266. for (mszStringIndex = 0; ; mszStringIndex++) {
  267. LPCWSTR nameString;
  268. PFM_RESOURCE childResource;
  269. nameString = ClRtlMultiSzEnum(
  270. resource->Dependencies,
  271. resource->DependenciesSize/sizeof(WCHAR),
  272. mszStringIndex
  273. );
  274. if (nameString == NULL) {
  275. break;
  276. }
  277. //
  278. // Create the dependency.
  279. //
  280. dependency = LocalAlloc(LMEM_FIXED, sizeof(DEPENDENCY));
  281. if (dependency == NULL) {
  282. status = ERROR_NOT_ENOUGH_MEMORY;
  283. goto error_exit;
  284. }
  285. //
  286. // Create the child resource recursively. We must also add an
  287. // additional reference required for the dependency relationship.
  288. //
  289. ClRtlLogPrint(LOG_NOISE,"[FM] Resource %1!ws! depends on %2!ws!. Creating...\n",
  290. ResourceId,
  291. nameString);
  292. childResource = FmpCreateResource( resource->Group,
  293. nameString,
  294. NULL,
  295. Initialize );
  296. if (childResource == NULL) {
  297. status = GetLastError();
  298. ClRtlLogPrint(LOG_NOISE,"[FM] Failed to create dep %1!ws! for resource %2!ws!\n",
  299. nameString,
  300. ResourceId);
  301. goto error_exit;
  302. } else {
  303. //
  304. // Add a reference to each resource to reflect the
  305. // dependency.
  306. //
  307. OmReferenceObject( childResource );
  308. OmReferenceObject( resource );
  309. dependency->DependentResource = resource;
  310. dependency->ProviderResource = childResource;
  311. InsertTailList(&childResource->ProvidesFor,
  312. &dependency->ProviderLinkage);
  313. InsertTailList(&resource->DependsOn,
  314. &dependency->DependentLinkage);
  315. }
  316. }
  317. resource->dwStructState |= FM_RESOURCE_STRUCT_INITIALIZED;
  318. ClRtlLogPrint(LOG_NOISE,"[FM] All dependencies for resource %1!ws! created.\n",
  319. ResourceId);
  320. return(resource);
  321. error_exit:
  322. FmpAcquireLocalResourceLock( resource );
  323. RemoveEntryList( &resource->ContainsLinkage );
  324. //dereference the resource object for being removed from the contains linkage
  325. OmDereferenceObject( resource );
  326. FmpDestroyResource( resource, FALSE );
  327. //dereference the resource object, for being removed from the resource list.
  328. //OmDereferenceObject( resource );
  329. //delete the extra reference that was added to the group
  330. //OmDereferenceObject(Group);
  331. SetLastError(status);
  332. return(NULL);
  333. } // FmpCreateResource
  334. DWORD
  335. FmpInitializeResource(
  336. IN PFM_RESOURCE Resource,
  337. IN BOOL Initialize
  338. )
  339. /*++
  340. Routine Description:
  341. Initializes a resource from the registry and tells the Resource
  342. Monitor about the new resource (if the local system can host the
  343. resource).
  344. Arguments:
  345. Resource - Supplies the resource to be initialized.
  346. Initialize - TRUE if the resource should be fully initialized.
  347. FALSE otherwise.
  348. Return Value:
  349. ERROR_SUCCESS if successful.
  350. A Win32 error code on failure.
  351. Notes:
  352. It is assumed that the resource lock is held.
  353. --*/
  354. {
  355. DWORD status;
  356. if ( Resource->Monitor != NULL ) {
  357. return(ERROR_ALREADY_INITIALIZED);
  358. }
  359. status = FmpQueryResourceInfo( Resource, Initialize );
  360. if ( status != ERROR_SUCCESS ) {
  361. return(status);
  362. }
  363. //
  364. // If we didn't fully initialize the resource, then leave now.
  365. //
  366. if ( !Initialize ) {
  367. return(ERROR_SUCCESS);
  368. }
  369. //
  370. // This is a newly initialized resource. Tell the Resource Monitor to
  371. // create it.
  372. //
  373. // TODO - we don't want to instantiate resources in the resource
  374. // monitor that we cannot execute. We must check possible owners list
  375. // before making this call. We must also make sure the registry
  376. // parameters are read. We use the Monitor field as a surrogate for
  377. // determining whether the registry parameters have been read.
  378. //
  379. return(FmpRmCreateResource(Resource));
  380. } // FmpInitializeResource
  381. DWORD
  382. FmpOnlineResource(
  383. IN PFM_RESOURCE Resource,
  384. IN BOOL ForceOnline
  385. )
  386. /*++
  387. Routine Description:
  388. Brings a resource and all its dependencies online. If ERROR_IO_PENDING is
  389. returned, then no thread is started to complete the online request.
  390. Arguments:
  391. Resource - Supplies the resource to be brought online
  392. ForceOnline - TRUE if the resource should be forced online.
  393. Return Value:
  394. ERROR_SUCCESS if successful.
  395. ERROR_IO_PENDING if the request is pending.
  396. Win32 error code otherwise.
  397. --*/
  398. {
  399. PLIST_ENTRY entry;
  400. PDEPENDENCY dependency;
  401. DWORD status;
  402. BOOL waitingResource = FALSE;
  403. DWORD separateMonitor;
  404. DWORD onlinestatus;
  405. FmpAcquireLocalResourceLock( Resource );
  406. //
  407. // If the resource is not owned by this system, then return error.
  408. //
  409. CL_ASSERT( Resource->Group != NULL );
  410. if (Resource->Group->OwnerNode != NmLocalNode)
  411. {
  412. FmpReleaseLocalResourceLock( Resource );
  413. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  414. }
  415. //if it is the quorum resource dont check for the node
  416. //being in the preferred list, we should be able to
  417. //bring the quorum resource online on any node
  418. if (!(Resource->QuorumResource) &&
  419. !FmpInPreferredList( Resource->Group, Resource->Group->OwnerNode, TRUE, Resource ))
  420. {
  421. FmpReleaseLocalResourceLock( Resource );
  422. return(ERROR_NODE_CANT_HOST_RESOURCE);
  423. }
  424. //
  425. // If the resource is already online, then return immediately.
  426. //
  427. if (Resource->State == ClusterResourceOnline) {
  428. FmpReleaseLocalResourceLock( Resource );
  429. return(ERROR_SUCCESS);
  430. }
  431. //
  432. // If the resource is in online pending state, then return immediately.
  433. //
  434. if ( Resource->State == ClusterResourceOnlinePending ) {
  435. FmpReleaseLocalResourceLock( Resource );
  436. return(ERROR_IO_PENDING);
  437. }
  438. //
  439. // If the resource is in offline pending state, then return immediately.
  440. //
  441. if ( Resource->State == ClusterResourceOfflinePending ) {
  442. FmpReleaseLocalResourceLock( Resource );
  443. return(ERROR_INVALID_STATE);
  444. }
  445. //
  446. // If the resource is not initialized, then initialize it now.
  447. //
  448. if ( Resource->Monitor == NULL ) {
  449. status = FmpInitializeResource( Resource, TRUE );
  450. if ( status != ERROR_SUCCESS ) {
  451. FmpReleaseLocalResourceLock( Resource );
  452. return(status);
  453. }
  454. } else {
  455. //
  456. // If the separate monitor flag has changed, then close down old
  457. // resource in resmon, and re-create it.
  458. //
  459. separateMonitor = (Resource->Flags & RESOURCE_SEPARATE_MONITOR) ? 1 : 0;
  460. status = DmQueryDword( Resource->RegistryKey,
  461. CLUSREG_NAME_RES_SEPARATE_MONITOR,
  462. &separateMonitor,
  463. &separateMonitor );
  464. if ( (!separateMonitor &&
  465. (Resource->Flags & RESOURCE_SEPARATE_MONITOR)) ||
  466. (separateMonitor &&
  467. ((Resource->Flags & RESOURCE_SEPARATE_MONITOR) == 0)) ) {
  468. status = FmpChangeResourceMonitor( Resource, separateMonitor );
  469. if ( status != ERROR_SUCCESS ) {
  470. FmpReleaseLocalResourceLock( Resource );
  471. return(status);
  472. }
  473. }
  474. }
  475. //
  476. // If this resource is supposed to be left offline, then make it so.
  477. //
  478. if ( !ForceOnline && (Resource->PersistentState == ClusterResourceOffline) ) {
  479. FmpReleaseLocalResourceLock( Resource );
  480. return(ERROR_RESOURCE_NOT_ONLINE);
  481. }
  482. //
  483. // Next, make sure there are no resources down the tree that are waiting.
  484. // This prevents a deadlock where the top of the tree is trying to go
  485. // offline, while the bottom of the tree is trying to go online.
  486. //
  487. for ( entry = Resource->DependsOn.Flink;
  488. entry != &(Resource->DependsOn);
  489. entry = entry->Flink
  490. )
  491. {
  492. dependency = CONTAINING_RECORD(entry, DEPENDENCY, DependentLinkage);
  493. if ( (dependency->ProviderResource->State == ClusterResourceOfflinePending) &&
  494. (dependency->ProviderResource->Flags & RESOURCE_WAITING) ) {
  495. waitingResource= TRUE;
  496. break;
  497. }
  498. }
  499. if ( waitingResource ) {
  500. Resource->Flags |= RESOURCE_WAITING;
  501. FmpReleaseLocalResourceLock( Resource );
  502. return(ERROR_RESOURCE_NOT_AVAILABLE);
  503. }
  504. //
  505. // If the PersistentState is Offline, then reset the current state.
  506. //
  507. if ( Resource->PersistentState == ClusterResourceOffline ) {
  508. FmpSetResourcePersistentState( Resource, ClusterResourceOnline );
  509. }
  510. //
  511. // Make sure the Waiting flag is clear.
  512. //
  513. Resource->Flags &= ~RESOURCE_WAITING;
  514. //
  515. // If this resource has any dependencies, bring them online first.
  516. //
  517. for ( entry = Resource->DependsOn.Flink;
  518. entry != &(Resource->DependsOn);
  519. entry = entry->Flink
  520. )
  521. {
  522. dependency = CONTAINING_RECORD(entry, DEPENDENCY, DependentLinkage);
  523. //
  524. // Recursively bring the provider resource online.
  525. //
  526. ClRtlLogPrint(LOG_NOISE,
  527. "[FM] OnlineResource: %1!ws! depends on %2!ws!. Bring online first.\n",
  528. OmObjectId(Resource),
  529. OmObjectId(dependency->ProviderResource));
  530. onlinestatus = FmpDoOnlineResource( dependency->ProviderResource,
  531. ForceOnline );
  532. if ( onlinestatus != ERROR_SUCCESS ) {
  533. if ( onlinestatus != ERROR_IO_PENDING ) {
  534. ClRtlLogPrint(LOG_NOISE,
  535. "[FM] OnlineResource: dependency %1!ws! failed %2!d!\n",
  536. OmObjectId(dependency->ProviderResource),
  537. status);
  538. FmpReleaseLocalResourceLock( Resource );
  539. status = onlinestatus;
  540. return(status);
  541. } else {
  542. FmpCallResourceNotifyCb(Resource, ClusterResourceOnlinePending);
  543. FmpPropagateResourceState( Resource,
  544. ClusterResourceOnlinePending );
  545. Resource->Flags |= RESOURCE_WAITING;
  546. if (status == ERROR_SUCCESS)
  547. status = onlinestatus;
  548. }
  549. }
  550. }
  551. //
  552. // Tell the resource monitor to bring this resource online.
  553. //
  554. if ( !(Resource->Flags & RESOURCE_WAITING) ) {
  555. status = FmpRmOnlineResource( Resource );
  556. }
  557. #ifdef CLUSTER_TESTPOINT
  558. TESTPT(TpFailOnlineResource) {
  559. FmpRmFailResource( Resource );
  560. }
  561. #endif
  562. FmpReleaseLocalResourceLock( Resource );
  563. return(status);
  564. } // FmpOnlineResource
  565. DWORD
  566. FmpTerminateResource(
  567. IN PFM_RESOURCE Resource
  568. )
  569. /*++
  570. Routine Description:
  571. This routine takes a resource (and all of the resources that it provides
  572. for) offline - the hard way.
  573. Arguments:
  574. Resource - A pointer to the resource to take offline the hard way.
  575. Returns:
  576. ERROR_SUCCESS - if the request is successful.
  577. A Win32 error if the request fails.
  578. --*/
  579. {
  580. PLIST_ENTRY entry;
  581. PDEPENDENCY dependency;
  582. DWORD status;
  583. FmpAcquireLocalResourceLock( Resource );
  584. //
  585. // If the resource is already offline, then return immediately.
  586. //
  587. // We should not have to check if a resource has been initialized,
  588. // since if it hasn't been initialized we will return because the
  589. // pre-initialized state of a resource is Offline.
  590. //
  591. if ( Resource->State == ClusterResourceOffline ) {
  592. FmpReleaseLocalResourceLock( Resource );
  593. return(ERROR_SUCCESS);
  594. }
  595. Resource->Flags &= ~RESOURCE_WAITING;
  596. //
  597. // If this resource has any dependents, terminate them first.
  598. //
  599. for ( entry = Resource->ProvidesFor.Flink;
  600. entry != &(Resource->ProvidesFor);
  601. entry = entry->Flink
  602. )
  603. {
  604. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  605. //
  606. // Recursively terminate the dependent resource
  607. //
  608. ClRtlLogPrint(LOG_NOISE,
  609. "[FM] TerminateResource: %1!ws! depends on %2!ws!. Terminating first\n",
  610. OmObjectId(dependency->DependentResource),
  611. OmObjectId(Resource));
  612. //
  613. // First stop any pending threads.
  614. //
  615. if ( dependency->DependentResource->PendingEvent ) {
  616. SetEvent( dependency->DependentResource->PendingEvent );
  617. }
  618. status = FmpTerminateResource(dependency->DependentResource);
  619. CL_ASSERT( status != ERROR_IO_PENDING );
  620. if (status != ERROR_SUCCESS) {
  621. FmpReleaseLocalResourceLock( Resource );
  622. return(status);
  623. }
  624. }
  625. //
  626. // Tell the resource monitor to terminate this resource.
  627. //
  628. FmpRmTerminateResource(Resource);
  629. FmpReleaseLocalResourceLock( Resource );
  630. return(ERROR_SUCCESS);
  631. } // FmpTerminateResource
  632. DWORD
  633. FmpOfflineResource(
  634. IN PFM_RESOURCE Resource,
  635. IN BOOL bForceOffline
  636. )
  637. /*++
  638. Routine Description:
  639. This routine takes a resource (and all of the resources that it provides
  640. for) offline. If ERROR_IO_PENDING is returned, then no thread is started
  641. to complete the offline request.
  642. Arguments:
  643. Resource - A pointer to the resource to take offline.
  644. bForceOffline - Indicates whether the persistent state is to be set.
  645. Returns:
  646. ERROR_SUCCESS if the request is successful.
  647. ERROR_IO_PENDING if the request is pending.
  648. A Win32 error code if the request fails.
  649. --*/
  650. {
  651. DWORD status = ERROR_SUCCESS;
  652. PLIST_ENTRY entry;
  653. PDEPENDENCY dependency;
  654. BOOL waitingResource = FALSE;
  655. DWORD offlinestatus;
  656. FmpAcquireLocalResourceLock( Resource );
  657. ClRtlLogPrint(LOG_NOISE,
  658. "[FM] FmpOfflineResource: Offline resource <%1!ws!> <%2!ws!>\n",
  659. OmObjectName(Resource),
  660. OmObjectId(Resource) );
  661. //
  662. // If we own the Group and we are not a possible owner, then the resource
  663. // better be offline!
  664. //
  665. if ( (Resource->Group->OwnerNode != NmLocalNode) ||
  666. (!FmpInPreferredList( Resource->Group, Resource->Group->OwnerNode , FALSE, NULL) &&
  667. (Resource->Group != gpQuoResource->Group) &&
  668. (Resource->State != ClusterResourceOffline)) ) {
  669. FmpReleaseLocalResourceLock( Resource );
  670. return(ERROR_INVALID_STATE);
  671. }
  672. //
  673. // If the resource is already offline, then return immediately.
  674. //
  675. // We should not have to check if a resource has been initialized,
  676. // since if it hasn't, then we will return because the pre-initialized
  677. // state of a resource is Offline.
  678. //
  679. if ( Resource->State == ClusterResourceOffline ) {
  680. //
  681. // If this is the quorum resource, make sure any reservation
  682. // threads are stopped!
  683. //
  684. if ( Resource->QuorumResource ) {
  685. FmpRmTerminateResource( Resource );
  686. }
  687. FmpReleaseLocalResourceLock( Resource );
  688. return(ERROR_SUCCESS);
  689. } else if ( Resource->State == ClusterResourceFailed ) {
  690. //
  691. // Chittur Subbaraman (chitturs) - 4/8/99
  692. //
  693. // If the resource has already failed, then don't do anything.
  694. // You could run into some funny cases of a resource switching
  695. // between offline pending and failed states for ever if you
  696. // attempt to offline a failed resource.
  697. //
  698. FmpReleaseLocalResourceLock( Resource );
  699. return(ERROR_SUCCESS);
  700. }
  701. //
  702. // If this system is not the owner, then return an error. Forwarding
  703. // should have been done at a higher layer.
  704. //
  705. CL_ASSERT( Resource->Group != NULL );
  706. if ( (Resource->Group->OwnerNode != NmLocalNode) ||
  707. ((Resource->Group != gpQuoResource->Group) &&
  708. !FmpInPreferredList( Resource->Group, Resource->Group->OwnerNode, FALSE, NULL)) ) {
  709. FmpReleaseLocalResourceLock( Resource );
  710. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  711. }
  712. if (Resource->State == ClusterResourceOnlinePending ) {
  713. FmpReleaseLocalResourceLock( Resource );
  714. ClRtlLogPrint(LOG_NOISE,
  715. "[FM] FmpOfflineResource: Offline resource <%1!ws!> is in online pending state\n",
  716. OmObjectName(Resource) );
  717. if (FmpShutdown)
  718. {
  719. FmpRmTerminateResource( Resource );
  720. return(ERROR_SUCCESS);
  721. }
  722. else
  723. return(ERROR_INVALID_STATE);
  724. }
  725. //
  726. // If the resource is in a pending state, then return immediately.
  727. //
  728. if (Resource->State == ClusterResourceOfflinePending ) {
  729. FmpReleaseLocalResourceLock( Resource );
  730. ClRtlLogPrint(LOG_NOISE,
  731. "[FM] FmpOfflineResource: Offline resource <%1!ws!> returned pending\n",
  732. OmObjectName(Resource) );
  733. return(ERROR_IO_PENDING);
  734. }
  735. //
  736. // Next, make sure there are no resources up the tree that are waiting.
  737. // This prevents a deadlock where the top of the tree is trying to go
  738. // offline, while the bottom of the tree is trying to go online.
  739. //
  740. for ( entry = Resource->ProvidesFor.Flink;
  741. entry != &(Resource->ProvidesFor);
  742. entry = entry->Flink
  743. )
  744. {
  745. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  746. if ( (dependency->DependentResource->State == ClusterResourceOnlinePending) &&
  747. (dependency->DependentResource->Flags & RESOURCE_WAITING) ) {
  748. waitingResource = TRUE;
  749. break;
  750. }
  751. }
  752. if ( waitingResource ) {
  753. Resource->Flags |= RESOURCE_WAITING;
  754. FmpReleaseLocalResourceLock( Resource );
  755. return(ERROR_RESOURCE_NOT_AVAILABLE);
  756. }
  757. //
  758. // Make sure the Waiting flag is clear.
  759. //
  760. Resource->Flags &= ~RESOURCE_WAITING;
  761. //
  762. // If this resource has any dependents, shut them down first.
  763. //
  764. for ( entry = Resource->ProvidesFor.Flink;
  765. entry != &(Resource->ProvidesFor);
  766. entry = entry->Flink
  767. )
  768. {
  769. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  770. //
  771. // Recursively shutdown the dependent resource.
  772. //
  773. ClRtlLogPrint(LOG_NOISE,
  774. "[FM] FmpOfflineResource: %1!ws! depends on %2!ws!. Shut down first.\n",
  775. OmObjectName(dependency->DependentResource),
  776. OmObjectName(Resource));
  777. offlinestatus = FmpDoOfflineResource(dependency->DependentResource,
  778. bForceOffline);
  779. if ( offlinestatus != ERROR_SUCCESS ) {
  780. if ( offlinestatus != ERROR_IO_PENDING ) {
  781. ClRtlLogPrint(LOG_NOISE,
  782. "[FM] FmpOfflineResource for %1!ws!, bad status returned %2!u!.\n",
  783. OmObjectName(dependency->DependentResource),
  784. offlinestatus);
  785. FmpTerminateResource( dependency->DependentResource );
  786. FmpReleaseLocalResourceLock( Resource );
  787. return(offlinestatus);
  788. } else {
  789. ClRtlLogPrint(LOG_NOISE,
  790. "[FM] FmpOfflineResource for %1!ws! marked as waiting.\n",
  791. OmObjectName(Resource));
  792. FmpCallResourceNotifyCb(Resource, ClusterResourceOfflinePending);
  793. FmpPropagateResourceState( Resource,
  794. ClusterResourceOfflinePending );
  795. Resource->Flags |= RESOURCE_WAITING;
  796. if (status == ERROR_SUCCESS)
  797. status = offlinestatus;
  798. }
  799. }
  800. }
  801. //
  802. // Tell the resource monitor to shut this resource down.
  803. // The state gets updated by the return status in FmpRmOfflineResource.
  804. //
  805. if ( !(Resource->Flags & RESOURCE_WAITING) ) {
  806. status = FmpRmOfflineResource( Resource );
  807. //
  808. // Chittur Subbaraman (chitturs) - 3/2/2000
  809. //
  810. // If the resource could not be made offline since the quorum
  811. // resource online operation failed or for other reasons, then
  812. // make sure the resource is terminated after you declare the
  813. // state of the resource as failed. This is necessary since
  814. // otherwise the FM will consider the resource as having failed
  815. // while the resource itself is actually online. This will
  816. // lead to disastrous cases whereby the FM will allow the online
  817. // entry point of a resource to be called while the resource is
  818. // actually online !
  819. //
  820. if( ( status != ERROR_SUCCESS ) &&
  821. ( status != ERROR_IO_PENDING ) &&
  822. ( status != ERROR_RETRY ) ) {
  823. FmpRmTerminateResource( Resource );
  824. }
  825. }
  826. FmpReleaseLocalResourceLock( Resource );
  827. return(status);
  828. } // FmpOfflineResource
  829. DWORD
  830. FmpDoOnlineResource(
  831. IN PFM_RESOURCE Resource,
  832. IN BOOL ForceOnline
  833. )
  834. /*++
  835. Routine Description:
  836. This routine brings a resource online. If ERROR_IO_PENDING is returned,
  837. then a thread is started to complete the Online request.
  838. Arguments:
  839. Resource - A pointer to the resource to bring online.
  840. ForceOnline - TRUE if the resource should be forced online.
  841. Returns:
  842. ERROR_SUCCESS if the request is successful.
  843. ERROR_IO_PENDING if the request is pending.
  844. A Win32 error code if the request fails.
  845. --*/
  846. {
  847. DWORD status;
  848. FmpAcquireLocalResourceLock( Resource );
  849. //
  850. // If the resource is already online, then return immediately.
  851. //
  852. if ( Resource->State == ClusterResourceOnline ) {
  853. FmpReleaseLocalResourceLock( Resource );
  854. return(ERROR_SUCCESS);
  855. }
  856. //
  857. // If the resource is in a pending state, then return immediately.
  858. // FmpOnlineResource checks for offlinepending state and returns
  859. // ERROR_INVALID_STATE if so.
  860. //
  861. if ( Resource->State == ClusterResourceOnlinePending ) {
  862. FmpReleaseLocalResourceLock( Resource );
  863. return(ERROR_IO_PENDING);
  864. }
  865. //
  866. // If this node is paused, return failure.
  867. //
  868. if (NmGetNodeState(NmLocalNode) == ClusterNodePaused) {
  869. FmpReleaseLocalResourceLock( Resource );
  870. return(ERROR_SHARING_PAUSED);
  871. }
  872. //
  873. // Try to bring the resource online.
  874. //
  875. status = FmpOnlineResource( Resource, ForceOnline );
  876. //
  877. // Write the persistent state if it is forced online.
  878. //
  879. if ( ForceOnline &&
  880. ((status == ERROR_SUCCESS)||
  881. (status == ERROR_IO_PENDING))) {
  882. FmpSetResourcePersistentState( Resource, ClusterResourceOnline );
  883. }
  884. FmpReleaseLocalResourceLock( Resource );
  885. return(status);
  886. } // FmpDoOnlineResource
  887. DWORD
  888. FmpDoOfflineResource(
  889. IN PFM_RESOURCE Resource,
  890. IN BOOL bForceOffline
  891. )
  892. /*++
  893. Routine Description:
  894. This routine takes a resource offline. If ERROR_IO_PENDING is returned,
  895. then a thread is started to complete the Offline request.
  896. Arguments:
  897. Resource - A pointer to the resource to take offline.
  898. bForceOffline - Indicates whether the persistent state must be changed.
  899. Returns:
  900. ERROR_SUCCESS if the request is successful.
  901. ERROR_IO_PENDING if the request is pending.
  902. A Win32 error code if the request fails.
  903. --*/
  904. {
  905. DWORD status;
  906. FmpAcquireLocalResourceLock( Resource );
  907. //
  908. // If the resource is already offline, then return immediately.
  909. //
  910. if (Resource->State == ClusterResourceOffline) {
  911. //
  912. // If this is the quorum resource, make sure any reservation
  913. // threads are stopped!
  914. //
  915. if ( Resource->QuorumResource ) {
  916. FmpRmTerminateResource( Resource );
  917. }
  918. FmpReleaseLocalResourceLock( Resource );
  919. return(ERROR_SUCCESS);
  920. }
  921. //
  922. // If the resource is in a pending state, then return immediately.
  923. // FmpOffline resource checks to see if it is in OnlinePending state
  924. // and returns invalid state
  925. //
  926. if (Resource->State == ClusterResourceOfflinePending ) {
  927. FmpReleaseLocalResourceLock( Resource );
  928. return(ERROR_IO_PENDING);
  929. }
  930. //
  931. // Try to take the resource offline.
  932. //
  933. status = FmpOfflineResource( Resource, bForceOffline );
  934. //
  935. // Write the persistent state if it is forced offline
  936. //
  937. if ( bForceOffline &&
  938. ((status == ERROR_SUCCESS)||
  939. (status == ERROR_IO_PENDING))) {
  940. FmpSetResourcePersistentState( Resource, ClusterResourceOffline );
  941. }
  942. FmpReleaseLocalResourceLock( Resource );
  943. return(status);
  944. } // FmpDoOfflineResource
  945. VOID
  946. FmpSetResourcePersistentState(
  947. IN PFM_RESOURCE Resource,
  948. IN CLUSTER_RESOURCE_STATE State
  949. )
  950. /*++
  951. Routine Description:
  952. Set the persistent state of a Resource in the registry and set the
  953. PersistentState for the volatile (in-memory) resource. It is assumed
  954. that the dynamic state gets changed elsewhere depending on whether
  955. the resource online request succeeds or fails.
  956. Arguments:
  957. Resource - The resource to set the state.
  958. State - The new state for the Resource.
  959. Returns:
  960. ERROR_SUCCESS if successful.
  961. A Win32 error code on failure.
  962. Notes:
  963. The LocalResourceLock must be held.
  964. --*/
  965. {
  966. CLUSTER_RESOURCE_STATE persistentState;
  967. LPWSTR persistentStateName = CLUSREG_NAME_RES_PERSISTENT_STATE;
  968. if (!gbIsQuoResEnoughSpace)
  969. return;
  970. //
  971. // If the current state has changed, then do the work. Otherwise,
  972. // skip the effort.
  973. //
  974. if ( Resource->PersistentState != State ) {
  975. Resource->PersistentState = State;
  976. CL_ASSERT( Resource->RegistryKey != NULL );
  977. ClRtlLogPrint(LOG_NOISE,
  978. "[FM] FmpSetResourcePersistentState: Setting persistent state for resource %1!ws!...\r\n",
  979. OmObjectId(Resource));
  980. //
  981. // Set the new value, but only if it is online or offline.
  982. //
  983. if ( State == ClusterResourceOffline ) {
  984. persistentState = 0;
  985. DmSetValue( Resource->RegistryKey,
  986. persistentStateName,
  987. REG_DWORD,
  988. (LPBYTE)&persistentState,
  989. sizeof(DWORD) );
  990. } else if ( State == ClusterResourceOnline ) {
  991. persistentState = 1;
  992. DmSetValue( Resource->RegistryKey,
  993. persistentStateName,
  994. REG_DWORD,
  995. (LPBYTE)&persistentState,
  996. sizeof(DWORD) );
  997. }
  998. }
  999. } // FmpSetResourcePersistentState
  1000. void FmpCallResourceNotifyCb(
  1001. IN PFM_RESOURCE Resource,
  1002. IN CLUSTER_RESOURCE_STATE State
  1003. )
  1004. {
  1005. switch ( State ) {
  1006. case ClusterResourceOnline:
  1007. OmNotifyCb(Resource, NOTIFY_RESOURCE_POSTONLINE);
  1008. break;
  1009. case ClusterResourceOffline:
  1010. OmNotifyCb(Resource, NOTIFY_RESOURCE_POSTOFFLINE);
  1011. break;
  1012. case ClusterResourceFailed:
  1013. OmNotifyCb(Resource, NOTIFY_RESOURCE_FAILED);
  1014. break;
  1015. case ClusterResourceOnlinePending:
  1016. OmNotifyCb(Resource, NOTIFY_RESOURCE_ONLINEPENDING);
  1017. break;
  1018. case ClusterResourceOfflinePending:
  1019. OmNotifyCb(Resource, NOTIFY_RESOURCE_OFFLINEPENDING);
  1020. break;
  1021. default:
  1022. break;
  1023. }
  1024. return;
  1025. }
  1026. DWORD
  1027. FmpPropagateResourceState(
  1028. IN PFM_RESOURCE Resource,
  1029. IN CLUSTER_RESOURCE_STATE State
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. Propagates the state of the resource to other systems in the cluster.
  1034. Ideally the gQuoCritSec lock should be held when this routine is called.
  1035. This is because this routine checks the quorumresource field of the
  1036. resource
  1037. Arguments:
  1038. Resource - The resource to propagate state.
  1039. State - The new state for the resource.
  1040. Returns:
  1041. ERROR_SUCCESS if successful.
  1042. A Win32 error code on failure.
  1043. --*/
  1044. {
  1045. GUM_RESOURCE_STATE resourceState;
  1046. LPCWSTR resourceId;
  1047. DWORD resourceStateSize;
  1048. DWORD status= ERROR_SUCCESS;
  1049. BOOL bAcquiredQuoLock = FALSE;
  1050. //for quorum resource use the quorum lock for state changes
  1051. // for others use the group locks
  1052. if (Resource->QuorumResource)
  1053. {
  1054. ACQUIRE_EXCLUSIVE_LOCK(gQuoLock);
  1055. bAcquiredQuoLock = TRUE;
  1056. }
  1057. else
  1058. FmpAcquireLocalResourceLock( Resource );
  1059. ++Resource->StateSequence;
  1060. if (! FmpFMFormPhaseProcessing )
  1061. {
  1062. //
  1063. // If this is the same state, or we don't own the group
  1064. // then don't bother propagating.
  1065. //
  1066. if ( (State == Resource->State) ||
  1067. (Resource->Group->OwnerNode != NmLocalNode) ) {
  1068. goto ReleaseResourceLock;
  1069. }
  1070. //if the previous state is the online pending and this
  1071. // is called for the quorum resource, wake up all resources
  1072. // make sure that if this is called while the form phase
  1073. //processing is going on(when the quorum group is destroyed
  1074. //and recreated), that the group is not referenced
  1075. if ((Resource->QuorumResource) &&
  1076. (Resource->State==ClusterResourceOnlinePending) &&
  1077. (Resource->Group->OwnerNode == NmLocalNode) )
  1078. {
  1079. //set the state and signal
  1080. Resource->State = State;
  1081. ClRtlLogPrint(LOG_NOISE,
  1082. "[FM] FmpPropagateResourceState: signalling the ghQuoOnlineEvent\r\n");
  1083. SetEvent(ghQuoOnlineEvent);
  1084. }
  1085. }
  1086. Resource->State = State;
  1087. //
  1088. // Prepare to notify other systems.
  1089. //
  1090. resourceId = OmObjectId( Resource );
  1091. resourceState.State = State;
  1092. resourceState.PersistentState = Resource->PersistentState;
  1093. resourceState.StateSequence = Resource->StateSequence;
  1094. status = GumSendUpdateEx(GumUpdateFailoverManager,
  1095. FmUpdateResourceState,
  1096. 2,
  1097. (lstrlenW(resourceId)+1)*sizeof(WCHAR),
  1098. resourceId,
  1099. sizeof(resourceState),
  1100. &resourceState);
  1101. //
  1102. // Signal change notify event.
  1103. //
  1104. switch ( State ) {
  1105. case ClusterResourceOnline:
  1106. ClRtlLogPrint(LOG_NOISE,
  1107. "[FM] FmpPropagateResourceState: resource %1!ws! online event.\n",
  1108. OmObjectId(Resource) );
  1109. ClusterEvent(CLUSTER_EVENT_RESOURCE_ONLINE, Resource);
  1110. break;
  1111. case ClusterResourceOffline:
  1112. ClRtlLogPrint(LOG_NOISE,
  1113. "[FM] FmpPropagateResourceState: resource %1!ws! offline event.\n",
  1114. OmObjectId(Resource) );
  1115. ClusterEvent(CLUSTER_EVENT_RESOURCE_OFFLINE, Resource);
  1116. break;
  1117. case ClusterResourceFailed:
  1118. ClRtlLogPrint(LOG_NOISE,
  1119. "[FM] FmpPropagateResourceState: resource %1!ws! failed event.\n",
  1120. OmObjectId(Resource) );
  1121. ClusterEvent(CLUSTER_EVENT_RESOURCE_FAILED, Resource);
  1122. break;
  1123. case ClusterResourceOnlinePending:
  1124. case ClusterResourceOfflinePending:
  1125. ClRtlLogPrint(LOG_NOISE,
  1126. "[FM] FmpPropagateResourceState: resource %1!ws! pending event.\n",
  1127. OmObjectId(Resource) );
  1128. ClusterEvent(CLUSTER_EVENT_RESOURCE_CHANGE, Resource);
  1129. break;
  1130. default:
  1131. break;
  1132. }
  1133. ReleaseResourceLock:
  1134. if (bAcquiredQuoLock)
  1135. RELEASE_LOCK(gQuoLock);
  1136. else
  1137. FmpReleaseLocalResourceLock( Resource );
  1138. if ( status != ERROR_SUCCESS )
  1139. {
  1140. ClRtlLogPrint(LOG_UNUSUAL,
  1141. "[FM] Propagation of resource %1!ws! state %2!u! failed. Error %3!u!\n",
  1142. OmObjectId(Resource),
  1143. State,
  1144. status);
  1145. goto FnExit;
  1146. }
  1147. //if fm is not completely online we dont want to propagate group state
  1148. // This is because the quorum group is destroyed in FmFormNewClusterPhase1
  1149. // and then recreated again in FmFormNewClusterPhase2.
  1150. if (FmpFMOnline)
  1151. {
  1152. OmReferenceObject(Resource->Group);
  1153. //FmpPropagateGroupState( Resource->Group );
  1154. FmpPostWorkItem(FM_EVENT_INTERNAL_PROP_GROUP_STATE, Resource->Group, 0);
  1155. }
  1156. FnExit:
  1157. return(status);
  1158. } // FmpPropagateResourceState
  1159. VOID
  1160. FmpDestroyResource(
  1161. IN PFM_RESOURCE Resource,
  1162. IN BOOL bDeleteObjOnly
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. Destroys a resource. This basically snips a resource out of the
  1167. dependency tree.
  1168. First, any resources that depend on the specified
  1169. resource are recursively destroyed. This removes any dependencies
  1170. that other resources may have on the specified resource (i.e. all
  1171. resources "higher" in the dependency tree are destroyed).
  1172. Second, all the dependencies that the specified resource has are
  1173. removed. This entails dereferencing the provider resource (to remove
  1174. the reference that was added when the dependency was created) removing
  1175. the DEPENDENCY structure from its provider and dependent lists, and
  1176. finally freeing the DEPENDENCY storage.
  1177. If the resource is online, it is terminated. The resource monitor is
  1178. signalled to clean up and close the specified resource id.
  1179. Arguments:
  1180. FoundResource - Returns the found resource.
  1181. Resource - Supplies the current resource.
  1182. Name - Supplies the current resource's name.
  1183. Return Value:
  1184. None.
  1185. Notes:
  1186. The LocalResourceLock MUST be held! The lock is released before exit!
  1187. --*/
  1188. {
  1189. DWORD status;
  1190. DWORD i;
  1191. PLIST_ENTRY ListEntry;
  1192. PDEPENDENCY Dependency;
  1193. PPOSSIBLE_ENTRY possibleEntry;
  1194. ClRtlLogPrint(LOG_NOISE,
  1195. "[FM] DestroyResource: destroying %1!ws!\n",
  1196. OmObjectId(Resource));
  1197. //
  1198. // First, unlink this resource from the resource list.
  1199. //
  1200. //
  1201. // if the resource belongs to the quorum group, it is destroyed
  1202. // after the quorum logs are created so that it can be recreated
  1203. // dont remove it from the list then
  1204. if ((!bDeleteObjOnly))
  1205. status = OmRemoveObject( Resource );
  1206. //
  1207. // If anyone depends on this resource, destroy them first.
  1208. //
  1209. while (!IsListEmpty(&Resource->ProvidesFor)) {
  1210. ListEntry = Resource->ProvidesFor.Flink;
  1211. Dependency = CONTAINING_RECORD(ListEntry, DEPENDENCY, ProviderLinkage);
  1212. CL_ASSERT(Dependency->ProviderResource == Resource);
  1213. #if 0
  1214. FmpRemoveResourceDependency( Dependency->DependentResource,
  1215. Resource );
  1216. #endif
  1217. RemoveEntryList(&Dependency->ProviderLinkage);
  1218. RemoveEntryList(&Dependency->DependentLinkage);
  1219. //
  1220. // Dereference provider/dependent resource and free dependency storage
  1221. //
  1222. OmDereferenceObject(Dependency->ProviderResource);
  1223. OmDereferenceObject(Dependency->DependentResource);
  1224. LocalFree(Dependency);
  1225. }
  1226. //
  1227. // Remove our resource dependencies.
  1228. //
  1229. while (!IsListEmpty(&Resource->DependsOn)) {
  1230. ListEntry = RemoveHeadList(&Resource->DependsOn);
  1231. Dependency = CONTAINING_RECORD(ListEntry, DEPENDENCY, DependentLinkage);
  1232. CL_ASSERT(Dependency->DependentResource == Resource);
  1233. #if 0
  1234. FmpRemoveResourceDependency( Resource,
  1235. Dependency->ProviderResource );
  1236. #endif
  1237. RemoveEntryList(&Dependency->ProviderLinkage);
  1238. RemoveEntryList(&Dependency->DependentLinkage);
  1239. //
  1240. // Dereference provider/dependent resource and free dependency storage
  1241. //
  1242. OmDereferenceObject(Dependency->DependentResource);
  1243. OmDereferenceObject(Dependency->ProviderResource);
  1244. LocalFree(Dependency);
  1245. }
  1246. //
  1247. // Remove all entries from the possible owners list.
  1248. //
  1249. while ( !IsListEmpty(&Resource->PossibleOwners) ) {
  1250. ListEntry = RemoveHeadList(&Resource->PossibleOwners);
  1251. possibleEntry = CONTAINING_RECORD( ListEntry,
  1252. POSSIBLE_ENTRY,
  1253. PossibleLinkage );
  1254. OmDereferenceObject( possibleEntry->PossibleNode );
  1255. LocalFree(possibleEntry);
  1256. }
  1257. if (!bDeleteObjOnly)
  1258. {
  1259. //
  1260. // Close the resource's registry key.
  1261. //
  1262. DmRundownList( &Resource->DmRundownList );
  1263. if (Resource->RegistryKey != NULL) {
  1264. DmCloseKey( Resource->RegistryKey );
  1265. Resource->RegistryKey = NULL;
  1266. }
  1267. //
  1268. // Decrement resource type reference.
  1269. //
  1270. if ( Resource->Type != NULL ) {
  1271. OmDereferenceObject( Resource->Type );
  1272. Resource->Type = NULL;
  1273. }
  1274. // Let the worker thread peform the 'last' dereference
  1275. FmpPostWorkItem(FM_EVENT_RESOURCE_DELETED, Resource, 0);
  1276. FmpReleaseLocalResourceLock( Resource );
  1277. }
  1278. else
  1279. {
  1280. //the resource being destroyed is from the quorum group
  1281. //This is done at initialization
  1282. FmpReleaseLocalResourceLock( Resource );
  1283. // make sure that all resources except the quorum resource
  1284. // are created completely in the second phase of initialization
  1285. //decrement its ref count here, this is the last ref
  1286. //SS:: we dont use FM_EVENT_RESOURCE_DELETED here
  1287. //since we want this done synchronously before phase 2 is
  1288. //complete
  1289. OmDereferenceObject(Resource);
  1290. }
  1291. //ss: for now we dont use it, so dont delete it
  1292. //DeleteCriticalSection(&Resource->Lock);
  1293. ClRtlLogPrint(LOG_NOISE,
  1294. "[FM] FmpDestroyResource Exit.\n");
  1295. return;
  1296. } // FmpDestroyResource
  1297. ///////////////////////////////////////////////////////////////////////////
  1298. //
  1299. // Initialization Routines
  1300. //
  1301. ///////////////////////////////////////////////////////////////////////////
  1302. BOOL
  1303. FmDependentResource(
  1304. IN PFM_RESOURCE Resource,
  1305. IN PFM_RESOURCE DependentResource,
  1306. IN BOOL ImmediateOnly
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. Returns indication of whether a resource is a dependent of another
  1311. resource.
  1312. Arguments:
  1313. Resource - The resource to scan if it depends on the dependent resource.
  1314. DependentResource - The dependent resource to check on.
  1315. ImmediateOnly - Specifies whether only immediate dependencies should be
  1316. checked. If this is FALSE, this routine recursively checks all
  1317. dependents.
  1318. Returns:
  1319. TRUE - The the resource does depend on the dependent resource.
  1320. FALSE - The resource does not depend on the dependent resource.
  1321. --*/
  1322. {
  1323. PLIST_ENTRY listEntry;
  1324. PDEPENDENCY dependency;
  1325. BOOL result = FALSE;
  1326. FmpAcquireLocalResourceLock( Resource );
  1327. listEntry = Resource->DependsOn.Flink;
  1328. while ( listEntry != &Resource->DependsOn ) {
  1329. dependency = CONTAINING_RECORD( listEntry,
  1330. DEPENDENCY,
  1331. DependentLinkage );
  1332. if ( dependency->ProviderResource == DependentResource ) {
  1333. result = TRUE;
  1334. break;
  1335. } else {
  1336. if (!ImmediateOnly) {
  1337. if (FmDependentResource(dependency->ProviderResource,
  1338. DependentResource,
  1339. FALSE)) {
  1340. result = TRUE;
  1341. break;
  1342. }
  1343. }
  1344. }
  1345. listEntry = listEntry->Flink;
  1346. } // while
  1347. FmpReleaseLocalResourceLock( Resource );
  1348. return(result);
  1349. } // FmpDependentResource
  1350. DWORD
  1351. FmpAddPossibleEntry(
  1352. IN PFM_RESOURCE Resource,
  1353. IN PNM_NODE Node
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Creates a new possible node entry and adds it to a resource's list.
  1358. If the node is already in the resource's list, it will not be added
  1359. again.
  1360. Arguments:
  1361. Resource - Supplies the resource whose node list is to be updated.
  1362. Node - Supplies the node to be added to the resource's list.
  1363. Return Value:
  1364. ERROR_SUCCESS if successful.
  1365. Win32 error otherwise.
  1366. --*/
  1367. {
  1368. PLIST_ENTRY ListEntry;
  1369. PPOSSIBLE_ENTRY PossibleEntry;
  1370. //
  1371. // First check to see if the node is already in the possible owners list.
  1372. //
  1373. ListEntry = Resource->PossibleOwners.Flink;
  1374. while (ListEntry != &Resource->PossibleOwners) {
  1375. PossibleEntry = CONTAINING_RECORD( ListEntry,
  1376. POSSIBLE_ENTRY,
  1377. PossibleLinkage );
  1378. if (PossibleEntry->PossibleNode == Node) {
  1379. //
  1380. // Found a match, it's already here, so return
  1381. // success.
  1382. //
  1383. return(ERROR_SUCCESS);
  1384. }
  1385. ListEntry = ListEntry->Flink;
  1386. }
  1387. ClRtlLogPrint(LOG_NOISE,
  1388. "[FM] FmpAddPossibleEntry: adding node %1!ws! as possible host for resource %2!ws!.\n",
  1389. OmObjectId(Node),
  1390. OmObjectId(Resource));
  1391. PossibleEntry = LocalAlloc(LMEM_FIXED, sizeof(POSSIBLE_ENTRY));
  1392. if (PossibleEntry == NULL) {
  1393. ClRtlLogPrint(LOG_CRITICAL,
  1394. "[FM] FmpAddPossibleEntry failed to allocated PossibleEntry\n");
  1395. return(ERROR_NOT_ENOUGH_MEMORY);
  1396. }
  1397. OmReferenceObject(Node);
  1398. PossibleEntry->PossibleNode = Node;
  1399. InsertTailList( &Resource->PossibleOwners,
  1400. &PossibleEntry->PossibleLinkage );
  1401. return(ERROR_SUCCESS);
  1402. }
  1403. DWORD
  1404. FmpAddPossibleNode(
  1405. IN PFM_RESOURCE Resource,
  1406. IN PNM_NODE Node
  1407. )
  1408. /*++
  1409. Routine Description:
  1410. Adds a node to the resource's list of possible nodes.
  1411. The resource lock must be held.
  1412. Arguments:
  1413. Resource - Supplies the resource whose list of nodes is to be updated
  1414. Node - Supplies the node to add to the specified resource's list.
  1415. Return Value:
  1416. ERROR_SUCCESS if successful
  1417. Win32 error otherwise
  1418. --*/
  1419. {
  1420. HDMKEY hGroup;
  1421. DWORD Status;
  1422. //
  1423. // Allocate the new possible node entry and add it to the list.
  1424. //
  1425. Status = FmpAddPossibleEntry(Resource, Node);
  1426. if (Status != ERROR_SUCCESS) {
  1427. return(Status);
  1428. }
  1429. //
  1430. // Need to check the group list to see if the specified node
  1431. // can be added to the preferred list now. The easiest way
  1432. // to do that is to simply recreate the entire preferred list,
  1433. // then reprune.
  1434. //
  1435. hGroup = DmOpenKey( DmGroupsKey,
  1436. OmObjectId(Resource->Group),
  1437. KEY_READ );
  1438. if (hGroup == NULL) {
  1439. Status = GetLastError();
  1440. ClRtlLogPrint(LOG_UNUSUAL,
  1441. "[FM] FmpAddPossibleNode failed to open group %1!ws! status %2!d!\n",
  1442. OmObjectId(Resource->Group),
  1443. Status);
  1444. return(Status);
  1445. }
  1446. Status = FmpQueryGroupNodes(Resource->Group,
  1447. hGroup);
  1448. CL_ASSERT(Status == ERROR_SUCCESS);
  1449. if (Status == ERROR_SUCCESS) {
  1450. FmpPruneGroupOwners(Resource->Group);
  1451. }
  1452. DmCloseKey(hGroup);
  1453. return(Status);
  1454. } // FmpAddPossibleNode
  1455. DWORD
  1456. FmpRemovePossibleNode(
  1457. IN PFM_RESOURCE Resource,
  1458. IN PNM_NODE Node,
  1459. IN BOOL RemoveQuorum
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. Removes a node from the resource's list of possible nodes.
  1464. The resource lock must be held.
  1465. Arguments:
  1466. Resource - Supplies the resource whose list of nodes is to be updated
  1467. Node - Supplies the node to be removed from the specified resource's list.
  1468. RemoveQuorum - TRUE if we can remove node from quorum device.
  1469. FALSE otherwise.
  1470. Return Value:
  1471. ERROR_SUCCESS if successful
  1472. Win32 error otherwise
  1473. --*/
  1474. {
  1475. PLIST_ENTRY ListEntry;
  1476. PPOSSIBLE_ENTRY PossibleEntry;
  1477. DWORD Status = ERROR_CLUSTER_NODE_NOT_FOUND;
  1478. //
  1479. // If the resource is currently online on the node to be removed,
  1480. // fail the call.
  1481. //
  1482. if ((Resource->Group->OwnerNode == Node) &&
  1483. (Resource->State == ClusterResourceOnline)) {
  1484. return(ERROR_INVALID_STATE);
  1485. }
  1486. //
  1487. // If it is NOT okay to remove this node from the quorum device,
  1488. // and this is the quorum device, then fail the request.
  1489. //
  1490. if ( !RemoveQuorum &&
  1491. Resource->QuorumResource) {
  1492. return(ERROR_INVALID_OPERATION_ON_QUORUM);
  1493. }
  1494. //
  1495. // Find the possible entry on the resource's list.
  1496. //
  1497. ListEntry = Resource->PossibleOwners.Flink;
  1498. while (ListEntry != &Resource->PossibleOwners) {
  1499. PossibleEntry = CONTAINING_RECORD( ListEntry,
  1500. POSSIBLE_ENTRY,
  1501. PossibleLinkage );
  1502. ListEntry = ListEntry->Flink;
  1503. if (PossibleEntry->PossibleNode == Node) {
  1504. //
  1505. // Found a match, remove it from the list.
  1506. //
  1507. RemoveEntryList(&PossibleEntry->PossibleLinkage);
  1508. OmDereferenceObject(PossibleEntry->PossibleNode);
  1509. LocalFree(PossibleEntry);
  1510. //
  1511. // Now prune the containing group. This is a little bit
  1512. // of overkill, if we were smarter, we could just
  1513. // remove the node from the preferred list directly.
  1514. //
  1515. FmpPrunePreferredList(Resource);
  1516. Status = ERROR_SUCCESS;
  1517. break;
  1518. }
  1519. }
  1520. return(Status);
  1521. } // FmpRemovePossibleNode
  1522. DWORD
  1523. FmpRemoveResourceDependency(
  1524. HLOCALXSACTION hXsaction,
  1525. IN PFM_RESOURCE Resource,
  1526. IN PFM_RESOURCE DependsOn
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. Removes a dependency relationship to a given resource. Both
  1531. resources must be in the same group.
  1532. Arguments:
  1533. Resource - Supplies the resource which is dependent.
  1534. DependsOn - Supplies the resource that hResource depends on.
  1535. Return Value:
  1536. ERROR_SUCCESS if successful.
  1537. Win32 error code otherwise.
  1538. --*/
  1539. {
  1540. DWORD status;
  1541. HDMKEY resKey = NULL;
  1542. //
  1543. // If the resources are not in the same group, fail the
  1544. // call. Also fail if some one tries to make a resource
  1545. // dependent upon itself.
  1546. //
  1547. if ((Resource->Group != DependsOn->Group) ||
  1548. (Resource == DependsOn)) {
  1549. return(ERROR_INVALID_PARAMETER);
  1550. }
  1551. //
  1552. // Remove the dependency from the registry database.
  1553. //
  1554. resKey = DmOpenKey(DmResourcesKey,
  1555. OmObjectId(Resource),
  1556. KEY_READ | KEY_SET_VALUE);
  1557. if (resKey == NULL)
  1558. {
  1559. status = GetLastError();
  1560. CL_LOGFAILURE(status);
  1561. goto FnExit;
  1562. }
  1563. else
  1564. {
  1565. status = DmLocalRemoveFromMultiSz(hXsaction,
  1566. resKey,
  1567. CLUSREG_NAME_RES_DEPENDS_ON,
  1568. OmObjectId(DependsOn));
  1569. }
  1570. FnExit:
  1571. if ( resKey ) {
  1572. DmCloseKey(resKey);
  1573. }
  1574. return(status);
  1575. } // FmpRemoveResourceDependency
  1576. DWORD
  1577. FmpChangeResourceGroup(
  1578. IN PFM_RESOURCE pResource,
  1579. IN PFM_GROUP pNewGroup
  1580. )
  1581. /*++
  1582. Routine Description:
  1583. Moves a resource from one group to another.
  1584. Arguments:
  1585. pResource - Supplies the resource to move.
  1586. pNewGroup - Supplies the new group that the resource should be in.
  1587. Return Value:
  1588. ERROR_SUCCESS if successful
  1589. Win32 error code otherwise.
  1590. --*/
  1591. {
  1592. DWORD dwBufSize;
  1593. LPCWSTR pszResourceId;
  1594. DWORD dwResourceLen;
  1595. LPCWSTR pszGroupId;
  1596. DWORD dwGroupLen;
  1597. DWORD dwStatus;
  1598. PGUM_CHANGE_GROUP pGumChange;
  1599. // we need to validate here as well
  1600. // this is called by the server side
  1601. // this will help avoid a gum call if things have changed
  1602. // since the request started from the originator
  1603. // and got to the server
  1604. //
  1605. // Check if we're moving to same group.
  1606. //
  1607. if (pResource->Group == pNewGroup) {
  1608. dwStatus = ERROR_ALREADY_EXISTS;
  1609. goto FnExit;
  1610. }
  1611. //
  1612. // For now... both Groups must be owned by the same node.
  1613. //
  1614. if ( pResource->Group->OwnerNode != pNewGroup->OwnerNode ) {
  1615. dwStatus = ERROR_HOST_NODE_NOT_GROUP_OWNER;
  1616. goto FnExit;
  1617. }
  1618. pszResourceId = OmObjectId(pResource);
  1619. dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
  1620. pszGroupId = OmObjectId(pNewGroup);
  1621. dwGroupLen = (lstrlenW(pszGroupId)+1)*sizeof(WCHAR);
  1622. dwBufSize = sizeof(GUM_CHANGE_GROUP) - sizeof(WCHAR) + dwResourceLen + dwGroupLen;
  1623. pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize);
  1624. if (pGumChange == NULL) {
  1625. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  1626. goto FnExit;
  1627. }
  1628. pGumChange->ResourceIdLen = dwResourceLen;
  1629. CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen);
  1630. CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen,
  1631. pszGroupId,
  1632. dwGroupLen);
  1633. dwStatus = GumSendUpdate(GumUpdateFailoverManager,
  1634. FmUpdateChangeGroup,
  1635. dwBufSize,
  1636. pGumChange);
  1637. LocalFree(pGumChange);
  1638. FnExit:
  1639. return(dwStatus);
  1640. }// FmpChangeResourceGroup
  1641. DWORD
  1642. FmpClusterEventPropHandler(
  1643. IN PFM_RESOURCE pResource
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. Post a worker item to process a cluster name change.
  1648. Arguments:
  1649. pResource - pointer to the resouce which is affected by the cluster
  1650. property change.
  1651. Return Value:
  1652. ERROR_SUCCESS if successful.
  1653. A Win32 error code on failure.
  1654. --*/
  1655. {
  1656. PFM_RESTYPE pResType;
  1657. DWORD dwError=ERROR_SUCCESS;
  1658. pResType = pResource->Type;
  1659. if ((pResource->ExFlags & CLUS_FLAG_CORE) &&
  1660. ( !lstrcmpiW(OmObjectId(pResType), CLUS_RESTYPE_NAME_NETNAME)))
  1661. {
  1662. FmResourceControl(pResource, NmLocalNode,
  1663. CLUSCTL_RESOURCE_CLUSTER_NAME_CHANGED, NULL, 0, NULL, 0, NULL, NULL);
  1664. }
  1665. return (dwError);
  1666. } // FmpClusterEventPropHandler
  1667. BOOL
  1668. FmpEnumResourceNodeEvict(
  1669. IN PVOID Context1,
  1670. IN PVOID Context2,
  1671. IN PVOID Object,
  1672. IN LPCWSTR Name
  1673. )
  1674. /*++
  1675. Routine Description:
  1676. Resource enumeration callback for removing node references when
  1677. a node is evicted.
  1678. Arguments:
  1679. Context1 - Supplies the node that is being evicted.
  1680. Context2 - not used
  1681. Object - Supplies a pointer to the resource object
  1682. Name - Supplies the resource's object name.
  1683. Return Value:
  1684. TRUE to continue enumeration
  1685. --*/
  1686. {
  1687. PFM_RESOURCE Resource = (PFM_RESOURCE)Object;
  1688. PNM_NODE Node = (PNM_NODE)Context1;
  1689. PLIST_ENTRY listEntry;
  1690. PPOSSIBLE_ENTRY possibleEntry;
  1691. ClRtlLogPrint(LOG_NOISE,
  1692. "[FM] EnumResourceNodeEvict: Removing references to node %1!ws! from resource %2!ws!\n",
  1693. OmObjectId(Node),
  1694. OmObjectId(Resource));
  1695. FmpAcquireLocalResourceLock(Resource);
  1696. FmpRemovePossibleNode(Resource, Node, TRUE);
  1697. FmpReleaseLocalResourceLock(Resource);
  1698. //
  1699. // Notify the resource of the removal of the node.
  1700. //
  1701. FmpRmResourceControl( Resource,
  1702. CLUSCTL_RESOURCE_EVICT_NODE,
  1703. (PUCHAR)OmObjectId(Node),
  1704. ((lstrlenW(OmObjectId(Node)) + 1) * sizeof(WCHAR)),
  1705. NULL,
  1706. 0,
  1707. NULL,
  1708. NULL );
  1709. // Ignore status return
  1710. ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, Resource );
  1711. return(TRUE);
  1712. } // FmpEnumResourceNodeEvict
  1713. DWORD
  1714. FmpPrepareQuorumResChange(
  1715. IN PFM_RESOURCE pNewQuoRes,
  1716. IN LPCWSTR lpszQuoLogPath,
  1717. IN DWORD dwMaxQuoLogSize
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. This routine prepares for a quorum resource change operation.
  1722. Arguments:
  1723. pNewQuoRes - pointer to the new quorum resource.
  1724. lpszQuoLogPath - pointer to the quorum log path string name.
  1725. dwMaxQuoLogSize - the maximum size of the quorum log path string.
  1726. --*/
  1727. {
  1728. CL_ASSERT(pNewQuoRes->Group->OwnerNode == NmLocalNode);
  1729. return(DmPrepareQuorumResChange(pNewQuoRes, lpszQuoLogPath, dwMaxQuoLogSize));
  1730. } // FmpPrepareQuorumResChange
  1731. DWORD
  1732. FmpCompleteQuorumResChange(
  1733. IN LPCWSTR lpszOldQuoResId,
  1734. IN LPCWSTR lpszQuoLogPath
  1735. )
  1736. /*++
  1737. Routine Description:
  1738. This routine is called if the new quorum log path is not the same as the old
  1739. quorum log path. This completes the change of quorum resource by deleting the old
  1740. quorum log files and creating a tompstone for them. A node that tries to do a form
  1741. with this as the quorum resource is prevented and has to do a join to get the location
  1742. of the new quorum resource and quorum log file.
  1743. Arguments:
  1744. pOldQuoRes - pointer to the new quorum resource.
  1745. lpszOldQuoLogPath - pointer to the quorum log path string name.
  1746. dwMaxQuoLogSize - the maximum size of the quorum log path string.
  1747. --*/
  1748. {
  1749. return(DmCompleteQuorumResChange(lpszOldQuoResId, lpszQuoLogPath));
  1750. } // FmpCompleteQuorumResChange
  1751. VOID
  1752. FmpResourceLastReference(
  1753. IN PFM_RESOURCE Resource
  1754. )
  1755. /*++
  1756. Routine Description:
  1757. Last dereference to resource object processing routine.
  1758. All cleanup for a resource should really be done here!
  1759. Arguments:
  1760. Resource - pointer the resource being removed.
  1761. Return Value:
  1762. None.
  1763. --*/
  1764. {
  1765. if ( Resource->DebugPrefix != NULL )
  1766. LocalFree(Resource->DebugPrefix);
  1767. if (Resource->Dependencies)
  1768. LocalFree(Resource->Dependencies);
  1769. if ( Resource->Group ) {
  1770. OmDereferenceObject(Resource->Group);
  1771. }
  1772. if (Resource->Type)
  1773. OmDereferenceObject(Resource->Type);
  1774. return;
  1775. } // FmpResourceLastReference
  1776. BOOL
  1777. FmpCheckNetworkDependencyWorker(
  1778. IN LPCWSTR DependentNetwork,
  1779. OUT PBOOL FoundDependency,
  1780. IN PFM_RESOURCE Resource,
  1781. IN LPCWSTR Name
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. Enumeration callback routine for finding an IP Address resource
  1786. and checking its dependency on given network guid.
  1787. Arguments:
  1788. DependentNetwork - The GUID of the network to check for a dependency.
  1789. FoundDependency - Returns TRUE if a dependency is found.
  1790. Resource - Supplies the current resource.
  1791. Name - Supplies the current resource's name.
  1792. Return Value:
  1793. TRUE - to continue searching
  1794. FALSE - to stop the search. The matching resource is returned in
  1795. *FoundResource
  1796. Notes:
  1797. The IP Address resource's parameters are searched directly by this
  1798. routine. Fetching them from the resource itself causes a deadlock.
  1799. This routine is called by the NM from within a global udpate
  1800. handler. The resource would have to call back into the cluster registry
  1801. routines, which would deadlock over the GUM lock.
  1802. --*/
  1803. {
  1804. BOOL returnValue = TRUE;
  1805. if ( lstrcmpiW(
  1806. OmObjectId(Resource->Type),
  1807. CLUS_RESTYPE_NAME_IPADDR
  1808. ) == 0
  1809. )
  1810. {
  1811. LPCWSTR resourceId = OmObjectId(Resource);
  1812. DWORD status;
  1813. HDMKEY resourceKey = DmOpenKey(DmResourcesKey, resourceId, KEY_READ);
  1814. if (resourceKey != NULL) {
  1815. HDMKEY paramsKey = DmOpenKey(
  1816. resourceKey,
  1817. L"Parameters",
  1818. KEY_READ
  1819. );
  1820. if (paramsKey != NULL) {
  1821. LPWSTR networkId = NULL;
  1822. DWORD valueLength = 0, valueSize = 0;
  1823. status = DmQueryString(
  1824. paramsKey,
  1825. L"Network",
  1826. REG_SZ,
  1827. &networkId,
  1828. &valueLength,
  1829. &valueSize
  1830. );
  1831. if (status == ERROR_SUCCESS) {
  1832. if ( lstrcmpiW( networkId, DependentNetwork ) == 0 ) {
  1833. *FoundDependency = TRUE;
  1834. returnValue = FALSE;
  1835. }
  1836. LocalFree(networkId);
  1837. }
  1838. else {
  1839. ClRtlLogPrint(LOG_WARNING,
  1840. "[NM] Query of Network value failed for ip addr resource %1!ws!, status %2!u!.\n",
  1841. resourceId,
  1842. status
  1843. );
  1844. }
  1845. DmCloseKey(paramsKey);
  1846. }
  1847. else {
  1848. status = GetLastError();
  1849. ClRtlLogPrint(LOG_WARNING,
  1850. "[FM] Failed to open params key for resource %1!ws!, status %2!u!\n",
  1851. resourceId,
  1852. status
  1853. );
  1854. }
  1855. DmCloseKey(resourceKey);
  1856. }
  1857. else {
  1858. status = GetLastError();
  1859. ClRtlLogPrint(LOG_WARNING,
  1860. "[FM] Failed to open key for resource %1!ws!, status %2!u!\n",
  1861. resourceId,
  1862. status
  1863. );
  1864. }
  1865. }
  1866. return(returnValue);
  1867. } // FmpCheckNetworkDependencyWorker
  1868. //lock must be held when this routine is called
  1869. DWORD FmpChangeResourceNode(
  1870. IN PFM_RESOURCE Resource,
  1871. IN LPCWSTR NodeId,
  1872. IN BOOL Add
  1873. )
  1874. {
  1875. PGUM_CHANGE_POSSIBLE_NODE GumChange;
  1876. LPCWSTR ResourceId;
  1877. DWORD ResourceLen;
  1878. DWORD NodeLen;
  1879. DWORD BufSize;
  1880. DWORD Status;
  1881. PLIST_ENTRY pListEntry;
  1882. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry = NULL;
  1883. BOOL bNodeSupportsResType = FALSE;
  1884. BOOL bRecalc = TRUE;
  1885. PPOSSIBLE_ENTRY PossibleEntry;
  1886. PNM_NODE pNode = NULL;
  1887. if ( Resource->QuorumResource ) {
  1888. Status = ERROR_INVALID_OPERATION_ON_QUORUM;
  1889. goto FnExit;
  1890. }
  1891. //
  1892. // We can't allow the owner node to be removed if the state
  1893. // of the resource or the group is not offline or failed.
  1894. //
  1895. if ( !Add &&
  1896. (NodeId == OmObjectId(NmLocalNode)) &&
  1897. (((Resource->State != ClusterResourceOffline) &&
  1898. (Resource->State != ClusterResourceFailed)) ||
  1899. (FmpGetGroupState( Resource->Group, TRUE ) != ClusterGroupOffline)) ) {
  1900. Status = ERROR_INVALID_STATE;
  1901. goto FnExit;
  1902. }
  1903. //make sure the node is on the list of possible nodes for this
  1904. // resource type
  1905. if (Add)
  1906. {
  1907. //if it is already on the list, return an error and dont
  1908. //send a gum update call
  1909. pNode = OmReferenceObjectById(ObjectTypeNode, NodeId);
  1910. pListEntry = Resource->PossibleOwners.Flink;
  1911. while (pListEntry != &Resource->PossibleOwners) {
  1912. PossibleEntry = CONTAINING_RECORD( pListEntry,
  1913. POSSIBLE_ENTRY,
  1914. PossibleLinkage );
  1915. if (PossibleEntry->PossibleNode == pNode) {
  1916. //
  1917. // Found a match, fail the duplicate add. Note that
  1918. // we must fail here, not succeed, so that the API
  1919. // layer knows not to add a duplicate to the registry.
  1920. //
  1921. Status = ERROR_OBJECT_ALREADY_EXISTS;
  1922. goto FnExit;
  1923. }
  1924. pListEntry = pListEntry->Flink;
  1925. }
  1926. ChkResTypeList:
  1927. pListEntry = &(Resource->Type->PossibleNodeList);
  1928. for (pListEntry = pListEntry->Flink;
  1929. pListEntry != &(Resource->Type->PossibleNodeList);
  1930. pListEntry = pListEntry->Flink)
  1931. {
  1932. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  1933. PossibleLinkage);
  1934. if (!lstrcmpW(OmObjectId(pResTypePosEntry->PossibleNode), NodeId))
  1935. {
  1936. bNodeSupportsResType = TRUE;
  1937. break;
  1938. }
  1939. }
  1940. if (!bNodeSupportsResType && bRecalc)
  1941. {
  1942. //if th node is not found, recalc again and retry..since then the
  1943. //dll might have been copied to this node
  1944. FmpSetPossibleNodeForResType(OmObjectId(Resource->Type), TRUE);
  1945. bRecalc = FALSE;
  1946. goto ChkResTypeList;
  1947. }
  1948. if (!bNodeSupportsResType)
  1949. {
  1950. Status = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
  1951. goto FnExit;
  1952. }
  1953. }
  1954. ResourceId = OmObjectId(Resource);
  1955. ResourceLen = (lstrlenW(ResourceId)+1)*sizeof(WCHAR);
  1956. NodeLen = (lstrlenW(NodeId)+1)*sizeof(WCHAR);
  1957. BufSize = sizeof(GUM_CHANGE_POSSIBLE_NODE) - sizeof(WCHAR) + ResourceLen + NodeLen;
  1958. GumChange = LocalAlloc(LMEM_FIXED, BufSize);
  1959. if (GumChange == NULL) {
  1960. CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
  1961. Status = ERROR_NOT_ENOUGH_MEMORY;
  1962. goto FnExit;
  1963. }
  1964. GumChange->ResourceIdLen = ResourceLen;
  1965. CopyMemory(GumChange->ResourceId, ResourceId, ResourceLen);
  1966. CopyMemory((PCHAR)GumChange->ResourceId + ResourceLen,
  1967. NodeId,
  1968. NodeLen);
  1969. Status = GumSendUpdate(GumUpdateFailoverManager,
  1970. Add ? FmUpdateAddPossibleNode : FmUpdateRemovePossibleNode,
  1971. BufSize,
  1972. GumChange);
  1973. LocalFree(GumChange);
  1974. FnExit:
  1975. if (pNode)
  1976. OmDereferenceObject(pNode);
  1977. return(Status);
  1978. }
  1979. BOOL
  1980. FmpCheckNetworkDependency(
  1981. IN LPCWSTR DependentNetwork
  1982. )
  1983. /*++
  1984. Routine Description:
  1985. Checks for an IP Address resource that may be dependent on the given
  1986. Network.
  1987. Arguments:
  1988. DependentNetwork - the dependent network to check for.
  1989. Returns:
  1990. TRUE - if an IP Address depends on the given network.
  1991. FALSE otherwise.
  1992. --*/
  1993. {
  1994. BOOL dependent = FALSE;
  1995. OmEnumObjects(ObjectTypeResource,
  1996. (OM_ENUM_OBJECT_ROUTINE)FmpCheckNetworkDependencyWorker,
  1997. (PVOID)DependentNetwork,
  1998. &dependent);
  1999. return(dependent);
  2000. } // FmpCheckNetworkDependency
  2001. /****
  2002. @func DWORD | FmpFixupPossibleNodesForResources| This fixes the possible
  2003. node information for a resource based on whether this node
  2004. supports the given resource type.
  2005. @parm IN BOOL| bJoin | If this node is joining, bJoin is set to TRUE.
  2006. @comm This routine iterates thru all the resources in a system and fixes
  2007. their possible node information. If this node is not on the possible
  2008. node list for the resource type corresponding to the resource, it
  2009. is also removed from the possible node list for the resource.
  2010. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2011. @xref <f FmpEnumFixupPossibleNodeForResource>
  2012. ****/
  2013. DWORD
  2014. FmpFixupPossibleNodesForResources(
  2015. BOOL bJoin
  2016. )
  2017. {
  2018. DWORD dwStatus=ERROR_SUCCESS;
  2019. ClRtlLogPrint(LOG_NOISE,"[FM] FmpFixupPossibleNodesForResources Entry.\n");
  2020. //
  2021. // Fix up all resources's possible node list information
  2022. //
  2023. OmEnumObjects( ObjectTypeResource,
  2024. FmpEnumFixupPossibleNodesForResource,
  2025. NULL,
  2026. NULL);
  2027. ClRtlLogPrint(LOG_NOISE,"[FM] FmpFixupPossibleNodesForResources Exit\r\n");
  2028. return(dwStatus);
  2029. } // FmpFixupPossibleNodesForResources
  2030. /****
  2031. @func DWORD | FmpEnumFixupPossibleNodesForResource | This is the enumeration
  2032. callback for every resource type to fix the possible node
  2033. information related with it.
  2034. @parm IN PVOID | pContext1 | Not used.
  2035. @parm IN PVOID | pContext2 | Not Used.
  2036. @parm IN PFM_RESTYPE | pResType | Pointer to the resource type object.
  2037. @parm IN LPCWSTR | pszResTypeName | The name of the resource type.
  2038. @comm This routine iterates thru all the resources in a system and fixes
  2039. their possible node information. If this node is not on the possible
  2040. node list for the resource type corresponding to the resource, it
  2041. is also removed from the possible node list for the resource.
  2042. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2043. @xref <f FmpFixupPossibleNodesForResources>
  2044. ****/
  2045. BOOL
  2046. FmpEnumFixupPossibleNodesForResource(
  2047. IN PVOID pContext1,
  2048. IN PVOID pContext2,
  2049. IN PFM_RESOURCE pResource,
  2050. IN LPCWSTR pszResName
  2051. )
  2052. {
  2053. //if we are on the possible node list for the
  2054. //resource but not for the resource type, remove it
  2055. //from the possible node for the resource as well.
  2056. //We do this because the join logic adds all nodes
  2057. //as possible owners for a resource and we have
  2058. //the rolling upgrade requirements - hence the fixups
  2059. //have to be made later on
  2060. if ((FmpInPossibleListForResource(pResource, NmLocalNode)) &&
  2061. !(FmpInPossibleListForResType(pResource->Type, NmLocalNode)))
  2062. {
  2063. //if we dont support this resource type, make sure it is not on the possible node
  2064. //list for a resource of this type
  2065. ClRtlLogPrint(LOG_NOISE,
  2066. "[FM] FmpEnumFixupPossibleNode:remove local node for resource %1!ws!\r\n",
  2067. OmObjectId(pResource));
  2068. //we send a gum update to remove it from all nodes
  2069. FmChangeResourceNode(pResource, NmLocalNode, FALSE);
  2070. }
  2071. //we add ourselves on the list only on a fresh install
  2072. //not on an upgrade
  2073. //csfirst run is also true on an upgrade, hence we need to
  2074. //check that csupgrade is false
  2075. if ((!FmpInPossibleListForResource(pResource, NmLocalNode)) &&
  2076. (FmpInPossibleListForResType(pResource->Type, NmLocalNode))
  2077. && CsFirstRun && !CsUpgrade)
  2078. {
  2079. //if we support a resource of this type, but we are not on the possible
  2080. //list for this resource, then add the local node to the possible list
  2081. //this may happen because on a setup join the other nodes may not
  2082. //add us because the possible node list exists. The possible node list
  2083. //may exist either because the user set it or we internally set it due
  2084. //to non availability of this resource type dll on one of the nodes
  2085. //Note that irrespective of whether the user had set the possible list
  2086. //or we set it internally, we always add a new node that joins
  2087. //to the possible node list of resources that are supported.
  2088. ClRtlLogPrint(LOG_NOISE,
  2089. "[FM] FmpEnumFixupPossibleNode:add local node for resource %1!ws!\r\n",
  2090. OmObjectId(pResource));
  2091. //we send a gum update to add it from all nodes
  2092. FmChangeResourceNode(pResource, NmLocalNode, TRUE);
  2093. }
  2094. //continue enumeration
  2095. return (TRUE);
  2096. }
  2097. DWORD FmpCleanupPossibleNodeList(
  2098. IN PFM_RESOURCE pResource)
  2099. {
  2100. PLIST_ENTRY pListEntry;
  2101. PPOSSIBLE_ENTRY pPossibleEntry;
  2102. DWORD dwStatus = ERROR_SUCCESS;
  2103. //for all possible nodes for this resource, check if the resource type
  2104. //supports it. If it doesnt, then remove that node from the in memory list
  2105. pListEntry = pResource->PossibleOwners.Flink;
  2106. while (pListEntry != &pResource->PossibleOwners)
  2107. {
  2108. //get the possible entry at this link
  2109. pPossibleEntry = CONTAINING_RECORD( pListEntry,
  2110. POSSIBLE_ENTRY,
  2111. PossibleLinkage );
  2112. //save the pointer to the next link
  2113. pListEntry = pListEntry->Flink;
  2114. if (!FmpInPossibleListForResType(pResource->Type,
  2115. pPossibleEntry->PossibleNode))
  2116. {
  2117. ClRtlLogPrint(LOG_NOISE,
  2118. "[FM] FmpCleanupPossibleNodeList:remove local node %1!u! for resource %2!ws!\r\n",
  2119. NmGetNodeId(pPossibleEntry->PossibleNode), OmObjectId(pResource));
  2120. FmChangeResourceNode(pResource, pPossibleEntry->PossibleNode,
  2121. FALSE);
  2122. }
  2123. }
  2124. return (dwStatus);
  2125. }
  2126. /****
  2127. @func DWORD | FmpInPossibleListForResource| This checks if a given node
  2128. is in the possible list of nodes for a resource.
  2129. @parm IN PFM_RESOURCE | pResource | A pointer to the the resource.
  2130. @parm IN PNM_NODE | pNode | A pointer to the node object.
  2131. @comm This routine check if a node is in the list of possible nodes
  2132. for this resource.
  2133. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2134. @xref <f FmpInPossibleListForResType>
  2135. ****/
  2136. BOOL
  2137. FmpInPossibleListForResource(
  2138. IN PFM_RESOURCE pResource,
  2139. IN PNM_NODE pNode
  2140. )
  2141. {
  2142. PLIST_ENTRY plistEntry;
  2143. PPOSSIBLE_ENTRY pPossibleEntry;
  2144. //see if this node is on the possible node list for the resource
  2145. for ( plistEntry = pResource->PossibleOwners.Flink;
  2146. plistEntry != &(pResource->PossibleOwners);
  2147. plistEntry = plistEntry->Flink ) {
  2148. pPossibleEntry = CONTAINING_RECORD( plistEntry,
  2149. POSSIBLE_ENTRY,
  2150. PossibleLinkage );
  2151. if ( pPossibleEntry->PossibleNode == pNode ) {
  2152. return(TRUE);
  2153. }
  2154. }
  2155. return(FALSE);
  2156. } // FmpInPossibleListForResource
  2157. /****
  2158. @func DWORD | FmpInPossibleListForResType| This checks if a given node
  2159. is in the possible list of nodes for a resource type.
  2160. @parm IN PFM_RESTYPE| pResType | A pointer to the the resource type.
  2161. @parm IN PNM_NODE | pNode | A pointer to the node object.
  2162. @comm This routine check if a node is in the list of possible nodes
  2163. for this resource type.
  2164. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2165. @xref <f FmpInPossibleListForResource>
  2166. ****/
  2167. BOOL
  2168. FmpInPossibleListForResType(
  2169. IN PFM_RESTYPE pResType,
  2170. IN PNM_NODE pNode
  2171. )
  2172. {
  2173. PLIST_ENTRY pListEntry;
  2174. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry;
  2175. ACQUIRE_SHARED_LOCK(gResTypeLock);
  2176. //see if this node is on the possible node list for the resource
  2177. for ( pListEntry = pResType->PossibleNodeList.Flink;
  2178. pListEntry != &(pResType->PossibleNodeList);
  2179. pListEntry = pListEntry->Flink )
  2180. {
  2181. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  2182. PossibleLinkage);
  2183. if ( pResTypePosEntry->PossibleNode == pNode )
  2184. {
  2185. RELEASE_LOCK(gResTypeLock);
  2186. return(TRUE);
  2187. }
  2188. }
  2189. RELEASE_LOCK(gResTypeLock);
  2190. return(FALSE);
  2191. } // FmpInPossibleListForResType
  2192. DWORD
  2193. FmpValAddResourceDependency(
  2194. IN PFM_RESOURCE pResource,
  2195. IN PFM_RESOURCE pDependentResource
  2196. )
  2197. /*++
  2198. Routine Description:
  2199. Add a dependency from one resource to another.
  2200. Arguments:
  2201. Resource - The resource to add the dependent resource.
  2202. DependentResource - The dependent resource.
  2203. Returns:
  2204. ERROR_SUCCESS if successful.
  2205. A Win32 error code on failure.
  2206. --*/
  2207. {
  2208. DWORD dwStatus = ERROR_SUCCESS;
  2209. //
  2210. // If the resource or dependent resource have been marked for
  2211. // delete, then dont let a dependency be added.
  2212. //
  2213. if ((!IS_VALID_FM_RESOURCE(pResource)) ||
  2214. (!IS_VALID_FM_RESOURCE(pDependentResource)))
  2215. {
  2216. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  2217. goto FnExit;
  2218. }
  2219. if (pResource->QuorumResource)
  2220. {
  2221. dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED;
  2222. goto FnExit;
  2223. }
  2224. //
  2225. // If the resources are not in the same group, fail the
  2226. // call. Also fail if some one tries to make a resource
  2227. // dependent upon itself.
  2228. //
  2229. if ((pResource->Group != pDependentResource->Group) ||
  2230. (pResource == pDependentResource))
  2231. {
  2232. dwStatus = ERROR_INVALID_PARAMETER;
  2233. goto FnExit;
  2234. }
  2235. // The resource to which the dependency is being added must be offline
  2236. // Otherwise, it looks like the dependency is in effect when the depending
  2237. // resource was not really brought online at the time the dependency
  2238. // existed
  2239. // must also be offline or failed.
  2240. // SS: For instance if a network name is dependent on two ip addresesses
  2241. // and
  2242. // is online and a third ip address resource dependency is added, the
  2243. // network name must be brought offline and online for the dependency
  2244. // to be truly in effect
  2245. //
  2246. if ((pResource->State != ClusterResourceOffline) &&
  2247. (pResource->State != ClusterResourceFailed))
  2248. {
  2249. dwStatus = ERROR_RESOURCE_ONLINE;
  2250. goto FnExit;
  2251. }
  2252. //
  2253. // Make sure that we don't have any circular dependencies!
  2254. //
  2255. if ( FmDependentResource( pDependentResource, pResource, FALSE ) )
  2256. {
  2257. dwStatus = ERROR_CIRCULAR_DEPENDENCY;
  2258. goto FnExit;
  2259. }
  2260. //
  2261. // Make sure that this dependency does not already exist!
  2262. //
  2263. if ( FmDependentResource(pResource, pDependentResource, TRUE))
  2264. {
  2265. dwStatus = ERROR_DEPENDENCY_ALREADY_EXISTS;
  2266. goto FnExit;
  2267. }
  2268. FnExit:
  2269. return(dwStatus);
  2270. } // FmpValAddResourceDependency
  2271. DWORD
  2272. FmpValRemoveResourceDependency(
  2273. IN PFM_RESOURCE pResource,
  2274. IN PFM_RESOURCE pDependentResource
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. Validation routine for dependency removal.
  2279. Arguments:
  2280. pResource - The resource to remove the dependent resource.
  2281. pDependentResource - The dependent resource.
  2282. Returns:
  2283. ERROR_SUCCESS if the validation is successful.
  2284. A Win32 error code if the validation fails.
  2285. --*/
  2286. {
  2287. DWORD dwStatus = ERROR_SUCCESS;
  2288. //
  2289. // Chittur Subbaraman (chitturs) - 8/3/99
  2290. //
  2291. // This function checks whether it is legal to remove the dependency
  2292. // relationship between 2 resources. Note that this function only
  2293. // does a partial validation, the rest is done in the GUM handler.
  2294. //
  2295. //
  2296. // If the resource has been marked for delete, then dont
  2297. // let any dependency changes be made.
  2298. //
  2299. if ( !IS_VALID_FM_RESOURCE( pResource ) )
  2300. {
  2301. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  2302. goto FnExit;
  2303. }
  2304. if ( pResource->QuorumResource )
  2305. {
  2306. dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED;
  2307. goto FnExit;
  2308. }
  2309. //
  2310. // If the resources are not in the same group, fail the
  2311. // call. Also fail if some one tries to make a resource
  2312. // dependent upon itself.
  2313. //
  2314. if ( ( pResource->Group != pDependentResource->Group ) ||
  2315. ( pResource == pDependentResource ) )
  2316. {
  2317. dwStatus = ERROR_INVALID_PARAMETER;
  2318. goto FnExit;
  2319. }
  2320. //
  2321. // Ensure that both the resource and the dependent resource are in
  2322. // a stable state. This is necessary to prevent cases in which the
  2323. // user gets rid of a dependency link when one of the resources is in
  2324. // a pending state and later when the notification from resmon comes
  2325. // in and you try to stablize the rest of the waiting tree, the
  2326. // dependency link is already cut and so the rest of the tree is
  2327. // stuck in pending state for ever !
  2328. //
  2329. if ( ( pResource->State > ClusterResourcePending ) ||
  2330. ( pDependentResource->State > ClusterResourcePending ) )
  2331. {
  2332. dwStatus = ERROR_INVALID_STATE;
  2333. goto FnExit;
  2334. }
  2335. FnExit:
  2336. return( dwStatus );
  2337. } // FmpValRemoveResourceDependency