Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3213 lines
92 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. FmpArbitrateResource(
  567. IN PFM_RESOURCE pResource
  568. )
  569. /*++
  570. Routine Description:
  571. This is called by FM internally. It makes sure the quorum resource
  572. is initialized on a node before sending it the arbitration request.
  573. This allows for third party quorum dlls to be installed on a node by
  574. node basis and moves to work. If a DLL is installed on a node and
  575. if a move operation is performed with a target of that node, the automagic
  576. calculation of possible node list kicks in. However, since the
  577. process of resource initialization is asynchronous, if the FmpTakeGroupRequest()
  578. is invoked before the worker thread gets to run, the resource may not
  579. be initialized and hence may not be able to perform the request to arbitrate.
  580. Arguments:
  581. Resource - Supplies the resource to be arbitrated.
  582. Return Value:
  583. ERROR_SUCCESS if successful.
  584. Win32 error code otherwise.
  585. --*/
  586. {
  587. DWORD dwStatus;
  588. DWORD dwSeparateMonitor;
  589. CL_ASSERT( pResource->Group != NULL );
  590. FmpAcquireLocalResourceLock(pResource);
  591. //
  592. // If the resource is not initialized, then initialize it now.
  593. //
  594. if ( pResource->Monitor == NULL )
  595. {
  596. dwStatus = FmpInitializeResource( pResource, TRUE );
  597. if ( dwStatus != ERROR_SUCCESS )
  598. {
  599. goto FnExit;
  600. }
  601. }
  602. else
  603. {
  604. //
  605. // If the separate monitor flag has changed, then close down old
  606. // resource in resmon, and re-create it.
  607. //
  608. dwSeparateMonitor = (pResource->Flags & RESOURCE_SEPARATE_MONITOR) ? 1 : 0;
  609. dwStatus = DmQueryDword( pResource->RegistryKey,
  610. CLUSREG_NAME_RES_SEPARATE_MONITOR,
  611. &dwSeparateMonitor,
  612. &dwSeparateMonitor );
  613. if ( (!dwSeparateMonitor &&
  614. (pResource->Flags & RESOURCE_SEPARATE_MONITOR)) ||
  615. (dwSeparateMonitor &&
  616. ((pResource->Flags & RESOURCE_SEPARATE_MONITOR) == 0)) )
  617. {
  618. dwStatus = FmpChangeResourceMonitor(pResource, dwSeparateMonitor );
  619. if ( dwStatus != ERROR_SUCCESS )
  620. {
  621. goto FnExit;
  622. }
  623. }
  624. }
  625. dwStatus = FmpRmArbitrateResource(pResource);
  626. FnExit:
  627. FmpReleaseLocalResourceLock(pResource);
  628. return(dwStatus);
  629. } // FmpArbitrateResource
  630. DWORD
  631. FmpTerminateResource(
  632. IN PFM_RESOURCE Resource
  633. )
  634. /*++
  635. Routine Description:
  636. This routine takes a resource (and all of the resources that it provides
  637. for) offline - the hard way.
  638. Arguments:
  639. Resource - A pointer to the resource to take offline the hard way.
  640. Returns:
  641. ERROR_SUCCESS - if the request is successful.
  642. A Win32 error if the request fails.
  643. --*/
  644. {
  645. PLIST_ENTRY entry;
  646. PDEPENDENCY dependency;
  647. DWORD status;
  648. FmpAcquireLocalResourceLock( Resource );
  649. //
  650. // If the resource is already offline, then return immediately.
  651. //
  652. // We should not have to check if a resource has been initialized,
  653. // since if it hasn't been initialized we will return because the
  654. // pre-initialized state of a resource is Offline.
  655. //
  656. if ( Resource->State == ClusterResourceOffline ) {
  657. FmpReleaseLocalResourceLock( Resource );
  658. return(ERROR_SUCCESS);
  659. }
  660. Resource->Flags &= ~RESOURCE_WAITING;
  661. //
  662. // If this resource has any dependents, terminate them first.
  663. //
  664. for ( entry = Resource->ProvidesFor.Flink;
  665. entry != &(Resource->ProvidesFor);
  666. entry = entry->Flink
  667. )
  668. {
  669. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  670. //
  671. // Recursively terminate the dependent resource
  672. //
  673. ClRtlLogPrint(LOG_NOISE,
  674. "[FM] TerminateResource: %1!ws! depends on %2!ws!. Terminating first\n",
  675. OmObjectId(dependency->DependentResource),
  676. OmObjectId(Resource));
  677. //
  678. // First stop any pending threads.
  679. //
  680. if ( dependency->DependentResource->PendingEvent ) {
  681. SetEvent( dependency->DependentResource->PendingEvent );
  682. }
  683. status = FmpTerminateResource(dependency->DependentResource);
  684. CL_ASSERT( status != ERROR_IO_PENDING );
  685. if (status != ERROR_SUCCESS) {
  686. FmpReleaseLocalResourceLock( Resource );
  687. return(status);
  688. }
  689. }
  690. //
  691. // Tell the resource monitor to terminate this resource.
  692. //
  693. FmpRmTerminateResource(Resource);
  694. FmpReleaseLocalResourceLock( Resource );
  695. return(ERROR_SUCCESS);
  696. } // FmpTerminateResource
  697. DWORD
  698. FmpOfflineResource(
  699. IN PFM_RESOURCE Resource,
  700. IN BOOL bForceOffline
  701. )
  702. /*++
  703. Routine Description:
  704. This routine takes a resource (and all of the resources that it provides
  705. for) offline. If ERROR_IO_PENDING is returned, then no thread is started
  706. to complete the offline request.
  707. Arguments:
  708. Resource - A pointer to the resource to take offline.
  709. bForceOffline - Indicates whether the persistent state is to be set.
  710. Returns:
  711. ERROR_SUCCESS if the request is successful.
  712. ERROR_IO_PENDING if the request is pending.
  713. A Win32 error code if the request fails.
  714. --*/
  715. {
  716. DWORD status = ERROR_SUCCESS;
  717. PLIST_ENTRY entry;
  718. PDEPENDENCY dependency;
  719. BOOL waitingResource = FALSE;
  720. DWORD offlinestatus;
  721. FmpAcquireLocalResourceLock( Resource );
  722. //
  723. // If we own the Group and we are not a possible owner, then the resource
  724. // better be offline!
  725. //
  726. if ( (Resource->Group->OwnerNode != NmLocalNode) ||
  727. (!FmpInPreferredList( Resource->Group, Resource->Group->OwnerNode , FALSE, NULL) &&
  728. (Resource->Group != gpQuoResource->Group) &&
  729. (Resource->State != ClusterResourceOffline)) ) {
  730. FmpReleaseLocalResourceLock( Resource );
  731. return(ERROR_INVALID_STATE);
  732. }
  733. //
  734. // If the resource is already offline, then return immediately.
  735. //
  736. // We should not have to check if a resource has been initialized,
  737. // since if it hasn't, then we will return because the pre-initialized
  738. // state of a resource is Offline.
  739. //
  740. if ( Resource->State == ClusterResourceOffline ) {
  741. //
  742. // If this is the quorum resource, make sure any reservation
  743. // threads are stopped!
  744. //
  745. if ( Resource->QuorumResource ) {
  746. FmpRmTerminateResource( Resource );
  747. }
  748. FmpReleaseLocalResourceLock( Resource );
  749. return(ERROR_SUCCESS);
  750. } else if ( Resource->State == ClusterResourceFailed ) {
  751. //
  752. // Chittur Subbaraman (chitturs) - 4/8/99
  753. //
  754. // If the resource has already failed, then don't do anything.
  755. // You could run into some funny cases of a resource switching
  756. // between offline pending and failed states for ever if you
  757. // attempt to offline a failed resource.
  758. //
  759. FmpReleaseLocalResourceLock( Resource );
  760. return(ERROR_SUCCESS);
  761. }
  762. //
  763. // If this system is not the owner, then return an error. Forwarding
  764. // should have been done at a higher layer.
  765. //
  766. CL_ASSERT( Resource->Group != NULL );
  767. if ( (Resource->Group->OwnerNode != NmLocalNode) ||
  768. ((Resource->Group != gpQuoResource->Group) &&
  769. !FmpInPreferredList( Resource->Group, Resource->Group->OwnerNode, FALSE, NULL)) ) {
  770. FmpReleaseLocalResourceLock( Resource );
  771. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  772. }
  773. if (Resource->State == ClusterResourceOnlinePending ) {
  774. FmpReleaseLocalResourceLock( Resource );
  775. ClRtlLogPrint(LOG_NOISE,
  776. "[FM] FmpOfflineResource: Offline resource <%1!ws!> is in online pending state\n",
  777. OmObjectName(Resource) );
  778. if (FmpShutdown)
  779. {
  780. FmpRmTerminateResource( Resource );
  781. return(ERROR_SUCCESS);
  782. }
  783. else
  784. return(ERROR_INVALID_STATE);
  785. }
  786. //
  787. // If the resource is in a pending state, then return immediately.
  788. //
  789. if (Resource->State == ClusterResourceOfflinePending ) {
  790. FmpReleaseLocalResourceLock( Resource );
  791. ClRtlLogPrint(LOG_NOISE,
  792. "[FM] FmpOfflineResource: Offline resource <%1!ws!> returned pending\n",
  793. OmObjectName(Resource) );
  794. return(ERROR_IO_PENDING);
  795. }
  796. //
  797. // Next, make sure there are no resources up the tree that are waiting.
  798. // This prevents a deadlock where the top of the tree is trying to go
  799. // offline, while the bottom of the tree is trying to go online.
  800. //
  801. for ( entry = Resource->ProvidesFor.Flink;
  802. entry != &(Resource->ProvidesFor);
  803. entry = entry->Flink
  804. )
  805. {
  806. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  807. if ( (dependency->DependentResource->State == ClusterResourceOnlinePending) &&
  808. (dependency->DependentResource->Flags & RESOURCE_WAITING) ) {
  809. waitingResource = TRUE;
  810. break;
  811. }
  812. }
  813. if ( waitingResource ) {
  814. Resource->Flags |= RESOURCE_WAITING;
  815. FmpReleaseLocalResourceLock( Resource );
  816. return(ERROR_RESOURCE_NOT_AVAILABLE);
  817. }
  818. //
  819. // Make sure the Waiting flag is clear.
  820. //
  821. Resource->Flags &= ~RESOURCE_WAITING;
  822. //
  823. // If this resource has any dependents, shut them down first.
  824. //
  825. for ( entry = Resource->ProvidesFor.Flink;
  826. entry != &(Resource->ProvidesFor);
  827. entry = entry->Flink
  828. )
  829. {
  830. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  831. //
  832. // Recursively shutdown the dependent resource.
  833. //
  834. ClRtlLogPrint(LOG_NOISE,
  835. "[FM] FmpOfflineResource: %1!ws! depends on %2!ws!. Shut down first.\n",
  836. OmObjectName(dependency->DependentResource),
  837. OmObjectName(Resource));
  838. offlinestatus = FmpDoOfflineResource(dependency->DependentResource,
  839. bForceOffline);
  840. if ( offlinestatus != ERROR_SUCCESS ) {
  841. if ( offlinestatus != ERROR_IO_PENDING ) {
  842. ClRtlLogPrint(LOG_NOISE,
  843. "[FM] FmpOfflineResource for %1!ws!, bad status returned %2!u!.\n",
  844. OmObjectName(dependency->DependentResource),
  845. offlinestatus);
  846. FmpTerminateResource( dependency->DependentResource );
  847. FmpReleaseLocalResourceLock( Resource );
  848. return(offlinestatus);
  849. } else {
  850. ClRtlLogPrint(LOG_NOISE,
  851. "[FM] FmpOfflineResource for %1!ws! marked as waiting.\n",
  852. OmObjectName(Resource));
  853. FmpCallResourceNotifyCb(Resource, ClusterResourceOfflinePending);
  854. FmpPropagateResourceState( Resource,
  855. ClusterResourceOfflinePending );
  856. Resource->Flags |= RESOURCE_WAITING;
  857. if (status == ERROR_SUCCESS)
  858. status = offlinestatus;
  859. }
  860. }
  861. }
  862. //
  863. // Tell the resource monitor to shut this resource down.
  864. // The state gets updated by the return status in FmpRmOfflineResource.
  865. //
  866. if ( !(Resource->Flags & RESOURCE_WAITING) ) {
  867. status = FmpRmOfflineResource( Resource );
  868. //
  869. // Chittur Subbaraman (chitturs) - 3/2/2000
  870. //
  871. // If the resource could not be made offline since the quorum
  872. // resource online operation failed or for other reasons, then
  873. // make sure the resource is terminated after you declare the
  874. // state of the resource as failed. This is necessary since
  875. // otherwise the FM will consider the resource as having failed
  876. // while the resource itself is actually online. This will
  877. // lead to disastrous cases whereby the FM will allow the online
  878. // entry point of a resource to be called while the resource is
  879. // actually online !
  880. //
  881. if( ( status != ERROR_SUCCESS ) &&
  882. ( status != ERROR_IO_PENDING ) &&
  883. ( status != ERROR_RETRY ) ) {
  884. FmpRmTerminateResource( Resource );
  885. }
  886. }
  887. FmpReleaseLocalResourceLock( Resource );
  888. return(status);
  889. } // FmpOfflineResource
  890. DWORD
  891. FmpDoOnlineResource(
  892. IN PFM_RESOURCE Resource,
  893. IN BOOL ForceOnline
  894. )
  895. /*++
  896. Routine Description:
  897. This routine brings a resource online. If ERROR_IO_PENDING is returned,
  898. then a thread is started to complete the Online request.
  899. Arguments:
  900. Resource - A pointer to the resource to bring online.
  901. ForceOnline - TRUE if the resource should be forced online.
  902. Returns:
  903. ERROR_SUCCESS if the request is successful.
  904. ERROR_IO_PENDING if the request is pending.
  905. A Win32 error code if the request fails.
  906. --*/
  907. {
  908. DWORD status;
  909. FmpAcquireLocalResourceLock( Resource );
  910. //
  911. // If the resource is already online, then return immediately.
  912. //
  913. if ( Resource->State == ClusterResourceOnline ) {
  914. FmpReleaseLocalResourceLock( Resource );
  915. return(ERROR_SUCCESS);
  916. }
  917. //
  918. // If the resource is in a pending state, then return immediately.
  919. // FmpOnlineResource checks for offlinepending state and returns
  920. // ERROR_INVALID_STATE if so.
  921. //
  922. if ( Resource->State == ClusterResourceOnlinePending ) {
  923. FmpReleaseLocalResourceLock( Resource );
  924. return(ERROR_IO_PENDING);
  925. }
  926. //
  927. // If this node is paused, return failure.
  928. //
  929. if (NmGetNodeState(NmLocalNode) == ClusterNodePaused) {
  930. FmpReleaseLocalResourceLock( Resource );
  931. return(ERROR_SHARING_PAUSED);
  932. }
  933. //
  934. // Try to bring the resource online.
  935. //
  936. status = FmpOnlineResource( Resource, ForceOnline );
  937. //
  938. // Write the persistent state if it is forced online.
  939. //
  940. if ( ForceOnline &&
  941. ((status == ERROR_SUCCESS)||
  942. (status == ERROR_IO_PENDING))) {
  943. FmpSetResourcePersistentState( Resource, ClusterResourceOnline );
  944. }
  945. FmpReleaseLocalResourceLock( Resource );
  946. return(status);
  947. } // FmpDoOnlineResource
  948. DWORD
  949. FmpDoOfflineResource(
  950. IN PFM_RESOURCE Resource,
  951. IN BOOL bForceOffline
  952. )
  953. /*++
  954. Routine Description:
  955. This routine takes a resource offline. If ERROR_IO_PENDING is returned,
  956. then a thread is started to complete the Offline request.
  957. Arguments:
  958. Resource - A pointer to the resource to take offline.
  959. bForceOffline - Indicates whether the persistent state must be changed.
  960. Returns:
  961. ERROR_SUCCESS if the request is successful.
  962. ERROR_IO_PENDING if the request is pending.
  963. A Win32 error code if the request fails.
  964. --*/
  965. {
  966. DWORD status;
  967. FmpAcquireLocalResourceLock( Resource );
  968. //
  969. // If the resource is already offline, then return immediately.
  970. //
  971. if (Resource->State == ClusterResourceOffline) {
  972. //
  973. // If this is the quorum resource, make sure any reservation
  974. // threads are stopped!
  975. //
  976. if ( Resource->QuorumResource ) {
  977. FmpRmTerminateResource( Resource );
  978. }
  979. FmpReleaseLocalResourceLock( Resource );
  980. return(ERROR_SUCCESS);
  981. }
  982. //
  983. // If the resource is in a pending state, then return immediately.
  984. // FmpOffline resource checks to see if it is in OnlinePending state
  985. // and returns invalid state
  986. //
  987. if (Resource->State == ClusterResourceOfflinePending ) {
  988. FmpReleaseLocalResourceLock( Resource );
  989. return(ERROR_IO_PENDING);
  990. }
  991. //
  992. // Try to take the resource offline.
  993. //
  994. status = FmpOfflineResource( Resource, bForceOffline );
  995. //
  996. // Write the persistent state if it is forced offline
  997. //
  998. if ( bForceOffline &&
  999. ((status == ERROR_SUCCESS)||
  1000. (status == ERROR_IO_PENDING))) {
  1001. FmpSetResourcePersistentState( Resource, ClusterResourceOffline );
  1002. }
  1003. FmpReleaseLocalResourceLock( Resource );
  1004. return(status);
  1005. } // FmpDoOfflineResource
  1006. VOID
  1007. FmpSetResourcePersistentState(
  1008. IN PFM_RESOURCE Resource,
  1009. IN CLUSTER_RESOURCE_STATE State
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. Set the persistent state of a Resource in the registry and set the
  1014. PersistentState for the volatile (in-memory) resource. It is assumed
  1015. that the dynamic state gets changed elsewhere depending on whether
  1016. the resource online request succeeds or fails.
  1017. Arguments:
  1018. Resource - The resource to set the state.
  1019. State - The new state for the Resource.
  1020. Returns:
  1021. ERROR_SUCCESS if successful.
  1022. A Win32 error code on failure.
  1023. Notes:
  1024. The LocalResourceLock must be held.
  1025. --*/
  1026. {
  1027. CLUSTER_RESOURCE_STATE persistentState;
  1028. LPWSTR persistentStateName = CLUSREG_NAME_RES_PERSISTENT_STATE;
  1029. if (!gbIsQuoResEnoughSpace)
  1030. return;
  1031. //
  1032. // If the current state has changed, then do the work. Otherwise,
  1033. // skip the effort.
  1034. //
  1035. if ( Resource->PersistentState != State ) {
  1036. Resource->PersistentState = State;
  1037. CL_ASSERT( Resource->RegistryKey != NULL );
  1038. ClRtlLogPrint(LOG_NOISE,
  1039. "[FM] FmpSetResourcePersistentState: Setting persistent state for resource %1!ws!...\r\n",
  1040. OmObjectId(Resource));
  1041. //
  1042. // Set the new value, but only if it is online or offline.
  1043. //
  1044. if ( State == ClusterResourceOffline ) {
  1045. persistentState = 0;
  1046. DmSetValue( Resource->RegistryKey,
  1047. persistentStateName,
  1048. REG_DWORD,
  1049. (LPBYTE)&persistentState,
  1050. sizeof(DWORD) );
  1051. } else if ( State == ClusterResourceOnline ) {
  1052. persistentState = 1;
  1053. DmSetValue( Resource->RegistryKey,
  1054. persistentStateName,
  1055. REG_DWORD,
  1056. (LPBYTE)&persistentState,
  1057. sizeof(DWORD) );
  1058. }
  1059. }
  1060. } // FmpSetResourcePersistentState
  1061. void FmpCallResourceNotifyCb(
  1062. IN PFM_RESOURCE Resource,
  1063. IN CLUSTER_RESOURCE_STATE State
  1064. )
  1065. {
  1066. switch ( State ) {
  1067. case ClusterResourceOnline:
  1068. OmNotifyCb(Resource, NOTIFY_RESOURCE_POSTONLINE);
  1069. break;
  1070. case ClusterResourceOffline:
  1071. OmNotifyCb(Resource, NOTIFY_RESOURCE_POSTOFFLINE);
  1072. break;
  1073. case ClusterResourceFailed:
  1074. OmNotifyCb(Resource, NOTIFY_RESOURCE_FAILED);
  1075. break;
  1076. case ClusterResourceOnlinePending:
  1077. OmNotifyCb(Resource, NOTIFY_RESOURCE_ONLINEPENDING);
  1078. break;
  1079. case ClusterResourceOfflinePending:
  1080. OmNotifyCb(Resource, NOTIFY_RESOURCE_OFFLINEPENDING);
  1081. break;
  1082. default:
  1083. break;
  1084. }
  1085. return;
  1086. }
  1087. DWORD
  1088. FmpPropagateResourceState(
  1089. IN PFM_RESOURCE Resource,
  1090. IN CLUSTER_RESOURCE_STATE State
  1091. )
  1092. /*++
  1093. Routine Description:
  1094. Propagates the state of the resource to other systems in the cluster.
  1095. Ideally the gQuoCritSec lock should be held when this routine is called.
  1096. This is because this routine checks the quorumresource field of the
  1097. resource
  1098. Arguments:
  1099. Resource - The resource to propagate state.
  1100. State - The new state for the resource.
  1101. Returns:
  1102. ERROR_SUCCESS if successful.
  1103. A Win32 error code on failure.
  1104. --*/
  1105. {
  1106. GUM_RESOURCE_STATE resourceState;
  1107. LPCWSTR resourceId;
  1108. DWORD resourceStateSize;
  1109. DWORD status= ERROR_SUCCESS;
  1110. BOOL bAcquiredQuoLock = FALSE;
  1111. //for quorum resource use the quorum lock for state changes
  1112. // for others use the group locks
  1113. if (Resource->QuorumResource)
  1114. {
  1115. ACQUIRE_EXCLUSIVE_LOCK(gQuoLock);
  1116. bAcquiredQuoLock = TRUE;
  1117. }
  1118. else
  1119. FmpAcquireLocalResourceLock( Resource );
  1120. ++Resource->StateSequence;
  1121. if (! FmpFMFormPhaseProcessing )
  1122. {
  1123. //
  1124. // If this is the same state, or we don't own the group
  1125. // then don't bother propagating.
  1126. //
  1127. if ( (State == Resource->State) ||
  1128. (Resource->Group->OwnerNode != NmLocalNode) ) {
  1129. goto ReleaseResourceLock;
  1130. }
  1131. //if the previous state is the online pending and this
  1132. // is called for the quorum resource, wake up all resources
  1133. // make sure that if this is called while the form phase
  1134. //processing is going on(when the quorum group is destroyed
  1135. //and recreated), that the group is not referenced
  1136. if ((Resource->QuorumResource) &&
  1137. (Resource->State==ClusterResourceOnlinePending) &&
  1138. (Resource->Group->OwnerNode == NmLocalNode) )
  1139. {
  1140. //set the state and signal
  1141. Resource->State = State;
  1142. ClRtlLogPrint(LOG_NOISE,
  1143. "[FM] FmpPropagateResourceState: signalling the ghQuoOnlineEvent\r\n");
  1144. SetEvent(ghQuoOnlineEvent);
  1145. }
  1146. }
  1147. Resource->State = State;
  1148. //
  1149. // Prepare to notify other systems.
  1150. //
  1151. resourceId = OmObjectId( Resource );
  1152. resourceState.State = State;
  1153. resourceState.PersistentState = Resource->PersistentState;
  1154. resourceState.StateSequence = Resource->StateSequence;
  1155. status = GumSendUpdateEx(GumUpdateFailoverManager,
  1156. FmUpdateResourceState,
  1157. 2,
  1158. (lstrlenW(resourceId)+1)*sizeof(WCHAR),
  1159. resourceId,
  1160. sizeof(resourceState),
  1161. &resourceState);
  1162. //
  1163. // Signal change notify event.
  1164. //
  1165. switch ( State ) {
  1166. case ClusterResourceOnline:
  1167. ClRtlLogPrint(LOG_NOISE,
  1168. "[FM] FmpPropagateResourceState: resource %1!ws! online event.\n",
  1169. OmObjectId(Resource) );
  1170. ClusterEvent(CLUSTER_EVENT_RESOURCE_ONLINE, Resource);
  1171. break;
  1172. case ClusterResourceOffline:
  1173. ClRtlLogPrint(LOG_NOISE,
  1174. "[FM] FmpPropagateResourceState: resource %1!ws! offline event.\n",
  1175. OmObjectId(Resource) );
  1176. ClusterEvent(CLUSTER_EVENT_RESOURCE_OFFLINE, Resource);
  1177. break;
  1178. case ClusterResourceFailed:
  1179. ClRtlLogPrint(LOG_NOISE,
  1180. "[FM] FmpPropagateResourceState: resource %1!ws! failed event.\n",
  1181. OmObjectId(Resource) );
  1182. ClusterEvent(CLUSTER_EVENT_RESOURCE_FAILED, Resource);
  1183. break;
  1184. case ClusterResourceOnlinePending:
  1185. case ClusterResourceOfflinePending:
  1186. ClRtlLogPrint(LOG_NOISE,
  1187. "[FM] FmpPropagateResourceState: resource %1!ws! pending event.\n",
  1188. OmObjectId(Resource) );
  1189. ClusterEvent(CLUSTER_EVENT_RESOURCE_CHANGE, Resource);
  1190. break;
  1191. default:
  1192. break;
  1193. }
  1194. ReleaseResourceLock:
  1195. if (bAcquiredQuoLock)
  1196. RELEASE_LOCK(gQuoLock);
  1197. else
  1198. FmpReleaseLocalResourceLock( Resource );
  1199. if ( status != ERROR_SUCCESS )
  1200. {
  1201. ClRtlLogPrint(LOG_UNUSUAL,
  1202. "[FM] Propagation of resource %1!ws! state %2!u! failed. Error %3!u!\n",
  1203. OmObjectId(Resource),
  1204. State,
  1205. status);
  1206. goto FnExit;
  1207. }
  1208. //if fm is not completely online we dont want to propagate group state
  1209. // This is because the quorum group is destroyed in FmFormNewClusterPhase1
  1210. // and then recreated again in FmFormNewClusterPhase2.
  1211. if (FmpFMOnline)
  1212. {
  1213. OmReferenceObject(Resource->Group);
  1214. //FmpPropagateGroupState( Resource->Group );
  1215. FmpPostWorkItem(FM_EVENT_INTERNAL_PROP_GROUP_STATE, Resource->Group, 0);
  1216. }
  1217. FnExit:
  1218. return(status);
  1219. } // FmpPropagateResourceState
  1220. VOID
  1221. FmpDestroyResource(
  1222. IN PFM_RESOURCE Resource,
  1223. IN BOOL bDeleteObjOnly
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. Destroys a resource. This basically snips a resource out of the
  1228. dependency tree.
  1229. First, any resources that depend on the specified
  1230. resource are recursively destroyed. This removes any dependencies
  1231. that other resources may have on the specified resource (i.e. all
  1232. resources "higher" in the dependency tree are destroyed).
  1233. Second, all the dependencies that the specified resource has are
  1234. removed. This entails dereferencing the provider resource (to remove
  1235. the reference that was added when the dependency was created) removing
  1236. the DEPENDENCY structure from its provider and dependent lists, and
  1237. finally freeing the DEPENDENCY storage.
  1238. If the resource is online, it is terminated. The resource monitor is
  1239. signalled to clean up and close the specified resource id.
  1240. Arguments:
  1241. FoundResource - Returns the found resource.
  1242. Resource - Supplies the current resource.
  1243. Name - Supplies the current resource's name.
  1244. Return Value:
  1245. None.
  1246. Notes:
  1247. The LocalResourceLock MUST be held! The lock is released before exit!
  1248. --*/
  1249. {
  1250. DWORD status;
  1251. DWORD i;
  1252. PLIST_ENTRY ListEntry;
  1253. PDEPENDENCY Dependency;
  1254. PPOSSIBLE_ENTRY possibleEntry;
  1255. ClRtlLogPrint(LOG_NOISE,
  1256. "[FM] DestroyResource: destroying %1!ws!\n",
  1257. OmObjectId(Resource));
  1258. //
  1259. // First, unlink this resource from the resource list.
  1260. //
  1261. //
  1262. // if the resource belongs to the quorum group, it is destroyed
  1263. // after the quorum logs are created so that it can be recreated
  1264. // dont remove it from the list then
  1265. if ((!bDeleteObjOnly))
  1266. status = OmRemoveObject( Resource );
  1267. //
  1268. // If anyone depends on this resource, destroy them first.
  1269. //
  1270. while (!IsListEmpty(&Resource->ProvidesFor)) {
  1271. ListEntry = Resource->ProvidesFor.Flink;
  1272. Dependency = CONTAINING_RECORD(ListEntry, DEPENDENCY, ProviderLinkage);
  1273. CL_ASSERT(Dependency->ProviderResource == Resource);
  1274. #if 0
  1275. FmpRemoveResourceDependency( Dependency->DependentResource,
  1276. Resource );
  1277. #endif
  1278. RemoveEntryList(&Dependency->ProviderLinkage);
  1279. RemoveEntryList(&Dependency->DependentLinkage);
  1280. //
  1281. // Dereference provider/dependent resource and free dependency storage
  1282. //
  1283. OmDereferenceObject(Dependency->ProviderResource);
  1284. OmDereferenceObject(Dependency->DependentResource);
  1285. LocalFree(Dependency);
  1286. }
  1287. //
  1288. // Remove our resource dependencies.
  1289. //
  1290. while (!IsListEmpty(&Resource->DependsOn)) {
  1291. ListEntry = RemoveHeadList(&Resource->DependsOn);
  1292. Dependency = CONTAINING_RECORD(ListEntry, DEPENDENCY, DependentLinkage);
  1293. CL_ASSERT(Dependency->DependentResource == Resource);
  1294. #if 0
  1295. FmpRemoveResourceDependency( Resource,
  1296. Dependency->ProviderResource );
  1297. #endif
  1298. RemoveEntryList(&Dependency->ProviderLinkage);
  1299. RemoveEntryList(&Dependency->DependentLinkage);
  1300. //
  1301. // Dereference provider/dependent resource and free dependency storage
  1302. //
  1303. OmDereferenceObject(Dependency->DependentResource);
  1304. OmDereferenceObject(Dependency->ProviderResource);
  1305. LocalFree(Dependency);
  1306. }
  1307. //
  1308. // Remove all entries from the possible owners list.
  1309. //
  1310. while ( !IsListEmpty(&Resource->PossibleOwners) ) {
  1311. ListEntry = RemoveHeadList(&Resource->PossibleOwners);
  1312. possibleEntry = CONTAINING_RECORD( ListEntry,
  1313. POSSIBLE_ENTRY,
  1314. PossibleLinkage );
  1315. OmDereferenceObject( possibleEntry->PossibleNode );
  1316. LocalFree(possibleEntry);
  1317. }
  1318. if (!bDeleteObjOnly)
  1319. {
  1320. //
  1321. // Close the resource's registry key.
  1322. //
  1323. DmRundownList( &Resource->DmRundownList );
  1324. if (Resource->RegistryKey != NULL) {
  1325. DmCloseKey( Resource->RegistryKey );
  1326. Resource->RegistryKey = NULL;
  1327. }
  1328. //
  1329. // Decrement resource type reference.
  1330. //
  1331. if ( Resource->Type != NULL ) {
  1332. OmDereferenceObject( Resource->Type );
  1333. Resource->Type = NULL;
  1334. }
  1335. // Let the worker thread peform the 'last' dereference
  1336. FmpPostWorkItem(FM_EVENT_RESOURCE_DELETED, Resource, 0);
  1337. FmpReleaseLocalResourceLock( Resource );
  1338. }
  1339. else
  1340. {
  1341. //the resource being destroyed is from the quorum group
  1342. //This is done at initialization
  1343. FmpReleaseLocalResourceLock( Resource );
  1344. // make sure that all resources except the quorum resource
  1345. // are created completely in the second phase of initialization
  1346. //decrement its ref count here, this is the last ref
  1347. //SS:: we dont use FM_EVENT_RESOURCE_DELETED here
  1348. //since we want this done synchronously before phase 2 is
  1349. //complete
  1350. OmDereferenceObject(Resource);
  1351. }
  1352. //ss: for now we dont use it, so dont delete it
  1353. //DeleteCriticalSection(&Resource->Lock);
  1354. ClRtlLogPrint(LOG_NOISE,
  1355. "[FM] FmpDestroyResource Exit.\n");
  1356. return;
  1357. } // FmpDestroyResource
  1358. ///////////////////////////////////////////////////////////////////////////
  1359. //
  1360. // Initialization Routines
  1361. //
  1362. ///////////////////////////////////////////////////////////////////////////
  1363. BOOL
  1364. FmDependentResource(
  1365. IN PFM_RESOURCE Resource,
  1366. IN PFM_RESOURCE DependentResource,
  1367. IN BOOL ImmediateOnly
  1368. )
  1369. /*++
  1370. Routine Description:
  1371. Returns indication of whether a resource is a dependent of another
  1372. resource.
  1373. Arguments:
  1374. Resource - The resource to scan if it depends on the dependent resource.
  1375. DependentResource - The dependent resource to check on.
  1376. ImmediateOnly - Specifies whether only immediate dependencies should be
  1377. checked. If this is FALSE, this routine recursively checks all
  1378. dependents.
  1379. Returns:
  1380. TRUE - The the resource does depend on the dependent resource.
  1381. FALSE - The resource does not depend on the dependent resource.
  1382. --*/
  1383. {
  1384. PLIST_ENTRY listEntry;
  1385. PDEPENDENCY dependency;
  1386. BOOL result = FALSE;
  1387. FmpAcquireLocalResourceLock( Resource );
  1388. listEntry = Resource->DependsOn.Flink;
  1389. while ( listEntry != &Resource->DependsOn ) {
  1390. dependency = CONTAINING_RECORD( listEntry,
  1391. DEPENDENCY,
  1392. DependentLinkage );
  1393. if ( dependency->ProviderResource == DependentResource ) {
  1394. result = TRUE;
  1395. break;
  1396. } else {
  1397. if (!ImmediateOnly) {
  1398. if (FmDependentResource(dependency->ProviderResource,
  1399. DependentResource,
  1400. FALSE)) {
  1401. result = TRUE;
  1402. break;
  1403. }
  1404. }
  1405. }
  1406. listEntry = listEntry->Flink;
  1407. } // while
  1408. FmpReleaseLocalResourceLock( Resource );
  1409. return(result);
  1410. } // FmpDependentResource
  1411. DWORD
  1412. FmpAddPossibleEntry(
  1413. IN PFM_RESOURCE Resource,
  1414. IN PNM_NODE Node
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. Creates a new possible node entry and adds it to a resource's list.
  1419. If the node is already in the resource's list, it will not be added
  1420. again.
  1421. Arguments:
  1422. Resource - Supplies the resource whose node list is to be updated.
  1423. Node - Supplies the node to be added to the resource's list.
  1424. Return Value:
  1425. ERROR_SUCCESS if successful.
  1426. Win32 error otherwise.
  1427. --*/
  1428. {
  1429. PLIST_ENTRY ListEntry;
  1430. PPOSSIBLE_ENTRY PossibleEntry;
  1431. //
  1432. // First check to see if the node is already in the possible owners list.
  1433. //
  1434. ListEntry = Resource->PossibleOwners.Flink;
  1435. while (ListEntry != &Resource->PossibleOwners) {
  1436. PossibleEntry = CONTAINING_RECORD( ListEntry,
  1437. POSSIBLE_ENTRY,
  1438. PossibleLinkage );
  1439. if (PossibleEntry->PossibleNode == Node) {
  1440. //
  1441. // Found a match, it's already here, so return
  1442. // success.
  1443. //
  1444. return(ERROR_SUCCESS);
  1445. }
  1446. ListEntry = ListEntry->Flink;
  1447. }
  1448. ClRtlLogPrint(LOG_NOISE,
  1449. "[FM] FmpAddPossibleEntry: adding node %1!ws! as possible host for resource %2!ws!.\n",
  1450. OmObjectId(Node),
  1451. OmObjectId(Resource));
  1452. PossibleEntry = LocalAlloc(LMEM_FIXED, sizeof(POSSIBLE_ENTRY));
  1453. if (PossibleEntry == NULL) {
  1454. ClRtlLogPrint(LOG_CRITICAL,
  1455. "[FM] FmpAddPossibleEntry failed to allocated PossibleEntry\n");
  1456. return(ERROR_NOT_ENOUGH_MEMORY);
  1457. }
  1458. OmReferenceObject(Node);
  1459. PossibleEntry->PossibleNode = Node;
  1460. InsertTailList( &Resource->PossibleOwners,
  1461. &PossibleEntry->PossibleLinkage );
  1462. return(ERROR_SUCCESS);
  1463. }
  1464. DWORD
  1465. FmpAddPossibleNode(
  1466. IN PFM_RESOURCE Resource,
  1467. IN PNM_NODE Node
  1468. )
  1469. /*++
  1470. Routine Description:
  1471. Adds a node to the resource's list of possible nodes.
  1472. The resource lock must be held.
  1473. Arguments:
  1474. Resource - Supplies the resource whose list of nodes is to be updated
  1475. Node - Supplies the node to add to the specified resource's list.
  1476. Return Value:
  1477. ERROR_SUCCESS if successful
  1478. Win32 error otherwise
  1479. --*/
  1480. {
  1481. HDMKEY hGroup;
  1482. DWORD Status;
  1483. //
  1484. // Allocate the new possible node entry and add it to the list.
  1485. //
  1486. Status = FmpAddPossibleEntry(Resource, Node);
  1487. if (Status != ERROR_SUCCESS) {
  1488. return(Status);
  1489. }
  1490. //
  1491. // Need to check the group list to see if the specified node
  1492. // can be added to the preferred list now. The easiest way
  1493. // to do that is to simply recreate the entire preferred list,
  1494. // then reprune.
  1495. //
  1496. hGroup = DmOpenKey( DmGroupsKey,
  1497. OmObjectId(Resource->Group),
  1498. KEY_READ );
  1499. if (hGroup == NULL) {
  1500. Status = GetLastError();
  1501. ClRtlLogPrint(LOG_UNUSUAL,
  1502. "[FM] FmpAddPossibleNode failed to open group %1!ws! status %2!d!\n",
  1503. OmObjectId(Resource->Group),
  1504. Status);
  1505. return(Status);
  1506. }
  1507. Status = FmpQueryGroupNodes(Resource->Group,
  1508. hGroup);
  1509. CL_ASSERT(Status == ERROR_SUCCESS);
  1510. if (Status == ERROR_SUCCESS) {
  1511. FmpPruneGroupOwners(Resource->Group);
  1512. }
  1513. DmCloseKey(hGroup);
  1514. return(Status);
  1515. } // FmpAddPossibleNode
  1516. DWORD
  1517. FmpRemovePossibleNode(
  1518. IN PFM_RESOURCE Resource,
  1519. IN PNM_NODE Node,
  1520. IN BOOL RemoveQuorum
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. Removes a node from the resource's list of possible nodes.
  1525. The resource lock must be held.
  1526. Arguments:
  1527. Resource - Supplies the resource whose list of nodes is to be updated
  1528. Node - Supplies the node to be removed from the specified resource's list.
  1529. RemoveQuorum - TRUE if we can remove node from quorum device.
  1530. FALSE otherwise.
  1531. Return Value:
  1532. ERROR_SUCCESS if successful
  1533. Win32 error otherwise
  1534. --*/
  1535. {
  1536. PLIST_ENTRY ListEntry;
  1537. PPOSSIBLE_ENTRY PossibleEntry;
  1538. DWORD Status = ERROR_CLUSTER_NODE_NOT_FOUND;
  1539. //
  1540. // If the resource is currently online on the node to be removed,
  1541. // fail the call.
  1542. //
  1543. if ((Resource->Group->OwnerNode == Node) &&
  1544. (Resource->State == ClusterResourceOnline)) {
  1545. return(ERROR_INVALID_STATE);
  1546. }
  1547. //
  1548. // If it is NOT okay to remove this node from the quorum device,
  1549. // and this is the quorum device, then fail the request.
  1550. //
  1551. if ( !RemoveQuorum &&
  1552. Resource->QuorumResource) {
  1553. return(ERROR_INVALID_OPERATION_ON_QUORUM);
  1554. }
  1555. //
  1556. // Find the possible entry on the resource's list.
  1557. //
  1558. ListEntry = Resource->PossibleOwners.Flink;
  1559. while (ListEntry != &Resource->PossibleOwners) {
  1560. PossibleEntry = CONTAINING_RECORD( ListEntry,
  1561. POSSIBLE_ENTRY,
  1562. PossibleLinkage );
  1563. ListEntry = ListEntry->Flink;
  1564. if (PossibleEntry->PossibleNode == Node) {
  1565. //
  1566. // Found a match, remove it from the list.
  1567. //
  1568. RemoveEntryList(&PossibleEntry->PossibleLinkage);
  1569. OmDereferenceObject(PossibleEntry->PossibleNode);
  1570. LocalFree(PossibleEntry);
  1571. //
  1572. // Now prune the containing group. This is a little bit
  1573. // of overkill, if we were smarter, we could just
  1574. // remove the node from the preferred list directly.
  1575. //
  1576. FmpPrunePreferredList(Resource);
  1577. Status = ERROR_SUCCESS;
  1578. break;
  1579. }
  1580. }
  1581. return(Status);
  1582. } // FmpRemovePossibleNode
  1583. DWORD
  1584. FmpRemoveResourceDependency(
  1585. HLOCALXSACTION hXsaction,
  1586. IN PFM_RESOURCE Resource,
  1587. IN PFM_RESOURCE DependsOn
  1588. )
  1589. /*++
  1590. Routine Description:
  1591. Removes a dependency relationship to a given resource. Both
  1592. resources must be in the same group.
  1593. Arguments:
  1594. Resource - Supplies the resource which is dependent.
  1595. DependsOn - Supplies the resource that hResource depends on.
  1596. Return Value:
  1597. ERROR_SUCCESS if successful.
  1598. Win32 error code otherwise.
  1599. --*/
  1600. {
  1601. DWORD status;
  1602. HDMKEY resKey = NULL;
  1603. //
  1604. // If the resources are not in the same group, fail the
  1605. // call. Also fail if some one tries to make a resource
  1606. // dependent upon itself.
  1607. //
  1608. if ((Resource->Group != DependsOn->Group) ||
  1609. (Resource == DependsOn)) {
  1610. return(ERROR_INVALID_PARAMETER);
  1611. }
  1612. //
  1613. // Remove the dependency from the registry database.
  1614. //
  1615. resKey = DmOpenKey(DmResourcesKey,
  1616. OmObjectId(Resource),
  1617. KEY_READ | KEY_SET_VALUE);
  1618. if (resKey == NULL)
  1619. {
  1620. status = GetLastError();
  1621. CL_LOGFAILURE(status);
  1622. goto FnExit;
  1623. }
  1624. else
  1625. {
  1626. status = DmLocalRemoveFromMultiSz(hXsaction,
  1627. resKey,
  1628. CLUSREG_NAME_RES_DEPENDS_ON,
  1629. OmObjectId(DependsOn));
  1630. }
  1631. FnExit:
  1632. if ( resKey ) {
  1633. DmCloseKey(resKey);
  1634. }
  1635. return(status);
  1636. } // FmpRemoveResourceDependency
  1637. DWORD
  1638. FmpChangeResourceGroup(
  1639. IN PFM_RESOURCE pResource,
  1640. IN PFM_GROUP pNewGroup
  1641. )
  1642. /*++
  1643. Routine Description:
  1644. Moves a resource from one group to another.
  1645. Arguments:
  1646. pResource - Supplies the resource to move.
  1647. pNewGroup - Supplies the new group that the resource should be in.
  1648. Return Value:
  1649. ERROR_SUCCESS if successful
  1650. Win32 error code otherwise.
  1651. --*/
  1652. {
  1653. DWORD dwBufSize;
  1654. LPCWSTR pszResourceId;
  1655. DWORD dwResourceLen;
  1656. LPCWSTR pszGroupId;
  1657. DWORD dwGroupLen;
  1658. DWORD dwStatus;
  1659. PGUM_CHANGE_GROUP pGumChange;
  1660. // we need to validate here as well
  1661. // this is called by the server side
  1662. // this will help avoid a gum call if things have changed
  1663. // since the request started from the originator
  1664. // and got to the server
  1665. //
  1666. // Check if we're moving to same group.
  1667. //
  1668. if (pResource->Group == pNewGroup) {
  1669. dwStatus = ERROR_ALREADY_EXISTS;
  1670. goto FnExit;
  1671. }
  1672. //
  1673. // For now... both Groups must be owned by the same node.
  1674. //
  1675. if ( pResource->Group->OwnerNode != pNewGroup->OwnerNode ) {
  1676. dwStatus = ERROR_HOST_NODE_NOT_GROUP_OWNER;
  1677. goto FnExit;
  1678. }
  1679. pszResourceId = OmObjectId(pResource);
  1680. dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
  1681. pszGroupId = OmObjectId(pNewGroup);
  1682. dwGroupLen = (lstrlenW(pszGroupId)+1)*sizeof(WCHAR);
  1683. dwBufSize = sizeof(GUM_CHANGE_GROUP) - sizeof(WCHAR) + dwResourceLen + dwGroupLen;
  1684. pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize);
  1685. if (pGumChange == NULL) {
  1686. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  1687. goto FnExit;
  1688. }
  1689. pGumChange->ResourceIdLen = dwResourceLen;
  1690. CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen);
  1691. CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen,
  1692. pszGroupId,
  1693. dwGroupLen);
  1694. dwStatus = GumSendUpdate(GumUpdateFailoverManager,
  1695. FmUpdateChangeGroup,
  1696. dwBufSize,
  1697. pGumChange);
  1698. LocalFree(pGumChange);
  1699. FnExit:
  1700. return(dwStatus);
  1701. }// FmpChangeResourceGroup
  1702. #if 0
  1703. DWORD
  1704. FmpClusterEventPropHandler(
  1705. IN PFM_RESOURCE pResource
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. Post a worker item to process a cluster name change.
  1710. Arguments:
  1711. pResource - pointer to the resouce which is affected by the cluster
  1712. property change.
  1713. Return Value:
  1714. ERROR_SUCCESS if successful.
  1715. A Win32 error code on failure.
  1716. --*/
  1717. {
  1718. PFM_RESTYPE pResType;
  1719. DWORD dwError=ERROR_SUCCESS;
  1720. pResType = pResource->Type;
  1721. if ((pResource->ExFlags & CLUS_FLAG_CORE) &&
  1722. ( !lstrcmpiW(OmObjectId(pResType), CLUS_RESTYPE_NAME_NETNAME)))
  1723. {
  1724. FmResourceControl(pResource, NmLocalNode,
  1725. CLUSCTL_RESOURCE_CLUSTER_NAME_CHANGED, NULL, 0, NULL, 0, NULL, NULL);
  1726. }
  1727. return (dwError);
  1728. } // FmpClusterEventPropHandler
  1729. #endif
  1730. BOOL
  1731. FmpEnumResourceNodeEvict(
  1732. IN PVOID Context1,
  1733. IN PVOID Context2,
  1734. IN PVOID Object,
  1735. IN LPCWSTR Name
  1736. )
  1737. /*++
  1738. Routine Description:
  1739. Resource enumeration callback for removing node references when
  1740. a node is evicted.
  1741. Arguments:
  1742. Context1 - Supplies the node that is being evicted.
  1743. Context2 - not used
  1744. Object - Supplies a pointer to the resource object
  1745. Name - Supplies the resource's object name.
  1746. Return Value:
  1747. TRUE to continue enumeration
  1748. --*/
  1749. {
  1750. PFM_RESOURCE Resource = (PFM_RESOURCE)Object;
  1751. PNM_NODE Node = (PNM_NODE)Context1;
  1752. PLIST_ENTRY listEntry;
  1753. PPOSSIBLE_ENTRY possibleEntry;
  1754. ClRtlLogPrint(LOG_NOISE,
  1755. "[FM] EnumResourceNodeEvict: Removing references to node %1!ws! from resource %2!ws!\n",
  1756. OmObjectId(Node),
  1757. OmObjectId(Resource));
  1758. FmpAcquireLocalResourceLock(Resource);
  1759. FmpRemovePossibleNode(Resource, Node, TRUE);
  1760. FmpReleaseLocalResourceLock(Resource);
  1761. //
  1762. // Notify the resource of the removal of the node.
  1763. //
  1764. FmpRmResourceControl( Resource,
  1765. CLUSCTL_RESOURCE_EVICT_NODE,
  1766. (PUCHAR)OmObjectId(Node),
  1767. ((lstrlenW(OmObjectId(Node)) + 1) * sizeof(WCHAR)),
  1768. NULL,
  1769. 0,
  1770. NULL,
  1771. NULL );
  1772. // Ignore status return
  1773. ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE, Resource );
  1774. return(TRUE);
  1775. } // FmpEnumResourceNodeEvict
  1776. DWORD
  1777. FmpPrepareQuorumResChange(
  1778. IN PFM_RESOURCE pNewQuoRes,
  1779. IN LPCWSTR lpszQuoLogPath,
  1780. IN DWORD dwMaxQuoLogSize
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. This routine prepares for a quorum resource change operation.
  1785. Arguments:
  1786. pNewQuoRes - pointer to the new quorum resource.
  1787. lpszQuoLogPath - pointer to the quorum log path string name.
  1788. dwMaxQuoLogSize - the maximum size of the quorum log path string.
  1789. --*/
  1790. {
  1791. CL_ASSERT(pNewQuoRes->Group->OwnerNode == NmLocalNode);
  1792. return(DmPrepareQuorumResChange(pNewQuoRes, lpszQuoLogPath, dwMaxQuoLogSize));
  1793. } // FmpPrepareQuorumResChange
  1794. DWORD
  1795. FmpCompleteQuorumResChange(
  1796. IN LPCWSTR lpszOldQuoResId,
  1797. IN LPCWSTR lpszQuoLogPath
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. This routine is called if the new quorum log path is not the same as the old
  1802. quorum log path. This completes the change of quorum resource by deleting the old
  1803. quorum log files and creating a tompstone for them. A node that tries to do a form
  1804. with this as the quorum resource is prevented and has to do a join to get the location
  1805. of the new quorum resource and quorum log file.
  1806. Arguments:
  1807. pOldQuoRes - pointer to the new quorum resource.
  1808. lpszOldQuoLogPath - pointer to the quorum log path string name.
  1809. dwMaxQuoLogSize - the maximum size of the quorum log path string.
  1810. --*/
  1811. {
  1812. return(DmCompleteQuorumResChange(lpszOldQuoResId, lpszQuoLogPath));
  1813. } // FmpCompleteQuorumResChange
  1814. VOID
  1815. FmpResourceLastReference(
  1816. IN PFM_RESOURCE Resource
  1817. )
  1818. /*++
  1819. Routine Description:
  1820. Last dereference to resource object processing routine.
  1821. All cleanup for a resource should really be done here!
  1822. Arguments:
  1823. Resource - pointer the resource being removed.
  1824. Return Value:
  1825. None.
  1826. --*/
  1827. {
  1828. if ( Resource->DebugPrefix != NULL )
  1829. LocalFree(Resource->DebugPrefix);
  1830. if (Resource->Dependencies)
  1831. LocalFree(Resource->Dependencies);
  1832. if ( Resource->Group ) {
  1833. OmDereferenceObject(Resource->Group);
  1834. }
  1835. if (Resource->Type)
  1836. OmDereferenceObject(Resource->Type);
  1837. return;
  1838. } // FmpResourceLastReference
  1839. BOOL
  1840. FmpCheckNetworkDependencyWorker(
  1841. IN LPCWSTR DependentNetwork,
  1842. OUT PBOOL FoundDependency,
  1843. IN PFM_RESOURCE Resource,
  1844. IN LPCWSTR Name
  1845. )
  1846. /*++
  1847. Routine Description:
  1848. Enumeration callback routine for finding an IP Address resource
  1849. and checking its dependency on given network guid.
  1850. Arguments:
  1851. DependentNetwork - The GUID of the network to check for a dependency.
  1852. FoundDependency - Returns TRUE if a dependency is found.
  1853. Resource - Supplies the current resource.
  1854. Name - Supplies the current resource's name.
  1855. Return Value:
  1856. TRUE - to continue searching
  1857. FALSE - to stop the search. The matching resource is returned in
  1858. *FoundResource
  1859. Notes:
  1860. The IP Address resource's parameters are searched directly by this
  1861. routine. Fetching them from the resource itself causes a deadlock.
  1862. This routine is called by the NM from within a global udpate
  1863. handler. The resource would have to call back into the cluster registry
  1864. routines, which would deadlock over the GUM lock.
  1865. --*/
  1866. {
  1867. BOOL returnValue = TRUE;
  1868. if ( lstrcmpiW(
  1869. OmObjectId(Resource->Type),
  1870. CLUS_RESTYPE_NAME_IPADDR
  1871. ) == 0
  1872. )
  1873. {
  1874. LPCWSTR resourceId = OmObjectId(Resource);
  1875. DWORD status;
  1876. HDMKEY resourceKey = DmOpenKey(DmResourcesKey, resourceId, KEY_READ);
  1877. if (resourceKey != NULL) {
  1878. HDMKEY paramsKey = DmOpenKey(
  1879. resourceKey,
  1880. L"Parameters",
  1881. KEY_READ
  1882. );
  1883. if (paramsKey != NULL) {
  1884. LPWSTR networkId = NULL;
  1885. DWORD valueLength = 0, valueSize = 0;
  1886. status = DmQueryString(
  1887. paramsKey,
  1888. L"Network",
  1889. REG_SZ,
  1890. &networkId,
  1891. &valueLength,
  1892. &valueSize
  1893. );
  1894. if (status == ERROR_SUCCESS) {
  1895. if ( lstrcmpiW( networkId, DependentNetwork ) == 0 ) {
  1896. *FoundDependency = TRUE;
  1897. returnValue = FALSE;
  1898. }
  1899. LocalFree(networkId);
  1900. }
  1901. else {
  1902. ClRtlLogPrint(LOG_UNUSUAL,
  1903. "[NM] Query of Network value failed for ip addr resource %1!ws!, status %2!u!.\n",
  1904. resourceId,
  1905. status
  1906. );
  1907. }
  1908. DmCloseKey(paramsKey);
  1909. }
  1910. else {
  1911. status = GetLastError();
  1912. ClRtlLogPrint(LOG_UNUSUAL,
  1913. "[FM] Failed to open params key for resource %1!ws!, status %2!u!\n",
  1914. resourceId,
  1915. status
  1916. );
  1917. }
  1918. DmCloseKey(resourceKey);
  1919. }
  1920. else {
  1921. status = GetLastError();
  1922. ClRtlLogPrint(LOG_UNUSUAL,
  1923. "[FM] Failed to open key for resource %1!ws!, status %2!u!\n",
  1924. resourceId,
  1925. status
  1926. );
  1927. }
  1928. }
  1929. return(returnValue);
  1930. } // FmpCheckNetworkDependencyWorker
  1931. //lock must be held when this routine is called
  1932. DWORD FmpChangeResourceNode(
  1933. IN PFM_RESOURCE Resource,
  1934. IN LPCWSTR NodeId,
  1935. IN BOOL Add
  1936. )
  1937. {
  1938. PGUM_CHANGE_POSSIBLE_NODE GumChange;
  1939. LPCWSTR ResourceId;
  1940. DWORD ResourceLen;
  1941. DWORD NodeLen;
  1942. DWORD BufSize;
  1943. DWORD Status;
  1944. PLIST_ENTRY pListEntry;
  1945. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry = NULL;
  1946. BOOL bNodeSupportsResType = FALSE;
  1947. BOOL bRecalc = TRUE;
  1948. PPOSSIBLE_ENTRY PossibleEntry;
  1949. PNM_NODE pNode = NULL;
  1950. //cant remove possible node list from the quorum
  1951. //we should allow adding possible node lists to quorum to
  1952. //allow 3rd party quorum resource vendors to install their
  1953. //quorum resource incrementally on the nodes
  1954. if ( Resource->QuorumResource && !Add ) {
  1955. Status = ERROR_INVALID_OPERATION_ON_QUORUM;
  1956. goto FnExit;
  1957. }
  1958. //
  1959. // We can't allow the owner node to be removed if the state
  1960. // of the resource or the group is not offline or failed.
  1961. //
  1962. if ( !Add &&
  1963. (lstrcmpi(NodeId, OmObjectId(NmLocalNode)) == 0) &&
  1964. (((Resource->State != ClusterResourceOffline) &&
  1965. (Resource->State != ClusterResourceFailed)) ||
  1966. (FmpGetGroupState( Resource->Group, TRUE ) != ClusterGroupOffline)) ) {
  1967. Status = ERROR_INVALID_STATE;
  1968. goto FnExit;
  1969. }
  1970. //make sure the node is on the list of possible nodes for this
  1971. // resource type
  1972. if (Add)
  1973. {
  1974. //if it is already on the list, return an error and dont
  1975. //send a gum update call
  1976. pNode = OmReferenceObjectById(ObjectTypeNode, NodeId);
  1977. pListEntry = Resource->PossibleOwners.Flink;
  1978. while (pListEntry != &Resource->PossibleOwners) {
  1979. PossibleEntry = CONTAINING_RECORD( pListEntry,
  1980. POSSIBLE_ENTRY,
  1981. PossibleLinkage );
  1982. if (PossibleEntry->PossibleNode == pNode) {
  1983. //
  1984. // Found a match, fail the duplicate add. Note that
  1985. // we must fail here, not succeed, so that the API
  1986. // layer knows not to add a duplicate to the registry.
  1987. //
  1988. Status = ERROR_OBJECT_ALREADY_EXISTS;
  1989. goto FnExit;
  1990. }
  1991. pListEntry = pListEntry->Flink;
  1992. }
  1993. ChkResTypeList:
  1994. pListEntry = &(Resource->Type->PossibleNodeList);
  1995. for (pListEntry = pListEntry->Flink;
  1996. pListEntry != &(Resource->Type->PossibleNodeList);
  1997. pListEntry = pListEntry->Flink)
  1998. {
  1999. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  2000. PossibleLinkage);
  2001. if (!lstrcmpW(OmObjectId(pResTypePosEntry->PossibleNode), NodeId))
  2002. {
  2003. bNodeSupportsResType = TRUE;
  2004. break;
  2005. }
  2006. }
  2007. if (!bNodeSupportsResType && bRecalc)
  2008. {
  2009. //if th node is not found, recalc again and retry..since then the
  2010. //dll might have been copied to this node
  2011. FmpSetPossibleNodeForResType(OmObjectId(Resource->Type), TRUE);
  2012. bRecalc = FALSE;
  2013. goto ChkResTypeList;
  2014. }
  2015. if (!bNodeSupportsResType)
  2016. {
  2017. Status = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
  2018. goto FnExit;
  2019. }
  2020. }
  2021. ResourceId = OmObjectId(Resource);
  2022. ResourceLen = (lstrlenW(ResourceId)+1)*sizeof(WCHAR);
  2023. NodeLen = (lstrlenW(NodeId)+1)*sizeof(WCHAR);
  2024. BufSize = sizeof(GUM_CHANGE_POSSIBLE_NODE) - sizeof(WCHAR) + ResourceLen + NodeLen;
  2025. GumChange = LocalAlloc(LMEM_FIXED, BufSize);
  2026. if (GumChange == NULL) {
  2027. CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
  2028. Status = ERROR_NOT_ENOUGH_MEMORY;
  2029. goto FnExit;
  2030. }
  2031. GumChange->ResourceIdLen = ResourceLen;
  2032. CopyMemory(GumChange->ResourceId, ResourceId, ResourceLen);
  2033. CopyMemory((PCHAR)GumChange->ResourceId + ResourceLen,
  2034. NodeId,
  2035. NodeLen);
  2036. Status = GumSendUpdate(GumUpdateFailoverManager,
  2037. Add ? FmUpdateAddPossibleNode : FmUpdateRemovePossibleNode,
  2038. BufSize,
  2039. GumChange);
  2040. LocalFree(GumChange);
  2041. FnExit:
  2042. if (pNode)
  2043. OmDereferenceObject(pNode);
  2044. return(Status);
  2045. }
  2046. BOOL
  2047. FmpCheckNetworkDependency(
  2048. IN LPCWSTR DependentNetwork
  2049. )
  2050. /*++
  2051. Routine Description:
  2052. Checks for an IP Address resource that may be dependent on the given
  2053. Network.
  2054. Arguments:
  2055. DependentNetwork - the dependent network to check for.
  2056. Returns:
  2057. TRUE - if an IP Address depends on the given network.
  2058. FALSE otherwise.
  2059. --*/
  2060. {
  2061. BOOL dependent = FALSE;
  2062. OmEnumObjects(ObjectTypeResource,
  2063. (OM_ENUM_OBJECT_ROUTINE)FmpCheckNetworkDependencyWorker,
  2064. (PVOID)DependentNetwork,
  2065. &dependent);
  2066. return(dependent);
  2067. } // FmpCheckNetworkDependency
  2068. /****
  2069. @func DWORD | FmpFixupPossibleNodesForResources| This fixes the possible
  2070. node information for a resource based on whether this node
  2071. supports the given resource type.
  2072. @parm IN BOOL| bJoin | If this node is joining, bJoin is set to TRUE.
  2073. @comm This routine iterates thru all the resources in a system and fixes
  2074. their possible node information. If this node is not on the possible
  2075. node list for the resource type corresponding to the resource, it
  2076. is also removed from the possible node list for the resource.
  2077. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2078. @xref <f FmpEnumFixupPossibleNodeForResource>
  2079. ****/
  2080. DWORD
  2081. FmpFixupPossibleNodesForResources(
  2082. BOOL bJoin
  2083. )
  2084. {
  2085. DWORD dwStatus=ERROR_SUCCESS;
  2086. ClRtlLogPrint(LOG_NOISE,"[FM] FmpFixupPossibleNodesForResources Entry.\n");
  2087. //
  2088. // Fix up all resources's possible node list information
  2089. //
  2090. OmEnumObjects( ObjectTypeResource,
  2091. FmpEnumFixupPossibleNodesForResource,
  2092. NULL,
  2093. NULL);
  2094. ClRtlLogPrint(LOG_NOISE,"[FM] FmpFixupPossibleNodesForResources Exit\r\n");
  2095. return(dwStatus);
  2096. } // FmpFixupPossibleNodesForResources
  2097. /****
  2098. @func DWORD | FmpEnumFixupPossibleNodesForResource | This is the enumeration
  2099. callback for every resource type to fix the possible node
  2100. information related with it.
  2101. @parm IN PVOID | pContext1 | Not used.
  2102. @parm IN PVOID | pContext2 | Not Used.
  2103. @parm IN PFM_RESTYPE | pResType | Pointer to the resource type object.
  2104. @parm IN LPCWSTR | pszResTypeName | The name of the resource type.
  2105. @comm This routine iterates thru all the resources in a system and fixes
  2106. their possible node information. If this node is not on the possible
  2107. node list for the resource type corresponding to the resource, it
  2108. is also removed from the possible node list for the resource.
  2109. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2110. @xref <f FmpFixupPossibleNodesForResources>
  2111. ****/
  2112. BOOL
  2113. FmpEnumFixupPossibleNodesForResource(
  2114. IN PVOID pContext1,
  2115. IN PVOID pContext2,
  2116. IN PFM_RESOURCE pResource,
  2117. IN LPCWSTR pszResName
  2118. )
  2119. {
  2120. //if we are on the possible node list for the
  2121. //resource but not for the resource type, remove it
  2122. //from the possible node for the resource as well.
  2123. //We do this because the join logic adds all nodes
  2124. //as possible owners for a resource and we have
  2125. //the rolling upgrade requirements - hence the fixups
  2126. //have to be made later on
  2127. if ((FmpInPossibleListForResource(pResource, NmLocalNode)) &&
  2128. !(FmpInPossibleListForResType(pResource->Type, NmLocalNode)))
  2129. {
  2130. //if we dont support this resource type, make sure it is not on the possible node
  2131. //list for a resource of this type
  2132. ClRtlLogPrint(LOG_NOISE,
  2133. "[FM] FmpEnumFixupPossibleNode:remove local node for resource %1!ws!\r\n",
  2134. OmObjectId(pResource));
  2135. //we send a gum update to remove it from all nodes
  2136. FmChangeResourceNode(pResource, NmLocalNode, FALSE);
  2137. }
  2138. //we add ourselves on the list only on a fresh install
  2139. //not on an upgrade
  2140. //csfirst run is also true on an upgrade, hence we need to
  2141. //check that csupgrade is false
  2142. if ((!FmpInPossibleListForResource(pResource, NmLocalNode)) &&
  2143. (FmpInPossibleListForResType(pResource->Type, NmLocalNode))
  2144. && CsFirstRun && !CsUpgrade)
  2145. {
  2146. //if we support a resource of this type, but we are not on the possible
  2147. //list for this resource, then add the local node to the possible list
  2148. //this may happen because on a setup join the other nodes may not
  2149. //add us because the possible node list exists. The possible node list
  2150. //may exist either because the user set it or we internally set it due
  2151. //to non availability of this resource type dll on one of the nodes
  2152. //Note that irrespective of whether the user had set the possible list
  2153. //or we set it internally, we always add a new node that joins
  2154. //to the possible node list of resources that are supported.
  2155. ClRtlLogPrint(LOG_NOISE,
  2156. "[FM] FmpEnumFixupPossibleNode:add local node for resource %1!ws!\r\n",
  2157. OmObjectId(pResource));
  2158. //we send a gum update to add it from all nodes
  2159. FmChangeResourceNode(pResource, NmLocalNode, TRUE);
  2160. }
  2161. //continue enumeration
  2162. return (TRUE);
  2163. }
  2164. DWORD FmpCleanupPossibleNodeList(
  2165. IN PFM_RESOURCE pResource)
  2166. {
  2167. PLIST_ENTRY pListEntry;
  2168. PPOSSIBLE_ENTRY pPossibleEntry;
  2169. DWORD dwStatus = ERROR_SUCCESS;
  2170. //for all possible nodes for this resource, check if the resource type
  2171. //supports it. If it doesnt, then remove that node from the in memory list
  2172. pListEntry = pResource->PossibleOwners.Flink;
  2173. while (pListEntry != &pResource->PossibleOwners)
  2174. {
  2175. //get the possible entry at this link
  2176. pPossibleEntry = CONTAINING_RECORD( pListEntry,
  2177. POSSIBLE_ENTRY,
  2178. PossibleLinkage );
  2179. //save the pointer to the next link
  2180. pListEntry = pListEntry->Flink;
  2181. if (!FmpInPossibleListForResType(pResource->Type,
  2182. pPossibleEntry->PossibleNode))
  2183. {
  2184. ClRtlLogPrint(LOG_NOISE,
  2185. "[FM] FmpCleanupPossibleNodeList:remove local node %1!u! for resource %2!ws!\r\n",
  2186. NmGetNodeId(pPossibleEntry->PossibleNode), OmObjectId(pResource));
  2187. FmChangeResourceNode(pResource, pPossibleEntry->PossibleNode,
  2188. FALSE);
  2189. }
  2190. }
  2191. return (dwStatus);
  2192. }
  2193. /****
  2194. @func DWORD | FmpInPossibleListForResource| This checks if a given node
  2195. is in the possible list of nodes for a resource.
  2196. @parm IN PFM_RESOURCE | pResource | A pointer to the the resource.
  2197. @parm IN PNM_NODE | pNode | A pointer to the node object.
  2198. @comm This routine check if a node is in the list of possible nodes
  2199. for this resource.
  2200. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2201. @xref <f FmpInPossibleListForResType>
  2202. ****/
  2203. BOOL
  2204. FmpInPossibleListForResource(
  2205. IN PFM_RESOURCE pResource,
  2206. IN PNM_NODE pNode
  2207. )
  2208. {
  2209. PLIST_ENTRY plistEntry;
  2210. PPOSSIBLE_ENTRY pPossibleEntry;
  2211. //see if this node is on the possible node list for the resource
  2212. for ( plistEntry = pResource->PossibleOwners.Flink;
  2213. plistEntry != &(pResource->PossibleOwners);
  2214. plistEntry = plistEntry->Flink ) {
  2215. pPossibleEntry = CONTAINING_RECORD( plistEntry,
  2216. POSSIBLE_ENTRY,
  2217. PossibleLinkage );
  2218. if ( pPossibleEntry->PossibleNode == pNode ) {
  2219. return(TRUE);
  2220. }
  2221. }
  2222. return(FALSE);
  2223. } // FmpInPossibleListForResource
  2224. /****
  2225. @func DWORD | FmpInPossibleListForResType| This checks if a given node
  2226. is in the possible list of nodes for a resource type.
  2227. @parm IN PFM_RESTYPE| pResType | A pointer to the the resource type.
  2228. @parm IN PNM_NODE | pNode | A pointer to the node object.
  2229. @comm This routine check if a node is in the list of possible nodes
  2230. for this resource type.
  2231. @rdesc Returns a result code. ERROR_SUCCESS on success.
  2232. @xref <f FmpInPossibleListForResource>
  2233. ****/
  2234. BOOL
  2235. FmpInPossibleListForResType(
  2236. IN PFM_RESTYPE pResType,
  2237. IN PNM_NODE pNode
  2238. )
  2239. {
  2240. PLIST_ENTRY pListEntry;
  2241. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry;
  2242. ACQUIRE_SHARED_LOCK(gResTypeLock);
  2243. //see if this node is on the possible node list for the resource
  2244. for ( pListEntry = pResType->PossibleNodeList.Flink;
  2245. pListEntry != &(pResType->PossibleNodeList);
  2246. pListEntry = pListEntry->Flink )
  2247. {
  2248. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  2249. PossibleLinkage);
  2250. if ( pResTypePosEntry->PossibleNode == pNode )
  2251. {
  2252. RELEASE_LOCK(gResTypeLock);
  2253. return(TRUE);
  2254. }
  2255. }
  2256. RELEASE_LOCK(gResTypeLock);
  2257. return(FALSE);
  2258. } // FmpInPossibleListForResType
  2259. DWORD
  2260. FmpValAddResourceDependency(
  2261. IN PFM_RESOURCE pResource,
  2262. IN PFM_RESOURCE pDependentResource
  2263. )
  2264. /*++
  2265. Routine Description:
  2266. Add a dependency from one resource to another.
  2267. Arguments:
  2268. Resource - The resource to add the dependent resource.
  2269. DependentResource - The dependent resource.
  2270. Returns:
  2271. ERROR_SUCCESS if successful.
  2272. A Win32 error code on failure.
  2273. --*/
  2274. {
  2275. DWORD dwStatus = ERROR_SUCCESS;
  2276. //
  2277. // If the resource or dependent resource have been marked for
  2278. // delete, then dont let a dependency be added.
  2279. //
  2280. if ((!IS_VALID_FM_RESOURCE(pResource)) ||
  2281. (!IS_VALID_FM_RESOURCE(pDependentResource)))
  2282. {
  2283. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  2284. goto FnExit;
  2285. }
  2286. if (pResource->QuorumResource)
  2287. {
  2288. dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED;
  2289. goto FnExit;
  2290. }
  2291. //
  2292. // If the resources are not in the same group, fail the
  2293. // call. Also fail if some one tries to make a resource
  2294. // dependent upon itself.
  2295. //
  2296. if ((pResource->Group != pDependentResource->Group) ||
  2297. (pResource == pDependentResource))
  2298. {
  2299. dwStatus = ERROR_INVALID_PARAMETER;
  2300. goto FnExit;
  2301. }
  2302. // The resource to which the dependency is being added must be offline
  2303. // Otherwise, it looks like the dependency is in effect when the depending
  2304. // resource was not really brought online at the time the dependency
  2305. // existed
  2306. // must also be offline or failed.
  2307. // SS: For instance if a network name is dependent on two ip addresesses
  2308. // and
  2309. // is online and a third ip address resource dependency is added, the
  2310. // network name must be brought offline and online for the dependency
  2311. // to be truly in effect
  2312. //
  2313. if ((pResource->State != ClusterResourceOffline) &&
  2314. (pResource->State != ClusterResourceFailed))
  2315. {
  2316. dwStatus = ERROR_RESOURCE_ONLINE;
  2317. goto FnExit;
  2318. }
  2319. //
  2320. // Make sure that we don't have any circular dependencies!
  2321. //
  2322. if ( FmDependentResource( pDependentResource, pResource, FALSE ) )
  2323. {
  2324. dwStatus = ERROR_CIRCULAR_DEPENDENCY;
  2325. goto FnExit;
  2326. }
  2327. //
  2328. // Make sure that this dependency does not already exist!
  2329. //
  2330. if ( FmDependentResource(pResource, pDependentResource, TRUE))
  2331. {
  2332. dwStatus = ERROR_DEPENDENCY_ALREADY_EXISTS;
  2333. goto FnExit;
  2334. }
  2335. FnExit:
  2336. return(dwStatus);
  2337. } // FmpValAddResourceDependency
  2338. DWORD
  2339. FmpValRemoveResourceDependency(
  2340. IN PFM_RESOURCE pResource,
  2341. IN PFM_RESOURCE pDependentResource
  2342. )
  2343. /*++
  2344. Routine Description:
  2345. Validation routine for dependency removal.
  2346. Arguments:
  2347. pResource - The resource to remove the dependent resource.
  2348. pDependentResource - The dependent resource.
  2349. Returns:
  2350. ERROR_SUCCESS if the validation is successful.
  2351. A Win32 error code if the validation fails.
  2352. --*/
  2353. {
  2354. DWORD dwStatus = ERROR_SUCCESS;
  2355. //
  2356. // Chittur Subbaraman (chitturs) - 8/3/99
  2357. //
  2358. // This function checks whether it is legal to remove the dependency
  2359. // relationship between 2 resources. Note that this function only
  2360. // does a partial validation, the rest is done in the GUM handler.
  2361. //
  2362. //
  2363. // If the resource has been marked for delete, then dont
  2364. // let any dependency changes be made.
  2365. //
  2366. if ( !IS_VALID_FM_RESOURCE( pResource ) )
  2367. {
  2368. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  2369. goto FnExit;
  2370. }
  2371. if ( pResource->QuorumResource )
  2372. {
  2373. dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED;
  2374. goto FnExit;
  2375. }
  2376. //
  2377. // If the resources are not in the same group, fail the
  2378. // call. Also fail if some one tries to make a resource
  2379. // dependent upon itself.
  2380. //
  2381. if ( ( pResource->Group != pDependentResource->Group ) ||
  2382. ( pResource == pDependentResource ) )
  2383. {
  2384. dwStatus = ERROR_INVALID_PARAMETER;
  2385. goto FnExit;
  2386. }
  2387. //
  2388. // Ensure that both the resource and the dependent resource are in
  2389. // a stable state. This is necessary to prevent cases in which the
  2390. // user gets rid of a dependency link when one of the resources is in
  2391. // a pending state and later when the notification from resmon comes
  2392. // in and you try to stablize the rest of the waiting tree, the
  2393. // dependency link is already cut and so the rest of the tree is
  2394. // stuck in pending state for ever !
  2395. //
  2396. if ( ( pResource->State > ClusterResourcePending ) ||
  2397. ( pDependentResource->State > ClusterResourcePending ) )
  2398. {
  2399. dwStatus = ERROR_INVALID_STATE;
  2400. goto FnExit;
  2401. }
  2402. FnExit:
  2403. return( dwStatus );
  2404. } // FmpValRemoveResourceDependency
  2405. VOID
  2406. FmpNotifyResourceStateChangeReason(
  2407. IN PFM_RESOURCE pResource,
  2408. IN CLUSTER_RESOURCE_STATE_CHANGE_REASON eReason
  2409. )
  2410. /*++
  2411. Routine Description:
  2412. Notify a resource DLL about the reason for a state change.
  2413. Arguments:
  2414. pResource - The resource to be notified.
  2415. eReason - The reason for the state change.
  2416. Returns:
  2417. None.
  2418. Comments:
  2419. This function will drop the notification only to those resources that support the
  2420. CLUS_CHAR_REQUIRES_STATE_CHANGE_REASON characteristics. This function MUST be called
  2421. with local group lock held.
  2422. --*/
  2423. {
  2424. DWORD dwStatus = ERROR_SUCCESS;
  2425. DWORD dwCharacteristics = 0;
  2426. CLUSCTL_RESOURCE_STATE_CHANGE_REASON_STRUCT ClusterResourceStateChangeReason;
  2427. //
  2428. // Make sure the state change reason is a valid one.
  2429. //
  2430. if ( eReason == eResourceStateChangeReasonUnknown )
  2431. {
  2432. ClRtlLogPrint(LOG_UNUSUAL,
  2433. "[FM] FmpNotifyResourceStateChangeReason: Invalid state change reason specified for resource %1!ws!...\n",
  2434. OmObjectId(pResource));
  2435. CL_ASSERT( FALSE );
  2436. goto FnExit;
  2437. }
  2438. //
  2439. // First of, check if the resource needs this state change notification.
  2440. //
  2441. dwStatus = FmpRmResourceControl( pResource,
  2442. CLUSCTL_RESOURCE_GET_CHARACTERISTICS,
  2443. NULL,
  2444. 0,
  2445. ( PUCHAR ) &dwCharacteristics,
  2446. sizeof( DWORD ),
  2447. NULL,
  2448. NULL );
  2449. if ( ( dwStatus != ERROR_SUCCESS ) ||
  2450. !( dwCharacteristics & CLUS_CHAR_REQUIRES_STATE_CHANGE_REASON ) )
  2451. {
  2452. goto FnExit;
  2453. }
  2454. ClRtlLogPrint(LOG_NOISE,
  2455. "[FM] FmpNotifyResourceStateChangeReason: Resource %1!ws! [%2!ws!], Reason specified=%3!u!...\n",
  2456. OmObjectName(pResource),
  2457. OmObjectId(pResource),
  2458. eReason);
  2459. //
  2460. // This resource needs the state change reason. Drop it down to this resource.
  2461. //
  2462. ClusterResourceStateChangeReason.dwSize = sizeof ( CLUSCTL_RESOURCE_STATE_CHANGE_REASON_STRUCT );
  2463. ClusterResourceStateChangeReason.dwVersion = CLUSCTL_RESOURCE_STATE_CHANGE_REASON_VERSION_1;
  2464. ClusterResourceStateChangeReason.eReason = eReason;
  2465. dwStatus = FmpRmResourceControl( pResource,
  2466. CLUSCTL_RESOURCE_STATE_CHANGE_REASON,
  2467. ( PUCHAR ) &ClusterResourceStateChangeReason,
  2468. ClusterResourceStateChangeReason.dwSize,
  2469. NULL,
  2470. 0,
  2471. NULL,
  2472. NULL );
  2473. ClRtlLogPrint(LOG_NOISE,
  2474. "[FM] FmpNotifyResourceStateChangeReason: Notified state change reason with status %1!u!...\n",
  2475. dwStatus);
  2476. FnExit:
  2477. return;
  2478. } // FmpNotifyResourceStateChangeReason