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.

3773 lines
106 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. fmapi.c
  5. Abstract:
  6. Cluster manager api service routines.
  7. Author:
  8. Rod Gamache (rodga) 8-Mar-1996
  9. Revision History:
  10. --*/
  11. #include "fmp.h"
  12. #define LOG_MODULE FMAPI
  13. //
  14. // Local Functions
  15. //
  16. DWORD
  17. FmpCanonicalizePath(
  18. IN OUT LPWSTR lpszPath,
  19. OUT PBOOL pfIsPathUNC
  20. );
  21. //
  22. // Functions Exported to the rest of the Cluster Manager
  23. //
  24. ////////////////////////////////////////////////////////
  25. //
  26. // Group management functions.
  27. //
  28. ////////////////////////////////////////////////////////
  29. DWORD
  30. WINAPI
  31. FmOnlineGroup(
  32. IN PFM_GROUP Group
  33. )
  34. /*++
  35. Routine Description:
  36. Bring the specified group online. This means bringing all of the
  37. individual resources contained within the group online. This is an
  38. atomic operation - so either all resources contained within the group
  39. are brought online, or none of them are.
  40. Arguments:
  41. Group - Supplies a pointer to the group structure to bring online.
  42. Retruns:
  43. ERROR_SUCCESS if the request was successful.
  44. A Win32 error code on failure.
  45. --*/
  46. {
  47. DWORD status;
  48. PLIST_ENTRY listEntry;
  49. FmpMustBeOnline( );
  50. FmpAcquireLocalGroupLock( Group );
  51. //if the group has been marked for delete, then fail this call
  52. if (!IS_VALID_FM_GROUP(Group))
  53. {
  54. FmpReleaseLocalGroupLock( Group);
  55. return (ERROR_GROUP_NOT_AVAILABLE);
  56. }
  57. //
  58. // Make sure the owning node is not paused.
  59. //
  60. if (NmGetNodeState(Group->OwnerNode) == ClusterNodePaused) {
  61. FmpReleaseLocalGroupLock( Group );
  62. return(ERROR_SHARING_PAUSED);
  63. }
  64. //
  65. // Check if we are the owner... if not, ship the request off someplace
  66. // else.
  67. //
  68. if ( Group->OwnerNode != NmLocalNode ) {
  69. FmpReleaseLocalGroupLock( Group );
  70. return(FmcOnlineGroupRequest(Group));
  71. }
  72. //
  73. // Set the PersistentState for this Group - the PersistentState is persistent.
  74. //
  75. FmpSetGroupPersistentState( Group, ClusterGroupOnline );
  76. status = FmpOnlineGroup( Group, TRUE );
  77. FmpReleaseLocalGroupLock( Group );
  78. return(status);
  79. } // FmOnlineGroup
  80. DWORD
  81. WINAPI
  82. FmOfflineGroup(
  83. IN PFM_GROUP Group
  84. )
  85. /*++
  86. Routine Description:
  87. Bring the specified group offline. This means bringing all of the
  88. individual resources contained within the group offline.
  89. Arguments:
  90. Group - Supplies a pointer to the group structure to bring offline.
  91. Returns:
  92. ERROR_SUCCESS if the request was successful.
  93. A Win32 error code on failure.
  94. --*/
  95. {
  96. DWORD status = ERROR_SUCCESS;
  97. PLIST_ENTRY listEntry;
  98. PFM_RESOURCE Resource;
  99. FmpMustBeOnline( );
  100. //
  101. // Check if we are the owner... if not, ship the request off to some
  102. // other place.
  103. //
  104. if ( Group->OwnerNode != NmLocalNode ) {
  105. return(FmcOfflineGroupRequest(Group));
  106. }
  107. //
  108. // Set the PersistentState for this Group - the PersistentState is persistent.
  109. //
  110. FmpSetGroupPersistentState( Group, ClusterGroupOffline );
  111. status = FmpOfflineGroup( Group, FALSE, TRUE);
  112. return(status);
  113. } // FmOfflineGroup
  114. DWORD
  115. WINAPI
  116. FmMoveGroup(
  117. IN PFM_GROUP Group,
  118. IN PNM_NODE DestinationNode OPTIONAL
  119. )
  120. /*++
  121. Routine Description:
  122. Failover the specified Group. This means taking all of the individual
  123. resources contained within the group offline and requesting the
  124. DestinationNode to bring the Group Online.
  125. Arguments:
  126. Group - Supplies a pointer to the group structure to move.
  127. DestinationNode - Supplies the node object to move the group to. If not
  128. present, then move it to THE OTHER node.
  129. Returns:
  130. ERROR_SUCCESS if the request was successful.
  131. A Win32 error code on failure.
  132. Notes:
  133. The Group may or may not be online on the DestinationNode, depending on
  134. whether the online request succeeded. This means that the status return
  135. is merely the status return for the Online request for the DestinationNode.
  136. --*/
  137. {
  138. FmpMustBeOnline( );
  139. return(FmpDoMoveGroup( Group, DestinationNode, TRUE ));
  140. } // FmMoveGroup
  141. PFM_GROUP
  142. WINAPI
  143. FmCreateGroup(
  144. IN LPWSTR GroupId,
  145. IN LPCWSTR GroupName
  146. )
  147. /*++
  148. Routine Description:
  149. Create the specified GroupId. This requires verifying that the
  150. specified GroupId does not already exist and then creating an
  151. empty Group container into which resources can be added.
  152. Note that the returned PFM_GROUP will have already been referenced.
  153. This prevents somebody from deleting the group before the caller
  154. gets a chance to reference it.
  155. Arguments:
  156. GroupId - Supplies the Id of the Group to create.
  157. GroupName - Supplies the 'user-friendly' name of the Group.
  158. Returns:
  159. Pointer to the newly created group if successful.
  160. NULL if unsuccessful. GetLastError() will return the specific error.
  161. --*/
  162. {
  163. DWORD Status;
  164. PFM_GROUP Group;
  165. PGUM_CREATE_GROUP GumGroup;
  166. DWORD BufSize;
  167. DWORD GroupIdLen;
  168. DWORD GroupNameLen;
  169. FmpMustBeOnlineEx( NULL );
  170. //
  171. // Allocate a message buffer.
  172. //
  173. GroupIdLen = (lstrlenW(GroupId)+1)*sizeof(WCHAR);
  174. GroupNameLen = (lstrlenW(GroupName)+1)*sizeof(WCHAR);
  175. BufSize = sizeof(GUM_CREATE_GROUP) - sizeof(WCHAR) + GroupIdLen +
  176. GroupNameLen + (lstrlenW( OmObjectId(NmLocalNode) ) + 1) * sizeof(WCHAR);
  177. GumGroup = LocalAlloc(LMEM_FIXED, BufSize);
  178. if (GumGroup == NULL) {
  179. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmCreateGroup: Unable to alloc mem for group <%1!ws!>....\n",
  180. GroupName);
  181. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  182. return(NULL);
  183. }
  184. //
  185. // Fill in message buffer.
  186. //
  187. GumGroup->Group = NULL;
  188. GumGroup->GroupIdLen = GroupIdLen;
  189. GumGroup->GroupNameLen = GroupNameLen;
  190. wcscpy(GumGroup->GroupId, GroupId);
  191. CopyMemory((PCHAR)GumGroup->GroupId + GroupIdLen,
  192. GroupName,
  193. GroupNameLen);
  194. CopyMemory((PCHAR)GumGroup->GroupId + GroupIdLen + GroupNameLen,
  195. OmObjectId(NmLocalNode),
  196. (lstrlenW( OmObjectId(NmLocalNode) ) + 1) * sizeof(WCHAR));
  197. //
  198. // Send message.
  199. //
  200. Status = GumSendUpdate(GumUpdateFailoverManager,
  201. FmUpdateCreateGroup,
  202. BufSize,
  203. GumGroup);
  204. if ((GumGroup->Group == NULL) && (FmpShutdown)) {
  205. Status = ERROR_CLUSTER_NODE_SHUTTING_DOWN;
  206. }
  207. if (Status != ERROR_SUCCESS) {
  208. LocalFree(GumGroup);
  209. SetLastError(Status);
  210. return(NULL);
  211. }
  212. Group = GumGroup->Group;
  213. CL_ASSERT(Group != NULL);
  214. LocalFree(GumGroup);
  215. return(Group);
  216. } // FmCreateGroup
  217. DWORD
  218. WINAPI
  219. FmDeleteGroup(
  220. IN PFM_GROUP pGroup
  221. )
  222. /*--
  223. Routine Description:
  224. Delete the specified Group. This means verifying that the specified
  225. Group does not contain any resources (resources must be removed
  226. by a separate call to remove the resources), and then deleting the
  227. Group.
  228. Arguments:
  229. Group - Supplies the Group to delete.
  230. Returns:
  231. ERROR_SUCCESS if the request was successful.
  232. A Win32 error code on failure.
  233. --*/
  234. {
  235. DWORD dwStatus;
  236. FmpMustBeOnline( );
  237. FmpAcquireLocalGroupLock( pGroup );
  238. if (pGroup->OwnerNode == NmLocalNode)
  239. {
  240. dwStatus = FmpDeleteGroup(pGroup);
  241. }
  242. else
  243. {
  244. //
  245. // FmcDeleteGroup releases the group lock
  246. //
  247. dwStatus = FmcDeleteGroupRequest(pGroup);
  248. goto FnExit;
  249. }
  250. FmpReleaseLocalGroupLock(pGroup);
  251. FnExit:
  252. return(dwStatus);
  253. } // FmDeleteGroup
  254. DWORD
  255. WINAPI
  256. FmSetGroupName(
  257. IN PFM_GROUP Group,
  258. IN LPCWSTR FriendlyName
  259. )
  260. /*++
  261. Routine Description:
  262. Set the user-friendly name for the specified Group.
  263. Note that the Group must have already been created. It is also
  264. assumed that the caller of this routine (the cluster API) has already
  265. verified that the name is NOT a duplicate.
  266. Arguments:
  267. Group - Supplies the Group to enter a new name.
  268. FriendlyName - Supplies the user-friendly name for the resource.
  269. Returns:
  270. ERROR_SUCCESS if successful.
  271. A Win32 error code on failure.
  272. --*/
  273. {
  274. LPCWSTR GroupId;
  275. DWORD Status;
  276. GroupId = OmObjectId(Group);
  277. Status = GumSendUpdateEx(GumUpdateFailoverManager,
  278. FmUpdateChangeGroupName,
  279. 2,
  280. (lstrlenW(GroupId)+1)*sizeof(WCHAR),
  281. GroupId,
  282. (lstrlenW(FriendlyName)+1)*sizeof(WCHAR),
  283. FriendlyName);
  284. return(Status);
  285. } // FmSetGroupName
  286. CLUSTER_GROUP_STATE
  287. WINAPI
  288. FmGetGroupState(
  289. IN PFM_GROUP Group,
  290. OUT LPWSTR NodeName,
  291. IN OUT PDWORD NameLength OPTIONAL
  292. )
  293. /*++
  294. Routine Description:
  295. Get the current state for the specified Group. The Group state
  296. consists of state of the group, along with the current node that is
  297. hosting the Group (if the state of the Group is anything but
  298. ClusterGroupOffline.
  299. Arguments:
  300. Group - Supplies the group object to get the state.
  301. NodeName - Supplies a pointer to a buffer into which the name of
  302. the node in the cluster the specified Group is currently hosted.
  303. This field can be NULL, if NameLength is zero.
  304. NameLength - Supplies a pointer to a DWORD containing the number of
  305. characters available to the NodeName buffer (including the terminating
  306. NULL character. On return, it is the number of characters written
  307. into the NodeName buffer not including the NULL character.
  308. Returns:
  309. Returns the current state of the group:
  310. ClusterGroupOnline
  311. ClusterGroupOffline
  312. ClusterGroupPending
  313. ClusterGroupPartialOnline
  314. ClusterGroupFailed
  315. If the function fails, then the return value is ClusterGroupStateUnknown.
  316. --*/
  317. {
  318. CLUSTER_GROUP_STATE state;
  319. DWORD nameLength=0;
  320. DWORD length;
  321. if ( ARGUMENT_PRESENT( NameLength ) ) {
  322. nameLength = *NameLength;
  323. *NodeName = (WCHAR)0;
  324. *NameLength = 0;
  325. }
  326. FmpMustBeOnlineEx( ClusterGroupStateUnknown );
  327. FmpAcquireLocalGroupLock( Group );
  328. //if the group has been marked for delete, then fail this call
  329. if (!IS_VALID_FM_GROUP(Group))
  330. {
  331. FmpReleaseLocalGroupLock( Group);
  332. return (ERROR_GROUP_NOT_AVAILABLE);
  333. }
  334. //
  335. // Check if the OwnerNodes exists
  336. //
  337. // SS: dont filter out the node if it not in the preferred list
  338. // how is the poor user going to know who the current owner is??
  339. if (Group->OwnerNode != NULL) {
  340. //
  341. // The Group is 'owned' by some system
  342. //
  343. if ( ARGUMENT_PRESENT( NameLength ) ) {
  344. length = lstrlenW( OmObjectName(Group->OwnerNode) ) + 1;
  345. if ( nameLength < length ) {
  346. length = nameLength;
  347. }
  348. lstrcpynW( NodeName, OmObjectName(Group->OwnerNode), length );
  349. *NameLength = length;
  350. }
  351. }
  352. //
  353. // Get the group state which is not normalized
  354. //
  355. state = FmpGetGroupState( Group, FALSE );
  356. FmpReleaseLocalGroupLock( Group );
  357. if ( state == ClusterGroupStateUnknown ) {
  358. SetLastError(ERROR_INVALID_STATE);
  359. }
  360. return(state);
  361. } // FmGetGroupState
  362. DWORD
  363. WINAPI
  364. FmEnumerateGroupResources(
  365. IN PFM_GROUP Group,
  366. IN FM_ENUM_GROUP_RESOURCE_ROUTINE EnumerationRoutine,
  367. IN PVOID Context1,
  368. IN PVOID Context2
  369. )
  370. /*++
  371. Routine Description:
  372. Enumerate all the resources in a group.
  373. Arguments:
  374. Group - Supplies the group which must be enumerated.
  375. EnumerationRoutine - The enumeration function.
  376. Context1 - The enumeration list (allocated by the caller).
  377. Context2 - Size of the enumerated list.
  378. Returns:
  379. ERROR_SUCCESS on success.
  380. A Win32 error code otherwise.
  381. Comments:
  382. This function executes only when the FM is fully online.
  383. --*/
  384. {
  385. FmpMustBeOnline();
  386. FmpEnumerateGroupResources( Group,
  387. EnumerationRoutine,
  388. Context1,
  389. Context2 );
  390. return(ERROR_SUCCESS);
  391. } // FmEnumerateGroupResources
  392. DWORD
  393. FmpEnumerateGroupResources(
  394. IN PFM_GROUP pGroup,
  395. IN FM_ENUM_GROUP_RESOURCE_ROUTINE pfnEnumerationRoutine,
  396. IN PVOID pContext1,
  397. IN PVOID pContext2
  398. )
  399. /*++
  400. Routine Description:
  401. Enumerate all the resources in a group.
  402. Arguments:
  403. pGroup - Supplies the group which must be enumerated.
  404. pfnEnumerationRoutine - The enumeration function.
  405. pContext1 - The enumeration list (allocated by the caller).
  406. pContext2 - Size of the enumerated list.
  407. Returns:
  408. ERROR_SUCCESS.
  409. Comments:
  410. This function executes even when the FM is not fully online. This is
  411. necessary for a joining node to query the resource states while the
  412. owner node of the group is shutting down.
  413. --*/
  414. {
  415. PFM_RESOURCE pResource;
  416. PLIST_ENTRY pListEntry;
  417. ClRtlLogPrint(LOG_NOISE,
  418. "[FM] FmpEnumerateGroupResources: Entry for group <%1!ws!>....\n",
  419. OmObjectId(pGroup));
  420. FmpAcquireLocalGroupLock( pGroup );
  421. //
  422. // If the group has been marked for delete, then fail this call
  423. //
  424. if ( !IS_VALID_FM_GROUP( pGroup ) )
  425. {
  426. ClRtlLogPrint(LOG_UNUSUAL,
  427. "[FM] FmpEnumerateGroupResources: Group <%1!ws!> marked for deletion....\n",
  428. OmObjectId(pGroup));
  429. goto FnExit;
  430. }
  431. //
  432. // Run through contains list, then find all resources under that tree.
  433. //
  434. for ( pListEntry = pGroup->Contains.Flink;
  435. pListEntry != &(pGroup->Contains);
  436. pListEntry = pListEntry->Flink )
  437. {
  438. pResource = CONTAINING_RECORD( pListEntry,
  439. FM_RESOURCE,
  440. ContainsLinkage );
  441. if ( !pfnEnumerationRoutine( pContext1,
  442. pContext2,
  443. pResource,
  444. OmObjectId( pResource ) ) )
  445. {
  446. ClRtlLogPrint(LOG_CRITICAL,
  447. "[FM] FmpEnumerateGroupResources: Enumeration routine for group <%1!ws!> fails....\n",
  448. OmObjectId(pGroup));
  449. break;
  450. }
  451. }
  452. FnExit:
  453. FmpReleaseLocalGroupLock( pGroup );
  454. ClRtlLogPrint(LOG_NOISE,
  455. "[FM] FmpEnumerateGroupResources: Exit for group <%1!ws!>....\n",
  456. OmObjectId(pGroup));
  457. return( ERROR_SUCCESS );
  458. } // FmpEnumerateGroupResources
  459. ////////////////////////////////////////////////////////
  460. //
  461. // Resource management functions.
  462. //
  463. ////////////////////////////////////////////////////////
  464. PFM_RESOURCE
  465. WINAPI
  466. FmCreateResource(
  467. IN PFM_GROUP Group,
  468. IN LPWSTR ResourceId,
  469. IN LPCWSTR ResourceName,
  470. IN LPCWSTR ResourceType,
  471. IN DWORD dwFlags
  472. )
  473. /*++
  474. Routine Description:
  475. Create the specified resource.
  476. Note that the returned PFM_RESOURCE will have already been referenced.
  477. This prevents somebody from deleting the resource before the caller
  478. gets a chance to reference it.
  479. Arguments:
  480. Group - Supplies the group in which this resource belongs.
  481. ResourceId - Supplies the Id of the resource to create.
  482. ResourceName - Supplies the 'user-friendly' name of the resource.
  483. ResourceType - Supplies the 'user-friendly' name of the resource type.
  484. dwFlags - The flags for the resource.
  485. Returns:
  486. Pointer to the newly created resource if successful.
  487. NULL if unsuccessful. GetLastError() will return the specific error.
  488. --*/
  489. {
  490. DWORD Status;
  491. PFM_RESOURCE Resource;
  492. LPCWSTR GroupId;
  493. PGUM_CREATE_RESOURCE GumResource;
  494. DWORD GroupIdLen;
  495. DWORD ResourceIdLen;
  496. DWORD ResourceNameLen;
  497. DWORD ResourceTypeLen;
  498. DWORD BufSize;
  499. HDMKEY ResourceKey;
  500. HDMKEY ParamsKey;
  501. DWORD Disposition;
  502. FmpMustBeOnlineEx( NULL );
  503. FmpAcquireLocalGroupLock( Group );
  504. //
  505. // If we own the group then we can issue the Gum request to create
  506. // the resource. Otherwise, request the owner to initiate the request.
  507. //
  508. if ( Group->OwnerNode == NmLocalNode ) {
  509. //
  510. // Allocate a message buffer.
  511. //
  512. GroupId = OmObjectId(Group);
  513. GroupIdLen = (lstrlenW(GroupId)+1) * sizeof(WCHAR);
  514. ResourceIdLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR);
  515. ResourceNameLen = (lstrlenW(ResourceName)+1) * sizeof(WCHAR);
  516. ResourceTypeLen = (lstrlenW(ResourceType)+1) * sizeof(WCHAR);
  517. BufSize = sizeof(GUM_CREATE_RESOURCE) - sizeof(WCHAR) +
  518. GroupIdLen + ResourceIdLen + ResourceNameLen + ResourceTypeLen + 2 * sizeof( DWORD );
  519. GumResource = LocalAlloc(LMEM_FIXED, BufSize);
  520. if (GumResource == NULL) {
  521. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmCreateResource: Unable to allocate memory for resource <%1!ws!>....\n",
  522. ResourceName);
  523. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  524. return(NULL);
  525. }
  526. //
  527. // Fill in message buffer.
  528. //
  529. GumResource->Resource = NULL;
  530. GumResource->GroupIdLen = GroupIdLen;
  531. GumResource->ResourceIdLen = ResourceIdLen;
  532. CopyMemory(GumResource->GroupId, GroupId, GroupIdLen);
  533. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen,
  534. ResourceId,
  535. ResourceIdLen);
  536. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen + ResourceIdLen,
  537. ResourceName,
  538. ResourceNameLen);
  539. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen + ResourceIdLen + ResourceNameLen,
  540. &ResourceTypeLen,
  541. sizeof( DWORD ) );
  542. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen + ResourceIdLen + ResourceNameLen + sizeof( DWORD ),
  543. ResourceType,
  544. ResourceTypeLen );
  545. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen + ResourceIdLen + ResourceNameLen + sizeof( DWORD ) + ResourceTypeLen,
  546. &dwFlags,
  547. sizeof( DWORD ) );
  548. //
  549. // Send message.
  550. //
  551. Status = GumSendUpdate(GumUpdateFailoverManager,
  552. FmUpdateCreateResource,
  553. BufSize,
  554. GumResource);
  555. //
  556. // If the GUM call was successful, ensure that the resource DLL initialization stuff is
  557. // also done so that APIs following the CreateClusterResource API can make assumptions
  558. // that the resource is fully created. Note that the GUM call above will post a work item
  559. // for the FM worker thread to initialize a resource but there is no guarantee when the
  560. // FM worker thread will act on the work item. The following call will make sure we
  561. // won't return from this API until the initialization is fully done thus not giving any
  562. // chance for APIs such as ChangeClusterResourceGroup that follow this API to screw things
  563. // up. For backward compatibility reasons (consider a create call originating from a
  564. // W2K node), we still keep the work item posting in GUM and it won't do any harm since
  565. // the FmpInitializeResource call is idempotent.
  566. //
  567. if ( ( Status == ERROR_SUCCESS ) &&
  568. ( GumResource->Resource != NULL ) )
  569. {
  570. FmpClusterWideInitializeResource ( GumResource->Resource );
  571. }
  572. FmpReleaseLocalGroupLock( Group );
  573. if (Status != ERROR_SUCCESS) {
  574. LocalFree(GumResource);
  575. SetLastError(Status);
  576. return(NULL);
  577. }
  578. //The create resource by default adds all nodes
  579. //as possible nodes for a resource without filtering
  580. //out the nodes that dont support the resource type
  581. if( GumResource->Resource != NULL ) {
  582. FmpCleanupPossibleNodeList(GumResource->Resource);
  583. }
  584. Resource = GumResource->Resource;
  585. if( ( Resource == NULL ) && FmpShutdown ) {
  586. SetLastError( ERROR_CLUSTER_NODE_SHUTTING_DOWN );
  587. }
  588. LocalFree(GumResource);
  589. } else {
  590. //
  591. // The Group lock is released by FmcCreateResource
  592. //
  593. Resource = FmcCreateResource( Group,
  594. ResourceId,
  595. ResourceName,
  596. ResourceType,
  597. dwFlags );
  598. }
  599. //giving a reference to the client, increment ref count
  600. if ( Resource ) {
  601. OmReferenceObject(Resource);
  602. }
  603. return(Resource);
  604. } // FmCreateResource
  605. DWORD
  606. WINAPI
  607. FmDeleteResource(
  608. IN PFM_RESOURCE Resource
  609. )
  610. /*++
  611. Routine Description:
  612. Delete the specified resource.
  613. Arguments:
  614. Resource - Supplies the resource to delete.
  615. Returns:
  616. ERROR_SUCCESS if the request was successful.
  617. A Win32 error code on failure.
  618. --*/
  619. {
  620. DWORD Status;
  621. LPCWSTR ResourceId;
  622. DWORD ResourceLen;
  623. FmpMustBeOnline( );
  624. FmpAcquireLocalResourceLock( Resource );
  625. //
  626. // Check if this is the quorum resource.
  627. //
  628. if ( Resource->QuorumResource ) {
  629. FmpReleaseLocalResourceLock( Resource );
  630. return(ERROR_QUORUM_RESOURCE);
  631. }
  632. //other core resources cannot be deleted either
  633. if (Resource->ExFlags & CLUS_FLAG_CORE)
  634. {
  635. FmpReleaseLocalResourceLock( Resource );
  636. return (ERROR_CORE_RESOURCE);
  637. }
  638. //
  639. // If we own the resource then we can issue the Gum request to delete
  640. // the resource. Otherwise, request the owner to initiate the request.
  641. //
  642. if ( Resource->Group->OwnerNode == NmLocalNode ) {
  643. //
  644. // Check the state of the resource, before attempting to delete it.
  645. // It must be offline or failed in order to perform the delete.
  646. //
  647. if ((Resource->State != ClusterResourceOffline) &&
  648. (Resource->State != ClusterResourceFailed)) {
  649. FmpReleaseLocalResourceLock( Resource );
  650. return(ERROR_RESOURCE_ONLINE);
  651. }
  652. //
  653. // Check whether this resource provides for any other resources.
  654. // If so, it cannot be deleted.
  655. //
  656. if (!IsListEmpty(&Resource->ProvidesFor)) {
  657. FmpReleaseLocalResourceLock( Resource );
  658. return(ERROR_DEPENDENT_RESOURCE_EXISTS);
  659. }
  660. if (Resource->Group->MovingList)
  661. {
  662. FmpReleaseLocalResourceLock( Resource );
  663. return(ERROR_INVALID_STATE);
  664. }
  665. Status = FmpBroadcastDeleteControl(Resource);
  666. if ( Status != ERROR_SUCCESS ) {
  667. FmpReleaseLocalResourceLock( Resource );
  668. return(Status);
  669. }
  670. ResourceId = OmObjectId( Resource );
  671. ResourceLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR);
  672. //
  673. // Send message.
  674. //
  675. Status = GumSendUpdateEx(GumUpdateFailoverManager,
  676. FmUpdateDeleteResource,
  677. 1,
  678. ResourceLen,
  679. ResourceId);
  680. FmpReleaseLocalResourceLock( Resource );
  681. } else {
  682. Status = FmcDeleteResource( Resource );
  683. }
  684. return(Status);
  685. } // FmDeleteResource
  686. DWORD
  687. WINAPI
  688. FmSetResourceName(
  689. IN PFM_RESOURCE Resource,
  690. IN LPCWSTR FriendlyName
  691. )
  692. /*++
  693. Routine Description:
  694. Set the user-friendly name for the specified resource.
  695. Note that the resource must have already been created. It is also
  696. assumed that the caller of this routine (the cluster API) has already
  697. verified that the name is NOT a duplicate.
  698. Arguments:
  699. Resource - Supplies the resource to enter a new name.
  700. FriendlyName - Supplies the user-friendly name for the resource.
  701. Returns:
  702. ERROR_SUCCESS if successful.
  703. A Win32 error code on failure.
  704. --*/
  705. {
  706. DWORD dwStatus = ERROR_SUCCESS;
  707. dwStatus = FmpSetResourceName( Resource, FriendlyName );
  708. if( dwStatus != ERROR_SUCCESS )
  709. {
  710. ClRtlLogPrint(LOG_CRITICAL,
  711. "[FM] FmSetResourceName: FmpSetResourceName for resource %1!ws! fails, Status = %2!d!...\n",
  712. OmObjectId(Resource),
  713. dwStatus);
  714. }
  715. return( dwStatus );
  716. } // FmSetResourceName
  717. DWORD
  718. WINAPI
  719. FmOnlineResource(
  720. IN PFM_RESOURCE Resource
  721. )
  722. /*++
  723. Routine Description:
  724. This routine brings a resource online. It also updates the registry to
  725. indicate the new persistent, desired state of the resource.
  726. Arguments:
  727. Resource - A pointer to the resource to bring online.
  728. Returns:
  729. ERROR_SUCCESS if the request is successful.
  730. ERROR_IO_PENDING if the request is pending.
  731. A Win32 error code if the request fails.
  732. --*/
  733. {
  734. DWORD status;
  735. FmpMustBeOnline( );
  736. FmpAcquireLocalResourceLock( Resource );
  737. //if the resource has been marked for delete, then dont let
  738. //it be brought online
  739. if (!IS_VALID_FM_RESOURCE(Resource))
  740. {
  741. FmpReleaseLocalResourceLock( Resource );
  742. return (ERROR_RESOURCE_NOT_AVAILABLE);
  743. }
  744. //
  745. // Check if we are the owner... if not, ship the request off someplace
  746. // else.
  747. //
  748. CL_ASSERT( Resource->Group != NULL );
  749. if ( Resource->Group->OwnerNode != NmLocalNode ) {
  750. FmpReleaseLocalResourceLock( Resource );
  751. status = FmcOnlineResourceRequest( Resource );
  752. return(status);
  753. }
  754. //
  755. // Check if the resource has been initialized. If not, attempt
  756. // to initialize the resource now.
  757. //
  758. if ( Resource->Monitor == NULL ) {
  759. status = FmpInitializeResource( Resource, TRUE );
  760. if ( status != ERROR_SUCCESS ) {
  761. FmpReleaseLocalResourceLock( Resource );
  762. return(status);
  763. }
  764. }
  765. //
  766. // Chittur Subbaraman (chitturs) - 08/04/2000
  767. //
  768. // If the group is moving, fail this operation.
  769. //
  770. if ( Resource->Group->MovingList != NULL )
  771. {
  772. FmpReleaseLocalResourceLock( Resource );
  773. return (ERROR_GROUP_NOT_AVAILABLE);
  774. }
  775. //
  776. // Try to bring the resource online.
  777. //
  778. status = FmpDoOnlineResource( Resource, TRUE );
  779. FmpReleaseLocalResourceLock( Resource );
  780. return(status);
  781. } // FmOnlineResource
  782. DWORD
  783. WINAPI
  784. FmOfflineResource(
  785. IN PFM_RESOURCE Resource
  786. )
  787. /*++
  788. Routine Description:
  789. This routine takes a resource offline. It also updates the registry
  790. to indicate the new persistent, desired state of the resource.
  791. Arguments:
  792. Resource - A pointer to the resource to take offline.
  793. Returns:
  794. ERROR_SUCCESS if the request is successful.
  795. ERROR_IO_PENDING if the request is pending.
  796. A Win32 error code if the request fails.
  797. --*/
  798. {
  799. DWORD status;
  800. FmpMustBeOnline( );
  801. FmpAcquireLocalResourceLock( Resource );
  802. //if the resource has been marked for delete, then fail this call
  803. if (!IS_VALID_FM_RESOURCE(Resource))
  804. {
  805. FmpReleaseLocalResourceLock( Resource );
  806. return (ERROR_RESOURCE_NOT_AVAILABLE);
  807. }
  808. //
  809. // Check if this is the quorum resource.
  810. //
  811. if ( Resource->QuorumResource ) {
  812. FmpReleaseLocalResourceLock( Resource );
  813. return(ERROR_QUORUM_RESOURCE);
  814. }
  815. //
  816. // Chittur Subbaraman (chitturs) - 4/8/99
  817. //
  818. // Don't attempt to do anything if the resource has failed. You could
  819. // get into some funny cases in which the resource switches between
  820. // offline pending and failed states for ever.
  821. //
  822. if ( Resource->State == ClusterResourceFailed ) {
  823. FmpReleaseLocalResourceLock( Resource );
  824. return(ERROR_INVALID_STATE);
  825. }
  826. //
  827. // Check if we are the owner... if not, ship the request off someplace
  828. // else.
  829. //
  830. CL_ASSERT( Resource->Group != NULL );
  831. if ( Resource->Group->OwnerNode != NmLocalNode ) {
  832. FmpReleaseLocalResourceLock( Resource );
  833. return(FmcOfflineResourceRequest(Resource));
  834. }
  835. //
  836. // Check if the resource has been initialized. If not, return
  837. // success because the resource is not online.
  838. //
  839. if ( Resource->Monitor == NULL ) {
  840. FmpReleaseLocalResourceLock( Resource );
  841. return(ERROR_SUCCESS);
  842. }
  843. //
  844. // Chittur Subbaraman (chitturs) - 08/04/2000
  845. //
  846. // If the group is moving, fail this operation.
  847. //
  848. if ( Resource->Group->MovingList != NULL )
  849. {
  850. FmpReleaseLocalResourceLock( Resource );
  851. return (ERROR_GROUP_NOT_AVAILABLE);
  852. }
  853. //
  854. // Take the resource offline.
  855. //
  856. FmpReleaseLocalResourceLock( Resource );
  857. return(FmpDoOfflineResource( Resource, TRUE));
  858. } // FmOfflineResource
  859. CLUSTER_RESOURCE_STATE
  860. WINAPI
  861. FmGetResourceState(
  862. IN PFM_RESOURCE Resource,
  863. OUT LPWSTR NodeName,
  864. IN OUT PDWORD NameLength OPTIONAL
  865. )
  866. /*++
  867. Routine Description:
  868. Get the current state for the specified resource. The resource state
  869. consists of state of the resource, along with the current node that is
  870. hosting the resource.
  871. Arguments:
  872. Resource - Supplies the resource object to get the state.
  873. NodeName - Supplies a pointer to a buffer into which the name of
  874. the node in the cluster the specified resource is currently hosted.
  875. This field can be NULL, if NameLength is zero.
  876. NameLength - Supplies a pointer to a DWORD containing the number of
  877. characters available to the NodeName buffer (including the terminating
  878. NULL character. On return, it is the number of characters written
  879. into the NodeName buffer not including the NULL character.
  880. Returns:
  881. Returns the current state of the resource:
  882. ClusterResourceOnline
  883. ClusterResourceOffline
  884. ClusterResourceFailed
  885. etc.
  886. If the function fails, then the return value is ClusterResourceStateUnknown.
  887. --*/
  888. {
  889. WCHAR computerName[MAX_COMPUTERNAME_LENGTH+1];
  890. DWORD nameLength;
  891. DWORD length;
  892. PNM_NODE OwnerNode;
  893. CLUSTER_RESOURCE_STATE state;
  894. BOOL acquired;
  895. CL_ASSERT( OmObjectSignature(Resource) == FMP_RESOURCE_SIGNATURE );
  896. if ( ARGUMENT_PRESENT( NameLength ) ) {
  897. nameLength = *NameLength;
  898. *NodeName = (WCHAR)0;
  899. *NameLength = 0;
  900. }
  901. FmpMustBeOnlineEx( ClusterResourceStateUnknown );
  902. //
  903. // Try to acquire the lock to perform this work, so that resources
  904. // can query their current status and where the resource should be run.
  905. //
  906. // This does leave a potential window though if we can't get the lock,
  907. // some other thread could be changing the data!
  908. //
  909. FmpTryAcquireLocalResourceLock( Resource, acquired );
  910. OwnerNode = Resource->Group->OwnerNode;
  911. if ( OwnerNode != NULL ) {
  912. //
  913. // The Group is 'owned' by some system
  914. //
  915. if ( ARGUMENT_PRESENT( NameLength ) ) {
  916. length = lstrlenW( OmObjectName(OwnerNode) ) + 1;
  917. if ( nameLength < length ) {
  918. length = nameLength;
  919. }
  920. lstrcpynW( NodeName,
  921. OmObjectName(OwnerNode),
  922. length );
  923. *NameLength = length;
  924. }
  925. }
  926. state = Resource->State;
  927. if ( acquired ) {
  928. FmpReleaseLocalResourceLock( Resource );
  929. }
  930. if ( state == ClusterGroupStateUnknown ) {
  931. SetLastError(ERROR_INVALID_STATE);
  932. }
  933. return(state);
  934. } // FmGetResourceState
  935. DWORD
  936. WINAPI
  937. FmAddResourceDependency(
  938. IN PFM_RESOURCE pResource,
  939. IN PFM_RESOURCE pDependentResource
  940. )
  941. /*++
  942. Routine Description:
  943. Add a dependency from one resource to another.
  944. Arguments:
  945. Resource - The resource to add the dependent resource.
  946. DependentResource - The dependent resource.
  947. Returns:
  948. ERROR_SUCCESS if successful.
  949. A Win32 error code on failure.
  950. --*/
  951. {
  952. LPCWSTR pszResourceId;
  953. DWORD dwResourceLen;
  954. LPCWSTR pszDependsOnId;
  955. DWORD dwDependsOnLen;
  956. DWORD dwStatus = ERROR_SUCCESS;
  957. //
  958. // Chittur Subbaraman (chitturs) - 5/16/99
  959. //
  960. // Modify this API to route requests to owner node. Handle the
  961. // mixed mode case as well.
  962. //
  963. FmpMustBeOnline( );
  964. ClRtlLogPrint(LOG_NOISE,
  965. "[FM] FmAddResourceDependency : Resource <%1!ws!>, DependentResource <%2!ws!>...\n",
  966. OmObjectId( pResource ),
  967. OmObjectId( pDependentResource ));
  968. FmpAcquireLocalResourceLock( pResource );
  969. //
  970. // Check if we are the owner... if not, ship the request off some place
  971. // else.
  972. //
  973. if ( pResource->Group->OwnerNode != NmLocalNode )
  974. {
  975. //
  976. // FmcAddResourceDependency releases the local resource lock
  977. //
  978. dwStatus = FmcAddResourceDependency( pResource, pDependentResource );
  979. goto FnExit;
  980. }
  981. dwStatus = FmpValAddResourceDependency( pResource, pDependentResource );
  982. if ( dwStatus != ERROR_SUCCESS )
  983. {
  984. goto FnUnlock;
  985. }
  986. pszResourceId = OmObjectId( pResource );
  987. dwResourceLen = ( lstrlenW( pszResourceId ) +1 ) * sizeof( WCHAR) ;
  988. pszDependsOnId = OmObjectId( pDependentResource );
  989. dwDependsOnLen = ( lstrlenW( pszDependsOnId ) + 1 ) * sizeof( WCHAR );
  990. dwStatus = GumSendUpdateEx( GumUpdateFailoverManager,
  991. FmUpdateAddDependency,
  992. 2,
  993. dwResourceLen,
  994. pszResourceId,
  995. dwDependsOnLen,
  996. pszDependsOnId );
  997. if ( dwStatus == ERROR_SUCCESS )
  998. {
  999. FmpBroadcastDependencyChange( pResource,
  1000. pszDependsOnId,
  1001. FALSE );
  1002. }
  1003. FnUnlock:
  1004. FmpReleaseLocalResourceLock( pResource );
  1005. FnExit:
  1006. ClRtlLogPrint(LOG_NOISE,
  1007. "[FM] FmAddResourceDependency Exit: Status = <%1!u!>...\n",
  1008. dwStatus);
  1009. return( dwStatus );
  1010. }
  1011. // FmAddResourceDependency
  1012. DWORD
  1013. WINAPI
  1014. FmRemoveResourceDependency(
  1015. IN PFM_RESOURCE pResource,
  1016. IN PFM_RESOURCE pDependentResource
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. Remove a dependency from a resource.
  1021. Arguments:
  1022. Resource - The resource to remove the dependent resource.
  1023. DependentResource - The dependent resource.
  1024. Returns:
  1025. ERROR_SUCCESS if successful.
  1026. A Win32 error code on failure.
  1027. --*/
  1028. {
  1029. LPCWSTR pszResourceId;
  1030. DWORD dwResourceLen;
  1031. LPCWSTR pszDependsOnId;
  1032. DWORD dwDependsOnLen;
  1033. DWORD dwStatus;
  1034. //
  1035. // Chittur Subbaraman (chitturs) - 5/16/99
  1036. //
  1037. // Modify this API to route requests to owner node. Handle the
  1038. // mixed mode case as well.
  1039. //
  1040. FmpMustBeOnline( );
  1041. ClRtlLogPrint(LOG_NOISE,
  1042. "[FM] FmRemoveResourceDependency : Resource <%1!ws!>, DependentResource <%2!ws!>...\n",
  1043. OmObjectId( pResource ),
  1044. OmObjectId( pDependentResource ));
  1045. FmpAcquireLocalResourceLock( pResource );
  1046. //
  1047. // Check if we are the owner... if not, ship the request off some place
  1048. // else.
  1049. //
  1050. if ( pResource->Group->OwnerNode != NmLocalNode )
  1051. {
  1052. //
  1053. // FmcRemoveResourceDependency releases the local resource lock
  1054. //
  1055. dwStatus = FmcRemoveResourceDependency( pResource, pDependentResource );
  1056. goto FnExit;
  1057. }
  1058. dwStatus = FmpValRemoveResourceDependency( pResource, pDependentResource );
  1059. if ( dwStatus != ERROR_SUCCESS )
  1060. {
  1061. ClRtlLogPrint(LOG_NOISE,
  1062. "[FM] FmRemoveResourceDependency: FmpValRemoveResourceDependency returns status = <%1!u!>...\n",
  1063. dwStatus);
  1064. goto FnUnlock;
  1065. }
  1066. pszResourceId = OmObjectId( pResource );
  1067. dwResourceLen = ( lstrlenW( pszResourceId ) + 1 ) * sizeof( WCHAR );
  1068. pszDependsOnId = OmObjectId( pDependentResource );
  1069. dwDependsOnLen = ( lstrlenW( pszDependsOnId ) + 1 ) * sizeof( WCHAR );
  1070. dwStatus = GumSendUpdateEx( GumUpdateFailoverManager,
  1071. FmUpdateRemoveDependency,
  1072. 2,
  1073. dwResourceLen,
  1074. pszResourceId,
  1075. dwDependsOnLen,
  1076. pszDependsOnId );
  1077. if ( dwStatus == ERROR_SUCCESS )
  1078. {
  1079. FmpBroadcastDependencyChange( pResource,
  1080. pszDependsOnId,
  1081. TRUE );
  1082. }
  1083. FnUnlock:
  1084. FmpReleaseLocalResourceLock( pResource );
  1085. FnExit:
  1086. ClRtlLogPrint(LOG_NOISE,
  1087. "[FM] FmRemoveResourceDependency Exit: Status = <%1!u!>...\n",
  1088. dwStatus);
  1089. return( dwStatus );
  1090. }
  1091. // FmRemoveResourceDependency
  1092. DWORD
  1093. WINAPI
  1094. FmEnumResourceDependent(
  1095. IN PFM_RESOURCE Resource,
  1096. IN DWORD Index,
  1097. OUT PFM_RESOURCE *DependentResource
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. Enumerate the dependencies of a resources.
  1102. Arguments:
  1103. Resource - The resource to enumerate.
  1104. Index - The index for this enumeration.
  1105. DependentResource - The dependent resource. The returned resource
  1106. pointer will be referenced by this routine and should
  1107. be dereferenced when the caller is done with it.
  1108. Returns:
  1109. ERROR_SUCCESS if successful.
  1110. A Win32 error code on failure.
  1111. --*/
  1112. {
  1113. PLIST_ENTRY ListEntry;
  1114. DWORD i = 0;
  1115. PFM_RESOURCE Current;
  1116. PDEPENDENCY Dependency;
  1117. DWORD Status = ERROR_NO_MORE_ITEMS;
  1118. FmpMustBeOnline( );
  1119. FmpAcquireResourceLock();
  1120. if (!IS_VALID_FM_RESOURCE(Resource))
  1121. {
  1122. Status = ERROR_RESOURCE_NOT_AVAILABLE;
  1123. goto FnExit;
  1124. }
  1125. ListEntry = Resource->DependsOn.Flink;
  1126. while (ListEntry != &Resource->DependsOn) {
  1127. Dependency = CONTAINING_RECORD(ListEntry,
  1128. DEPENDENCY,
  1129. DependentLinkage);
  1130. CL_ASSERT(Dependency->DependentResource == Resource);
  1131. CL_ASSERT(Dependency->ProviderResource != Resource);
  1132. if (i==Index) {
  1133. //
  1134. // Got the right index
  1135. //
  1136. OmReferenceObject(Dependency->ProviderResource);
  1137. *DependentResource = Dependency->ProviderResource;
  1138. Status = ERROR_SUCCESS;
  1139. break;
  1140. }
  1141. ListEntry = ListEntry->Flink;
  1142. ++i;
  1143. }
  1144. FnExit:
  1145. FmpReleaseResourceLock();
  1146. return(Status);
  1147. } // FmEnumResourceDependent
  1148. DWORD
  1149. WINAPI
  1150. FmEnumResourceProvider(
  1151. IN PFM_RESOURCE Resource,
  1152. IN DWORD Index,
  1153. OUT PFM_RESOURCE *DependentResource
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Enumerate the providers for a resources.
  1158. Arguments:
  1159. Resource - The resource to enumerate.
  1160. Index - The index for this enumeration.
  1161. DependentResource - The provider resource. The returned resource
  1162. pointer will be referenced by this routine and should
  1163. be dereferenced when the caller is done with it.
  1164. Returns:
  1165. ERROR_SUCCESS if successful.
  1166. A Win32 error code on failure.
  1167. --*/
  1168. {
  1169. PLIST_ENTRY ListEntry;
  1170. DWORD i = 0;
  1171. PFM_RESOURCE Current;
  1172. PDEPENDENCY Dependency;
  1173. DWORD Status = ERROR_NO_MORE_ITEMS;
  1174. FmpMustBeOnline( );
  1175. FmpAcquireResourceLock();
  1176. if (!IS_VALID_FM_RESOURCE(Resource))
  1177. {
  1178. Status = ERROR_RESOURCE_NOT_AVAILABLE;
  1179. goto FnExit;
  1180. }
  1181. ListEntry = Resource->ProvidesFor.Flink;
  1182. while (ListEntry != &Resource->ProvidesFor) {
  1183. Dependency = CONTAINING_RECORD(ListEntry,
  1184. DEPENDENCY,
  1185. ProviderLinkage);
  1186. CL_ASSERT(Dependency->DependentResource != Resource);
  1187. CL_ASSERT(Dependency->ProviderResource == Resource);
  1188. if (i==Index) {
  1189. //
  1190. // Got the right index
  1191. //
  1192. OmReferenceObject(Dependency->DependentResource);
  1193. *DependentResource = Dependency->DependentResource;
  1194. Status = ERROR_SUCCESS;
  1195. break;
  1196. }
  1197. ListEntry = ListEntry->Flink;
  1198. ++i;
  1199. }
  1200. FnExit:
  1201. FmpReleaseResourceLock();
  1202. return(Status);
  1203. } // FmEnumResourceProvider
  1204. DWORD
  1205. WINAPI
  1206. FmEnumResourceNode(
  1207. IN PFM_RESOURCE Resource,
  1208. IN DWORD Index,
  1209. OUT PNM_NODE *PossibleNode
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Enumerate the possible nodes for a resources.
  1214. Arguments:
  1215. Resource - The resource to enumerate.
  1216. Index - The index for this enumeration.
  1217. PossibleNode - The possible node. The returned node
  1218. pointer will be referenced by this routine and should
  1219. be dereferenced when the caller is done with it.
  1220. Returns:
  1221. ERROR_SUCCESS if successful.
  1222. A Win32 error code on failure.
  1223. --*/
  1224. {
  1225. PLIST_ENTRY ListEntry;
  1226. DWORD i = 0;
  1227. PFM_RESOURCE Current;
  1228. PPOSSIBLE_ENTRY PossibleEntry;
  1229. DWORD Status = ERROR_NO_MORE_ITEMS;
  1230. FmpMustBeOnline( );
  1231. FmpAcquireResourceLock();
  1232. if (!IS_VALID_FM_RESOURCE(Resource))
  1233. {
  1234. Status = ERROR_RESOURCE_NOT_AVAILABLE;
  1235. goto FnExit;
  1236. }
  1237. ListEntry = Resource->PossibleOwners.Flink;
  1238. while (ListEntry != &Resource->PossibleOwners) {
  1239. PossibleEntry = CONTAINING_RECORD(ListEntry,
  1240. POSSIBLE_ENTRY,
  1241. PossibleLinkage);
  1242. if (i==Index) {
  1243. //
  1244. // Got the right index
  1245. //
  1246. OmReferenceObject(PossibleEntry->PossibleNode);
  1247. *PossibleNode = PossibleEntry->PossibleNode;
  1248. Status = ERROR_SUCCESS;
  1249. break;
  1250. }
  1251. ListEntry = ListEntry->Flink;
  1252. ++i;
  1253. }
  1254. FnExit:
  1255. FmpReleaseResourceLock();
  1256. return(Status);
  1257. } // FmEnumResourceNode
  1258. DWORD
  1259. WINAPI
  1260. FmFailResource(
  1261. IN PFM_RESOURCE Resource
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. Cause the specified resource to fail.
  1266. Arguments:
  1267. Resource - The resource to make fail.
  1268. Returns:
  1269. ERROR_SUCCESS - if successful.
  1270. A Win32 error code on failure.
  1271. --*/
  1272. {
  1273. FmpMustBeOnline( );
  1274. if ( Resource->Group->OwnerNode != NmLocalNode ) {
  1275. return(FmcFailResource( Resource ));
  1276. }
  1277. return(FmpRmFailResource( Resource ));
  1278. } // FmFailResource
  1279. DWORD
  1280. WINAPI
  1281. FmChangeResourceNode(
  1282. IN PFM_RESOURCE Resource,
  1283. IN PNM_NODE Node,
  1284. IN BOOL Add
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. Changes the list of nodes where the specified resource
  1289. can be brought online.
  1290. Arguments:
  1291. Resource - Supplies the resource whose list of possible nodes is
  1292. to be modified.
  1293. Node - Supplies the node to be added to the resource's list.
  1294. Add - Supplies whether the specified node is to be added (TRUE) or
  1295. deleted (FALSE) from the resource's node list.
  1296. Return Value:
  1297. ERROR_SUCCESS if successful
  1298. Win32 error code otherwise
  1299. --*/
  1300. {
  1301. DWORD Status;
  1302. FmpAcquireLocalResourceLock( Resource );
  1303. if ( Resource->Group->OwnerNode != NmLocalNode ) {
  1304. // Note: FmcChangeResourceNode must release the resource lock.
  1305. Status = FmcChangeResourceNode( Resource, Node, Add );
  1306. }
  1307. else
  1308. {
  1309. Status = FmpChangeResourceNode(Resource, OmObjectId(Node), Add);
  1310. FmpReleaseLocalResourceLock( Resource );
  1311. }
  1312. return(Status);
  1313. } // FmChangeResourceNode
  1314. DWORD
  1315. WINAPI
  1316. FmSetQuorumResource(
  1317. IN PFM_RESOURCE Resource,
  1318. IN LPCWSTR pszClusFileRootPath,
  1319. IN DWORD dwMaxQuorumLogSize
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. Set the specified resource as the quorum resource. This requires making
  1324. sure that the specified resource can perform an arbitrate. We do this
  1325. by asking the owner node to perform an arbitrate of the resource.
  1326. Arguments:
  1327. Resource - Supplies the resource that must be arbitrated.
  1328. pszLogPathName - The root path where the log files will be moved. "Microsoft
  1329. Cluster Manager Directory" is created under the root path provided. If NULL,
  1330. a partition on the shared quorum device is picked up randomly. And
  1331. the log files are placed in the directory specified by the
  1332. CLUSTER_QUORUM_DEFAULT_MAX_LOG_SIZE constant at the root of that partition.
  1333. dwMaxQuorumLogSize - The maximum size of the quorum logs. If 0, the default
  1334. used. If smaller that 32K, 32K is used.
  1335. Returns:
  1336. ERROR_SUCCESS if successful.
  1337. A Win32 error code on failure.
  1338. --*/
  1339. {
  1340. DWORD status;
  1341. DWORD resourceIdLen;
  1342. PFM_RESOURCE quorumResource = NULL;
  1343. PFM_RESOURCE pOldQuoResource = NULL;
  1344. PVOID gumResource = NULL;
  1345. DWORD dwBytesReturned;
  1346. DWORD dwRequired;
  1347. DWORD dwBufSize;
  1348. WCHAR szQuoLogPath[MAX_PATH] = L"\0";
  1349. WCHAR szLogRootPath[MAX_PATH];
  1350. CLUS_RESOURCE_CLASS_INFO resClassInfo;
  1351. PUCHAR pBuf = NULL;
  1352. LPWSTR pszOldQuoLogPath = NULL;
  1353. LPWSTR pszNext = NULL;
  1354. LPWSTR pszExpClusFileRootPath = NULL;
  1355. DWORD dwCharacteristics;
  1356. BOOL fIsPathUNC;
  1357. DWORD dwCurrentNodeCnt;
  1358. DWORD dwClusterHighestVersion;
  1359. FmpMustBeOnline( );
  1360. ClRtlLogPrint(LOG_NOISE,
  1361. "[FM] FmSetQuorumResource: Entry, pszClusFileRootPath=%1!ws!\r\n",
  1362. ((pszClusFileRootPath)? pszClusFileRootPath:szQuoLogPath));
  1363. dwCurrentNodeCnt = NmGetCurrentNumberOfNodes();
  1364. // find the old quorum resource
  1365. status = FmFindQuorumResource(&pOldQuoResource);
  1366. if (status != ERROR_SUCCESS)
  1367. {
  1368. goto FnExit;
  1369. }
  1370. //
  1371. // Synchronize access to Quorum Resource changes.
  1372. //
  1373. //
  1374. // Synchronize both the old and the new resource.
  1375. // Lock the lowest by lowest Group Id first - to prevent deadlocks!
  1376. // Note - the order of release is unimportant.
  1377. //
  1378. // if the old and new resource belong to the same group
  1379. // the comparison will be be equal!
  1380. //
  1381. ACQUIRE_EXCLUSIVE_LOCK(gQuoChangeLock);
  1382. if ( lstrcmpiW( OmObjectId( pOldQuoResource->Group ),
  1383. OmObjectId( Resource->Group ) ) <= 0 ) {
  1384. FmpAcquireLocalGroupLock( pOldQuoResource->Group );
  1385. FmpAcquireLocalGroupLock( Resource->Group );
  1386. } else {
  1387. FmpAcquireLocalGroupLock( Resource->Group );
  1388. FmpAcquireLocalGroupLock( pOldQuoResource->Group );
  1389. }
  1390. status = FmpGetResourceCharacteristics(Resource, &dwCharacteristics);
  1391. if (status != ERROR_SUCCESS)
  1392. {
  1393. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: getresourcecharacteristics failed, status=%1!u!\n",
  1394. status);
  1395. goto FnExit;
  1396. }
  1397. //
  1398. // If the resource doesn't advertise itself as quorum-capable, no point in proceeding.
  1399. //
  1400. if ( !( dwCharacteristics & CLUS_CHAR_QUORUM ) )
  1401. {
  1402. status = ERROR_NOT_QUORUM_CAPABLE;
  1403. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: Resource %1!ws! can't be quorum, status %2!u!\n",
  1404. OmObjectName(Resource),
  1405. status);
  1406. goto FnExit;
  1407. }
  1408. if (dwCurrentNodeCnt > 1)
  1409. {
  1410. //if the cluster is a multinode cluster, dont allow a switch to
  1411. //local quorum type resources unless the debug characteristic is set
  1412. if ((dwCharacteristics & CLUS_CHAR_LOCAL_QUORUM) &&
  1413. !(dwCharacteristics & CLUS_CHAR_LOCAL_QUORUM_DEBUG))
  1414. {
  1415. status = ERROR_INVALID_PARAMETER;
  1416. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: No debug property for local quorum resource %1!ws!, status %2!u!\n",
  1417. OmObjectName(Resource),
  1418. status);
  1419. goto FnExit;
  1420. }
  1421. }
  1422. if (Resource->State != ClusterResourceOnline)
  1423. {
  1424. status = ERROR_RESOURCE_NOT_ONLINE;
  1425. goto FnExit;
  1426. }
  1427. if (!IsListEmpty(&Resource->DependsOn))
  1428. {
  1429. status = ERROR_DEPENDENCY_NOT_ALLOWED;
  1430. goto FnExit;
  1431. }
  1432. //
  1433. // Get the old log path.
  1434. //
  1435. dwBytesReturned = 0;
  1436. dwRequired = 0;
  1437. status = DmQuerySz( DmQuorumKey,
  1438. cszPath,
  1439. (LPWSTR*)&pszOldQuoLogPath,
  1440. &dwRequired,
  1441. &dwBytesReturned);
  1442. if (status != ERROR_SUCCESS) {
  1443. ClRtlLogPrint(LOG_UNUSUAL,
  1444. "[FM] FmSetQuorumResource Failed to get the old quo log path, error %1!u!.\n",
  1445. status);
  1446. goto FnExit;
  1447. }
  1448. //SS: if you want to have a sub dir for logging files
  1449. //check the resource class
  1450. status = FmResourceControl(Resource, NULL, CLUSCTL_RESOURCE_GET_CLASS_INFO, NULL, 0,
  1451. (PUCHAR)&resClassInfo, sizeof(resClassInfo), &dwBytesReturned, &dwRequired);
  1452. if ( status != ERROR_SUCCESS )
  1453. {
  1454. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: Unable to get class info for resource %1!ws!, status %2!u!\n",
  1455. OmObjectName(Resource),
  1456. status);
  1457. goto FnExit;
  1458. }
  1459. if ( ( resClassInfo.SubClass & CLUS_RESSUBCLASS_SHARED ) == 0 )
  1460. {
  1461. status = ERROR_NOT_QUORUM_CLASS;
  1462. goto FnExit;
  1463. }
  1464. //allocate info for the disk info
  1465. //get disk info
  1466. dwBufSize = 2048;
  1467. Retry:
  1468. pBuf = LocalAlloc(LMEM_FIXED, dwBufSize);
  1469. if (pBuf == NULL ) {
  1470. status = ERROR_NOT_ENOUGH_MEMORY;
  1471. goto FnExit;
  1472. }
  1473. status = FmResourceControl(Resource, NULL, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  1474. NULL, 0, pBuf, dwBufSize, &dwBytesReturned, &dwRequired);
  1475. if ((status == ERROR_MORE_DATA) && (dwBufSize < dwRequired))
  1476. {
  1477. dwBufSize = dwRequired;
  1478. LocalFree(pBuf);
  1479. goto Retry;
  1480. }
  1481. if (status != ERROR_SUCCESS)
  1482. {
  1483. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: Unable to get disk info for resource %1!ws!, status %2!u!\n",
  1484. OmObjectName(Resource),
  1485. status);
  1486. goto FnExit;
  1487. }
  1488. if (pszClusFileRootPath)
  1489. pszExpClusFileRootPath = ClRtlExpandEnvironmentStrings(pszClusFileRootPath);
  1490. //use the expanded path name for validation
  1491. if (pszExpClusFileRootPath)
  1492. {
  1493. WCHAR cColon=L':';
  1494. //
  1495. // The quorum management code assumes that the quorum path + file names such as quolog.log can all fit in MAX_PATH
  1496. // sized buffers. It is too much code churn to fix all places in which this assumption is made. Let us reject paths that
  1497. // are too long right here.
  1498. //
  1499. if ( lstrlen ( pszExpClusFileRootPath ) + 20 > MAX_PATH )
  1500. {
  1501. status = ERROR_BAD_PATHNAME;
  1502. ClRtlLogPrint(LOG_UNUSUAL, "[FM] FmSetQuorumResource: Path specified is too long, status %1!u!\n",
  1503. status);
  1504. goto FnExit;
  1505. }
  1506. pszNext = wcschr(pszExpClusFileRootPath, cColon);
  1507. //pick up just the drive letter
  1508. if (pszNext)
  1509. {
  1510. lstrcpynW(szLogRootPath, pszExpClusFileRootPath,
  1511. (UINT)(pszNext-pszExpClusFileRootPath+2));
  1512. }
  1513. else
  1514. {
  1515. //if there is no drive letter, pick up a drive letter at random
  1516. szLogRootPath[0] = L'\0';
  1517. }
  1518. }
  1519. else
  1520. {
  1521. szLogRootPath[0] = L'\0';
  1522. }
  1523. ClRtlLogPrint(LOG_NOISE,
  1524. "[FM] FmSetQuorumResource: szLogRootPath=%1!ws!\r\n",
  1525. szLogRootPath);
  1526. //save the drive letter for the new quorum path
  1527. status = FmpGetDiskInfoParseProperties(pBuf, dwBytesReturned, szLogRootPath);
  1528. //if the status was invalid parameter for a local quorum, ignore the local
  1529. //quorum path setting..what is specified through this api overrides
  1530. if ((status == ERROR_INVALID_PARAMETER) &&
  1531. (dwCharacteristics & CLUS_CHAR_LOCAL_QUORUM))
  1532. {
  1533. status = ERROR_SUCCESS;
  1534. ClRtlLogPrint(LOG_NOISE,
  1535. "[FM] FmSetQuorumResource: LocalQuorum force success, szLogRootPath=%1!ws!\r\n",
  1536. szLogRootPath);
  1537. }
  1538. ClRtlLogPrint(LOG_NOISE,
  1539. "[FM] FmSetQuorumResource: szLogRootPath=%1!ws!\r\n",
  1540. szLogRootPath);
  1541. if (status != ERROR_SUCCESS)
  1542. {
  1543. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: Unable to parse disk info for resource %1!ws!, status %2!u!\n",
  1544. OmObjectName(Resource),
  1545. status);
  1546. goto FnExit;
  1547. }
  1548. if (szLogRootPath[0] == L'\0')
  1549. {
  1550. //no valid drive letter is found
  1551. status = ERROR_INVALID_PARAMETER;
  1552. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: No valid drive letter for resource %1!ws!, status %2!u!\n",
  1553. OmObjectName(Resource),
  1554. status);
  1555. goto FnExit;
  1556. }
  1557. //got the drive letter
  1558. lstrcpyW(szQuoLogPath, szLogRootPath);
  1559. if (pszNext)
  1560. {
  1561. // if the driver letter was supplied, append the rest of the path
  1562. lstrcatW(szQuoLogPath, pszNext+1);
  1563. }
  1564. else
  1565. {
  1566. //if no drive letter was supplied
  1567. // if a path was supplied, append the path
  1568. if ( pszExpClusFileRootPath )
  1569. {
  1570. //
  1571. // If the user specifies an SMB path, we override whatever the resource told us.
  1572. //
  1573. if ( ( lstrlenW( pszExpClusFileRootPath ) >=2 ) &&
  1574. ( pszExpClusFileRootPath[0] == L'\\' ) &&
  1575. ( pszExpClusFileRootPath[1] == L'\\' ) &&
  1576. ( dwCharacteristics & CLUS_CHAR_QUORUM ) )
  1577. {
  1578. lstrcpyW( szQuoLogPath, pszExpClusFileRootPath );
  1579. }
  1580. else if ( pszExpClusFileRootPath[0] == L'\\' )
  1581. {
  1582. lstrcatW( szQuoLogPath, pszExpClusFileRootPath );
  1583. }
  1584. else
  1585. {
  1586. lstrcatW( szQuoLogPath, L"\\" );
  1587. lstrcatW( szQuoLogPath, pszExpClusFileRootPath );
  1588. }
  1589. }
  1590. else
  1591. {
  1592. // else append the default path
  1593. lstrcatW( szQuoLogPath, L"\\" );
  1594. lstrcatW(szQuoLogPath, CLUS_NAME_DEFAULT_FILESPATH);
  1595. }
  1596. }
  1597. //if the path name is provided, check if it is terminated with '\'
  1598. //if not, terminate it
  1599. if (szQuoLogPath[lstrlenW(szQuoLogPath) - 1] != L'\\')
  1600. {
  1601. lstrcatW( szQuoLogPath, L"\\" );
  1602. }
  1603. //
  1604. // If the path is of UNC form, then prepend a \\?\UNC\ to it.
  1605. //
  1606. status = FmpCanonicalizePath( szQuoLogPath, &fIsPathUNC );
  1607. if ( status != ERROR_SUCCESS ) goto FnExit;
  1608. ClRtlLogPrint(LOG_NOISE,
  1609. "[FM] FmSetQuorumResource: szQuoLogPath=%1!ws!\r\n",
  1610. szQuoLogPath);
  1611. //
  1612. // Allocate a message buffer.
  1613. //
  1614. resourceIdLen = (lstrlenW(OmObjectId(Resource))+1) * sizeof(WCHAR);
  1615. gumResource = LocalAlloc(LMEM_FIXED, resourceIdLen);
  1616. if (gumResource == NULL)
  1617. {
  1618. status = ERROR_NOT_ENOUGH_MEMORY;
  1619. goto FnExit;
  1620. }
  1621. //
  1622. // Fill in message buffer.
  1623. //
  1624. CopyMemory(gumResource, OmObjectId(Resource), resourceIdLen);
  1625. //
  1626. // Make sure that we can arbitrate the new quorum resource.
  1627. //
  1628. if ( Resource->Group->OwnerNode != NmLocalNode ) {
  1629. status = FmcArbitrateResource( Resource );
  1630. } else {
  1631. status = FmpRmArbitrateResource( Resource );
  1632. }
  1633. if ( status != ERROR_SUCCESS ) {
  1634. ClRtlLogPrint(LOG_CRITICAL, "[FM] FmSetQuorumResource: Arbitrate for resource %1!ws! failed, status %2!u!\n",
  1635. OmObjectName(Resource),
  1636. status);
  1637. goto FnExit;
  1638. }
  1639. //check the log size, if it not zero but less than the min
  1640. //limit set it to 32K.
  1641. if ((dwMaxQuorumLogSize) && (dwMaxQuorumLogSize < CLUSTER_QUORUM_MIN_LOG_SIZE))
  1642. {
  1643. dwMaxQuorumLogSize = CLUSTER_QUORUM_MIN_LOG_SIZE;
  1644. }
  1645. //Prepare to move to a new quorum resource
  1646. //create a new quorum log file and
  1647. //move the registry files there.
  1648. if ( Resource->Group->OwnerNode != NmLocalNode ) {
  1649. status = FmcPrepareQuorumResChange( Resource, szQuoLogPath, dwMaxQuorumLogSize );
  1650. } else {
  1651. status = FmpPrepareQuorumResChange( Resource, szQuoLogPath, dwMaxQuorumLogSize );
  1652. }
  1653. if ( status != ERROR_SUCCESS ) {
  1654. if ((dwCharacteristics & CLUS_CHAR_LOCAL_QUORUM) && (fIsPathUNC == FALSE))
  1655. {
  1656. ClRtlLogPrint(LOG_NOISE,
  1657. "[FM] FmSetQuorumResource: Local quorum, map FmpPrepareQuorumResChange to success\n");
  1658. status = ERROR_SUCCESS;
  1659. }
  1660. else
  1661. goto FnExit;
  1662. }
  1663. //
  1664. // If we are dealing with the mixed mode cluster then dont set the arbitration
  1665. // timeouts
  1666. //
  1667. NmGetClusterOperationalVersion( &dwClusterHighestVersion,
  1668. NULL,
  1669. NULL );
  1670. if ((CLUSTER_GET_MAJOR_VERSION(dwClusterHighestVersion) < NT51_MAJOR_VERSION ))
  1671. {
  1672. //
  1673. // This is a mixed mode cluster, send the old gum message.
  1674. //
  1675. status = GumSendUpdateEx(GumUpdateFailoverManager,
  1676. FmUpdateChangeQuorumResource,
  1677. 3,
  1678. resourceIdLen,
  1679. gumResource,
  1680. (lstrlenW(szQuoLogPath) + 1 ) * sizeof(WCHAR),
  1681. szQuoLogPath,
  1682. sizeof(DWORD),
  1683. &dwMaxQuorumLogSize
  1684. );
  1685. }
  1686. else
  1687. {
  1688. DWORD dwArbTimeout;
  1689. CLUSPROP_DWORD ClusPropArbTimeout;
  1690. // Read and set the new arbitration timeout
  1691. status = FmResourceTypeControl(OmObjectId(Resource->Type), NULL, CLUSCTL_RESOURCE_TYPE_GET_ARB_TIMEOUT,
  1692. NULL, 0, (CHAR *)&ClusPropArbTimeout, sizeof(ClusPropArbTimeout), &dwBytesReturned, &dwRequired);
  1693. if ( status != ERROR_SUCCESS )
  1694. {
  1695. ClRtlLogPrint(LOG_NOISE,
  1696. "[FM] FmSetQuorumResource: couldnt get RESTYPE arbitration timeout, defaulting to 60 seconds. Status = %1!u!\n",
  1697. status);
  1698. dwArbTimeout = CLUSTER_QUORUM_DEFAULT_ARBITRATION_TIMEOUT;
  1699. //map to success, since we dont want to fail the request in this case
  1700. status = ERROR_SUCCESS;
  1701. } else {
  1702. dwArbTimeout = ClusPropArbTimeout.dw;
  1703. }
  1704. ClRtlLogPrint(LOG_NOISE,
  1705. "[FM] FmSetQuorumResource: setting arbitration timeout to %1!u! seconds.\n", dwArbTimeout );
  1706. //
  1707. // Send the message.
  1708. //
  1709. status = GumSendUpdateEx(GumUpdateFailoverManager,
  1710. FmUpdateChangeQuorumResource2,
  1711. 5,
  1712. resourceIdLen,
  1713. gumResource,
  1714. (lstrlenW(szQuoLogPath) + 1 ) * sizeof(WCHAR),
  1715. szQuoLogPath,
  1716. sizeof(DWORD),
  1717. &dwMaxQuorumLogSize,
  1718. sizeof(DWORD),
  1719. &dwArbTimeout,
  1720. sizeof(DWORD),
  1721. &dwCharacteristics
  1722. );
  1723. }
  1724. //if the old path is not the same as the new path
  1725. //create a tombstone for the quorum log files on the old path
  1726. //this is to prevent nodes that are not present in this update
  1727. //from doing a form.
  1728. if ( (status == ERROR_SUCCESS) &&
  1729. (lstrcmpiW(szQuoLogPath, pszOldQuoLogPath)) ) {
  1730. //
  1731. // delete the old quorum log files on the old resource and create a tombstone file
  1732. // in there.
  1733. //
  1734. if ( pOldQuoResource->Group->OwnerNode != NmLocalNode ) {
  1735. status = FmcCompleteQuorumResChange( pOldQuoResource, pszOldQuoLogPath );
  1736. } else {
  1737. status = FmpCompleteQuorumResChange( OmObjectId(pOldQuoResource), pszOldQuoLogPath );
  1738. }
  1739. }
  1740. FnExit:
  1741. //not the order of release is not important
  1742. FmpReleaseLocalGroupLock(pOldQuoResource->Group);
  1743. FmpReleaseLocalGroupLock(Resource->Group);
  1744. RELEASE_LOCK(gQuoChangeLock);
  1745. if (pBuf) LocalFree(pBuf);
  1746. if (gumResource) LocalFree(gumResource);
  1747. if (pOldQuoResource) OmDereferenceObject(pOldQuoResource);
  1748. if (pszOldQuoLogPath) LocalFree(pszOldQuoLogPath);
  1749. if (pszExpClusFileRootPath) LocalFree(pszExpClusFileRootPath);
  1750. ClRtlLogPrint(LOG_NOISE,
  1751. "[FM] FmSetQuorumResource: Exit, status=%1!u!\r\n",
  1752. status);
  1753. return(status);
  1754. } // FmSetQuorumResource
  1755. DWORD
  1756. FmCreateResourceType(
  1757. IN LPCWSTR lpszTypeName,
  1758. IN LPCWSTR lpszDisplayName,
  1759. IN LPCWSTR lpszDllName,
  1760. IN DWORD dwLooksAlive,
  1761. IN DWORD dwIsAlive
  1762. )
  1763. /*++
  1764. Routine Description:
  1765. Issues a GUM update to instantiate a resource type on every
  1766. node. The registry update as well as the FM in-memory state
  1767. update is done as a transaction within the GUM handler (NT5
  1768. clusters only).
  1769. Arguments:
  1770. lpszTypeName - Supplies the name of the new cluster resource type.
  1771. lpszDisplayName - Supplies the display name for the new resource
  1772. type. While lpszResourceTypeName should uniquely identify the
  1773. resource type on all clusters, the lpszDisplayName should be
  1774. a localized friendly name for the resource, suitable for displaying
  1775. to administrators.
  1776. lpszDllName - Supplies the name of the new resource types DLL.
  1777. dwLooksAlive - Supplies the default LooksAlive poll interval
  1778. for the new resource type in milliseconds.
  1779. dwIsAlive - Supplies the default IsAlive poll interval for
  1780. the new resource type in milliseconds.
  1781. Return Value:
  1782. ERROR_SUCCESS if successful.
  1783. Win32 error otherwise.
  1784. --*/
  1785. {
  1786. DWORD dwStatus = ERROR_SUCCESS;
  1787. PFM_RESTYPE pResType = NULL;
  1788. DWORD dwTypeNameLen;
  1789. DWORD dwDisplayNameLen;
  1790. DWORD dwDllNameLen;
  1791. DWORD dwBufferLen;
  1792. LPVOID Buffer = NULL;
  1793. //
  1794. // Chittur Subbaraman (chitturs) - 2/8/2000
  1795. //
  1796. // Rewrite this API to use a GUM handler which performs a local
  1797. // transaction for NT5.1
  1798. //
  1799. ClRtlLogPrint(LOG_NOISE,
  1800. "[FM] FmCreateResourceType: Entry for %1!ws!...\r\n",
  1801. lpszTypeName);
  1802. //
  1803. // If the resource type already exists, do not issue a GUM and have it fail.
  1804. //
  1805. pResType = OmReferenceObjectById( ObjectTypeResType,
  1806. lpszTypeName );
  1807. if ( pResType )
  1808. {
  1809. dwStatus = ERROR_ALREADY_EXISTS;
  1810. OmDereferenceObject( pResType );
  1811. goto FnExit;
  1812. }
  1813. dwTypeNameLen = ( lstrlenW( lpszTypeName ) + 1 ) * sizeof( WCHAR );
  1814. dwDisplayNameLen = ( lstrlenW( lpszDisplayName ) + 1 ) * sizeof( WCHAR );
  1815. dwDllNameLen = ( lstrlenW( lpszDllName ) + 1 ) * sizeof( WCHAR );
  1816. dwBufferLen = dwTypeNameLen + dwDisplayNameLen + dwDllNameLen +
  1817. 2 * sizeof( DWORD );
  1818. Buffer = LocalAlloc( LMEM_FIXED, dwBufferLen );
  1819. if ( Buffer == NULL )
  1820. {
  1821. dwStatus = GetLastError();
  1822. ClRtlLogPrint(LOG_CRITICAL,
  1823. "[FM] FmCreateResourceType: FmUpdateCreateResourceType for %1!ws! returned %2!u! on mem alloc...\n",
  1824. lpszTypeName,
  1825. dwStatus);
  1826. goto FnExit;
  1827. }
  1828. CopyMemory( Buffer, lpszTypeName, dwTypeNameLen );
  1829. CopyMemory( ( PCHAR ) Buffer + dwTypeNameLen, lpszDisplayName, dwDisplayNameLen );
  1830. CopyMemory( ( PCHAR ) Buffer + dwTypeNameLen + dwDisplayNameLen, lpszDllName, dwDllNameLen );
  1831. CopyMemory( ( PCHAR ) Buffer +
  1832. dwTypeNameLen +
  1833. dwDisplayNameLen +
  1834. dwDllNameLen, &dwLooksAlive, sizeof( DWORD ) );
  1835. CopyMemory( ( PCHAR ) Buffer +
  1836. dwTypeNameLen +
  1837. dwDisplayNameLen +
  1838. dwDllNameLen + sizeof( DWORD ), &dwIsAlive, sizeof( DWORD ) );
  1839. dwStatus = GumSendUpdate( GumUpdateFailoverManager,
  1840. FmUpdateCreateResourceType,
  1841. dwBufferLen,
  1842. Buffer );
  1843. if ( dwStatus != ERROR_SUCCESS )
  1844. {
  1845. ClRtlLogPrint(LOG_CRITICAL,
  1846. "[FM] FmCreateResourceType: FmUpdateCreateResourceType for %1!ws! returned %2!u!...\r\n",
  1847. lpszTypeName,
  1848. dwStatus);
  1849. goto FnExit;
  1850. }
  1851. dwStatus = FmpSetPossibleNodeForResType( lpszTypeName , FALSE );
  1852. if ( dwStatus != ERROR_SUCCESS )
  1853. {
  1854. ClRtlLogPrint(LOG_CRITICAL,
  1855. "[FM] FmCreateResourceType: FmpSetPossibleNodeForResType for %2!ws! returned <%1!u!>...\r\n",
  1856. lpszTypeName,
  1857. dwStatus);
  1858. goto FnExit;
  1859. }
  1860. pResType = OmReferenceObjectById( ObjectTypeResType, lpszTypeName );
  1861. if ( pResType )
  1862. {
  1863. ClusterWideEvent( CLUSTER_EVENT_RESTYPE_ADDED, pResType );
  1864. OmDereferenceObject( pResType );
  1865. } else
  1866. {
  1867. if ( !FmpFMGroupsInited )
  1868. {
  1869. dwStatus = ERROR_CLUSTER_NODE_NOT_READY;
  1870. } else if ( FmpShutdown )
  1871. {
  1872. dwStatus = ERROR_CLUSTER_NODE_SHUTTING_DOWN;
  1873. } else
  1874. {
  1875. dwStatus = ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND;
  1876. }
  1877. }
  1878. FnExit:
  1879. LocalFree( Buffer );
  1880. ClRtlLogPrint(LOG_NOISE,
  1881. "[FM] FmCreateResourceType: Exit for %1!ws!, Status=%2!u!...\r\n",
  1882. lpszTypeName,
  1883. dwStatus);
  1884. return( dwStatus );
  1885. } // FmCreateResourceType
  1886. DWORD
  1887. FmDeleteResourceType(
  1888. IN LPCWSTR TypeName
  1889. )
  1890. /*++
  1891. Routine Description:
  1892. Issues a GUM update to delete a resource type on every
  1893. node.
  1894. Arguments:
  1895. TypeName - Supplies the name of the cluster resource type
  1896. to delete
  1897. Return Value:
  1898. ERROR_SUCCESS if successful.
  1899. Win32 error otherwise.
  1900. --*/
  1901. {
  1902. PFM_RESTYPE pResType;
  1903. BOOL fResourceExists = FALSE;
  1904. //
  1905. // Chittur Subbaraman (chitturs) - 5/9/2001
  1906. //
  1907. // Make sure the resource type exists so that you can avoid a GUM if
  1908. // that is not necessary. This also takes care of the case in which one node was
  1909. // shutting down and so the GUM returns success and another node fails in the GUM
  1910. // and gets evicted since the resource type does not exist.
  1911. //
  1912. pResType = OmReferenceObjectById( ObjectTypeResType,
  1913. TypeName );
  1914. if ( pResType == NULL )
  1915. {
  1916. ClRtlLogPrint(LOG_UNUSUAL,
  1917. "[FM] FmDeleteResourceType: Resource type %1!ws! does not exist...\n",
  1918. TypeName);
  1919. return( ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND );
  1920. }
  1921. //
  1922. // Check if any resources of this type exist, we do this to avoid a GUM since at shutdown
  1923. // or startup we return ERROR_SUCCESS from the common GUM handler and that triggers
  1924. // the deletion of the type from the cluster database. Ideally, we should have made the
  1925. // API transactional and do this check inside GUM but for lack of time, this is the best
  1926. // we can do now.
  1927. //
  1928. OmEnumObjects( ObjectTypeResource,
  1929. FmpFindResourceType,
  1930. pResType,
  1931. &fResourceExists );
  1932. if ( fResourceExists )
  1933. {
  1934. OmDereferenceObject ( pResType );
  1935. return ( ERROR_DIR_NOT_EMPTY );
  1936. }
  1937. OmDereferenceObject ( pResType );
  1938. return(GumSendUpdate( GumUpdateFailoverManager,
  1939. FmUpdateDeleteResourceType,
  1940. (lstrlenW(TypeName)+1)*sizeof(WCHAR),
  1941. (PVOID)TypeName ));
  1942. } // FmDeleteResourceType
  1943. /****
  1944. @func DWORD | FmEnumResTypeNode | Enumerate the possible nodes for
  1945. a resource type
  1946. @parm IN PFM_RESTYPE | pResType | Pointer to the resource type
  1947. @parm IN DWORD | dwIndex | The index for this enumeration.
  1948. @parm OUT PNM_NODE | pPossibleNode | The possible node. The returned node
  1949. pointer will be referenced by this routine and should
  1950. be dereferenced when the caller is done with it.
  1951. @comm This routine helps enumerating all the nodes that a particular
  1952. resource type can be supported on.
  1953. @rdesc Returns a result code. ERROR_SUCCESS on success.
  1954. @xref
  1955. ****/
  1956. DWORD
  1957. FmEnumResourceTypeNode(
  1958. IN PFM_RESTYPE pResType,
  1959. IN DWORD dwIndex,
  1960. OUT PNM_NODE *pPossibleNode
  1961. )
  1962. {
  1963. PLIST_ENTRY pListEntry;
  1964. DWORD i = 0;
  1965. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry;
  1966. DWORD Status = ERROR_NO_MORE_ITEMS;
  1967. FmpMustBeOnline();
  1968. //
  1969. // Chittur Subbaraman (chitturs) - 09/06/98
  1970. //
  1971. // The creation and deletion of resource types are done
  1972. // via atomic GUM operations. Hence these two operations
  1973. // (i.e. API's) are guaranteed to be mutually exclusive.
  1974. // In contrast, the resource type enumeration operation
  1975. // is not mutually exclusive with either the create
  1976. // or the delete operation. Thus, when a resource type is
  1977. // being created/deleted, there is nothing that prevents a
  1978. // client from trying to enumerate the same resource type
  1979. // in a concurrent fashion, thus producing a potential race
  1980. // condition. Thus, it is advisable to consider some form
  1981. // of locking to avoid this situation !
  1982. //
  1983. // update the list to include all nodes that now support
  1984. // the resource type
  1985. if (dwIndex == 0)
  1986. FmpSetPossibleNodeForResType(OmObjectId(pResType), TRUE);
  1987. ACQUIRE_SHARED_LOCK(gResTypeLock);
  1988. pListEntry = pResType->PossibleNodeList.Flink;
  1989. while (pListEntry != &pResType->PossibleNodeList) {
  1990. pResTypePosEntry = CONTAINING_RECORD(pListEntry,
  1991. RESTYPE_POSSIBLE_ENTRY,
  1992. PossibleLinkage);
  1993. if (i==dwIndex) {
  1994. //
  1995. // Got the right index
  1996. //
  1997. OmReferenceObject(pResTypePosEntry->PossibleNode);
  1998. *pPossibleNode = pResTypePosEntry->PossibleNode;
  1999. Status = ERROR_SUCCESS;
  2000. break;
  2001. }
  2002. pListEntry = pListEntry->Flink;
  2003. ++i;
  2004. }
  2005. RELEASE_LOCK(gResTypeLock);
  2006. return(Status);
  2007. } // FmEnumResTypeNode
  2008. DWORD
  2009. FmChangeResourceGroup(
  2010. IN PFM_RESOURCE pResource,
  2011. IN PFM_GROUP pNewGroup
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. Moves a resource from one group to another.
  2016. Arguments:
  2017. Resource - Supplies the resource to move.
  2018. Group - Supplies the new group that the resource should be in.
  2019. Return Value:
  2020. ERROR_SUCCESS if successful
  2021. Win32 error code otherwise.
  2022. --*/
  2023. {
  2024. DWORD dwStatus;
  2025. PFM_GROUP pOldGroup;
  2026. FmpMustBeOnline( );
  2027. ClRtlLogPrint(LOG_NOISE,
  2028. "[FM] FmChangeResourceGroup : Resource <%1!ws!> NewGroup %2!lx!\n",
  2029. OmObjectId( pResource ),
  2030. OmObjectId( pNewGroup));
  2031. //
  2032. // Synchronize both the old and the new groups.
  2033. // Lock the lowest by lowest Group Id first - to prevent deadlocks!
  2034. // Note - the order of release is unimportant.
  2035. //
  2036. // strictly, the comparison below cannot be equal!
  2037. //
  2038. if ( lstrcmpiW( OmObjectId( pResource->Group ), OmObjectId( pNewGroup ) ) <= 0 ) {
  2039. FmpAcquireLocalGroupLock( pResource->Group );
  2040. FmpAcquireLocalGroupLock( pNewGroup );
  2041. } else {
  2042. FmpAcquireLocalGroupLock( pNewGroup );
  2043. FmpAcquireLocalGroupLock( pResource->Group );
  2044. }
  2045. //remember the old group for freeing locks
  2046. pOldGroup = pResource->Group;
  2047. //if the resource has been marked for delete, then fail this call
  2048. if (!IS_VALID_FM_RESOURCE(pResource))
  2049. {
  2050. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  2051. goto FnUnlock;
  2052. }
  2053. //
  2054. // Check if we're moving to same group.
  2055. //
  2056. if (pResource->Group == pNewGroup) {
  2057. dwStatus = ERROR_ALREADY_EXISTS;
  2058. goto FnUnlock;
  2059. }
  2060. if ( pResource->Group->OwnerNode != NmLocalNode ) {
  2061. // Note: FmcChangeResourceNode must release the both resource lock.
  2062. dwStatus = FmcChangeResourceGroup( pResource, pNewGroup);
  2063. goto FnExit;
  2064. }
  2065. else
  2066. {
  2067. dwStatus = FmpChangeResourceGroup(pResource, pNewGroup );
  2068. }
  2069. FnUnlock:
  2070. FmpReleaseLocalGroupLock(pNewGroup);
  2071. FmpReleaseLocalGroupLock(pOldGroup);
  2072. FnExit:
  2073. ClRtlLogPrint(LOG_NOISE,
  2074. "[FM] FmChangeResourceGroup : returned <%1!u!>\r\n",
  2075. dwStatus);
  2076. return(dwStatus);
  2077. } // FmChangeResourceGroup
  2078. DWORD
  2079. FmChangeClusterName(
  2080. IN LPCWSTR pszNewName,
  2081. IN LPCWSTR pszOldName
  2082. )
  2083. /*++
  2084. Routine Description:
  2085. Changes the name of the cluster
  2086. Arguments:
  2087. pszNewName - Supplies the new cluster name.
  2088. lpszOldName - Supplies the current name
  2089. Return Value:
  2090. ERROR_SUCCESS if successful. ERROR_RESOURCE_PROPERTIES STORED if the name
  2091. has been changed but wont be effective until the core network name resource
  2092. is brought online again.
  2093. Win32 error code otherwise
  2094. --*/
  2095. {
  2096. DWORD dwStatus=ERROR_INVALID_PARAMETER;
  2097. BOOL bNameUpdated = FALSE;
  2098. PFM_RESOURCE pCoreNetNameResource = NULL;
  2099. PVOID pPropList = NULL;
  2100. DWORD dwPropListSize = 0;
  2101. LPWSTR pszBuffer;
  2102. DWORD dwLength;
  2103. DWORD dwClusterHighestVersion;
  2104. ClRtlLogPrint(LOG_NOISE,
  2105. "[FM] FmChangeClusterName : Entry NewName=%1!ws! OldName=%2!ws!\r\n",
  2106. pszNewName, pszOldName);
  2107. //get all the info to be able to change the name
  2108. dwStatus = FmpGetClusterNameChangeParams(pszNewName, &pCoreNetNameResource,
  2109. &pPropList, &dwPropListSize);
  2110. if (dwStatus != ERROR_SUCCESS)
  2111. {
  2112. ClRtlLogPrint(LOG_CRITICAL,
  2113. "[FM] FmChangeClusterName : Failed to prepare params to set new name, Status=%1!u!\r\n",
  2114. dwStatus);
  2115. goto FnExit;
  2116. }
  2117. //first validate the name
  2118. dwStatus = FmpValidateCoreNetNameChange( pCoreNetNameResource, pPropList,
  2119. dwPropListSize);
  2120. if (dwStatus != ERROR_SUCCESS)
  2121. {
  2122. ClRtlLogPrint(LOG_CRITICAL,
  2123. "[FM] FmChangeClusterName : Failed validate the name, Status=%1!u!\r\n",
  2124. dwStatus);
  2125. goto FnExit;
  2126. }
  2127. dwStatus = GumSendUpdateEx(GumUpdateFailoverManager,
  2128. FmUpdateChangeClusterName,
  2129. 1,
  2130. (lstrlenW(pszNewName)+1)*sizeof(WCHAR),
  2131. pszNewName);
  2132. if (dwStatus != ERROR_SUCCESS)
  2133. {
  2134. ClRtlLogPrint(LOG_CRITICAL,
  2135. "[FM] FmChangeClusterName : GumUpdate to set new name failed with staus=%1!u!\r\n",
  2136. dwStatus);
  2137. goto FnExit;
  2138. }
  2139. bNameUpdated = TRUE;
  2140. //Now notify the resource dll of the change via the set private properties call
  2141. //the resource dll will try to commit the change, if it fails it will undo the change
  2142. //and return failure
  2143. //SS : what if it not online
  2144. dwStatus = FmpCoreNetNameChange(pCoreNetNameResource, pPropList, dwPropListSize);
  2145. //the core network name property/cluster name has been set
  2146. //but the name change isnt effective till the resource is brought
  2147. //offline and then online again, the netname dll is expected to return the correct error
  2148. //ie we dont do any mapping
  2149. if ((dwStatus != ERROR_SUCCESS) && (dwStatus != ERROR_RESOURCE_PROPERTIES_STORED))
  2150. {
  2151. //if the resource properties have been stored or have been handled
  2152. ClRtlLogPrint(LOG_CRITICAL,
  2153. "[FM] FmChangeClusterName : FmpCoreNetNameChange failed status=%1!u!\r\n",
  2154. dwStatus);
  2155. goto FnExit;
  2156. }
  2157. //the name change was successful generate the event notifications
  2158. //ignore the errors caused due to notifications, it is hard enough to
  2159. //recover from changes spanning the service and netname that at this point
  2160. //we wont bother with event notification problems
  2161. //dont issue the event notification in a mixed mode cluster..a bug in win2K
  2162. //cluster wide notification might result in an av
  2163. //
  2164. // If we are dealing with the mixed mode cluster or if the group does not have the antiaffinity
  2165. // property set, then don't do anything.
  2166. //
  2167. NmGetClusterOperationalVersion( &dwClusterHighestVersion,
  2168. NULL,
  2169. NULL );
  2170. if ( ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) < NT51_MAJOR_VERSION ))
  2171. {
  2172. //there is a lower version(lower than whistler) node in the cluster
  2173. //we could issue a local event here but that doesnt help if the
  2174. //cluster has more than two nodes..who would issue the event on other
  2175. //whistler nodes?
  2176. goto FnExit;
  2177. }
  2178. else
  2179. {
  2180. ClusterWideEventEx(CLUSTER_EVENT_PROPERTY_CHANGE, EP_CONTEXT_VALID|EP_FREE_CONTEXT, (PVOID)pszNewName,
  2181. ((lstrlenW(pszNewName) + 1) * sizeof(WCHAR)));
  2182. }
  2183. FnExit:
  2184. if (((dwStatus != ERROR_SUCCESS) && (dwStatus != ERROR_RESOURCE_PROPERTIES_STORED))
  2185. && (bNameUpdated))
  2186. {
  2187. DWORD dwError;
  2188. //we need to revert the change, netname doesnt like it
  2189. //and doesnt return success or properties stored.
  2190. //netname should not set the registry to revert to the old name
  2191. //it should leave that to FM
  2192. //If the locker fails to revert it back(hopefully that doesnt happen
  2193. //often, then the admin needs to fix the problem since now we will
  2194. //have a new cluster name that perhaps wont ever come online
  2195. ClRtlLogPrint(LOG_UNUSUAL,
  2196. "[FM] FmChangeClusterName : Making the GumUpdate to revert to old name.\r\n");
  2197. dwError = GumSendUpdateEx(GumUpdateFailoverManager,
  2198. FmUpdateChangeClusterName,
  2199. 1,
  2200. (lstrlenW(pszOldName)+1)*sizeof(WCHAR),
  2201. pszOldName);
  2202. if (dwError != ERROR_SUCCESS)
  2203. {
  2204. ClRtlLogPrint(LOG_CRITICAL,
  2205. "[FM] FmChangeClusterName : GumUpdate to revert to old name failed, status=%1!u!\r\n",
  2206. dwError);
  2207. //log an ominous message in the event log to say the network name
  2208. //change didnt happen successfully but the name has been changed and this might require administrative
  2209. //action to fix the problems
  2210. CL_LOGCLUSWARNING(SERVICE_NETNAME_CHANGE_WARNING);
  2211. }
  2212. }
  2213. if (pCoreNetNameResource)
  2214. OmDereferenceObject(pCoreNetNameResource);
  2215. if (pPropList)
  2216. LocalFree(pPropList);
  2217. ClRtlLogPrint(LOG_NOISE,
  2218. "[FM] FmChangeClusterName : Exit dwStatus=%1!u!\r\n",
  2219. dwStatus);
  2220. return(dwStatus);
  2221. } // FmChangeClusterName
  2222. DWORD
  2223. FmpSetResourceName(
  2224. IN PFM_RESOURCE pResource,
  2225. IN LPCWSTR lpszFriendlyName
  2226. )
  2227. /*++
  2228. Routine Description:
  2229. Updates the resource name consistently in the fm databases across
  2230. the cluster.
  2231. Arguments:
  2232. pResource - The resource whose name is changed.
  2233. lpszFriendlyName - The new name of the resource.
  2234. Return Value:
  2235. ERROR_SUCCESS if successful.
  2236. A Win32 error code on failure.
  2237. --*/
  2238. {
  2239. LPCWSTR ResourceId;
  2240. DWORD Status;
  2241. ResourceId = OmObjectId(pResource);
  2242. return(GumSendUpdateEx( GumUpdateFailoverManager,
  2243. FmUpdateChangeResourceName,
  2244. 2,
  2245. (lstrlenW(ResourceId)+1)*sizeof(WCHAR),
  2246. ResourceId,
  2247. (lstrlenW(lpszFriendlyName)+1)*sizeof(WCHAR),
  2248. lpszFriendlyName ));
  2249. } // FmpSetResourceName
  2250. DWORD
  2251. FmpRegUpdateClusterName(
  2252. IN LPCWSTR szNewClusterName
  2253. )
  2254. /*++
  2255. Routine Description:
  2256. This routine updates the cluster name in the cluster database.
  2257. Arguments:
  2258. szNewClusterName - A pointer to the new cluster name string.
  2259. Return Value:
  2260. ERROR_SUCCESS if successful.
  2261. A Win32 error on failure.
  2262. --*/
  2263. {
  2264. return(DmSetValue( DmClusterParametersKey,
  2265. CLUSREG_NAME_CLUS_NAME,
  2266. REG_SZ,
  2267. (CONST BYTE *)szNewClusterName,
  2268. (lstrlenW(szNewClusterName)+1)*sizeof(WCHAR) ));
  2269. } // FmpRegUpdateClusterName
  2270. DWORD
  2271. FmEvictNode(
  2272. IN PNM_NODE Node
  2273. )
  2274. /*++
  2275. Routine Description:
  2276. Removes any references to the specified node that the FM might
  2277. have put on.
  2278. Arguments:
  2279. Node - Supplies the node that is being evicted.
  2280. Return Value:
  2281. ERROR_SUCCESS if successful
  2282. Win32 error code otherwise
  2283. --*/
  2284. {
  2285. //add a reference to the node object, the worker thread will remove this
  2286. OmReferenceObject(Node);
  2287. FmpPostWorkItem(FM_EVENT_NODE_EVICTED,
  2288. Node,
  2289. 0);
  2290. return(ERROR_SUCCESS);
  2291. } // FmEvictNode
  2292. BOOL
  2293. FmCheckNetworkDependency(
  2294. IN LPCWSTR DependentNetwork
  2295. )
  2296. /*++
  2297. Routine Description:
  2298. Check if any IP Address resource has a dependency on a given network.
  2299. Arguments:
  2300. DependentNetwork - the GUID for the network to check.
  2301. Return Value:
  2302. TRUE - if an IP Address resource depends on the given network.
  2303. FALSE otherwise.
  2304. --*/
  2305. {
  2306. return( FmpCheckNetworkDependency( DependentNetwork ) );
  2307. } // FmCheckNetworkDependency
  2308. DWORD
  2309. WINAPI
  2310. FmBackupClusterDatabase(
  2311. IN LPCWSTR lpszPathName
  2312. )
  2313. /*++
  2314. Routine Description:
  2315. Attempts a backup of the quorum log files.
  2316. Arguments:
  2317. lpszPathName - The directory path name where the files have to be
  2318. backed up. This path must be visible to the node
  2319. on which the quorum resource is online.
  2320. Returns:
  2321. ERROR_SUCCESS if successful.
  2322. A Win32 error code on failure.
  2323. --*/
  2324. {
  2325. DWORD status;
  2326. PFM_RESOURCE pQuoResource = NULL;
  2327. FmpMustBeOnline( );
  2328. //
  2329. // Chittur Subbaraman (chitturs) - 10/12/98
  2330. //
  2331. // Find the quorum resource
  2332. //
  2333. status = FmFindQuorumResource( &pQuoResource );
  2334. if ( status != ERROR_SUCCESS )
  2335. {
  2336. ClRtlLogPrint(LOG_UNUSUAL,
  2337. "[FM] FmBackupQuorumLog: Could not find quorum resource...\r\n");
  2338. goto FnExit;
  2339. }
  2340. //
  2341. // Acquire the local resource lock
  2342. //
  2343. FmpAcquireLocalResourceLock( pQuoResource );
  2344. //
  2345. // Handle the request here if this node is the owner of the
  2346. // quorum resource, else redirect it to the appropriate node.
  2347. //
  2348. if ( pQuoResource->Group->OwnerNode != NmLocalNode )
  2349. {
  2350. //
  2351. // This function will release the resource lock
  2352. //
  2353. status = FmcBackupClusterDatabase( pQuoResource, lpszPathName );
  2354. } else
  2355. {
  2356. status = FmpBackupClusterDatabase( pQuoResource, lpszPathName );
  2357. FmpReleaseLocalResourceLock( pQuoResource );
  2358. }
  2359. OmDereferenceObject ( pQuoResource );
  2360. FnExit:
  2361. return( status );
  2362. } // FmBackupClusterDatabase
  2363. DWORD
  2364. FmpBackupClusterDatabase(
  2365. IN PFM_RESOURCE pQuoResource,
  2366. IN LPCWSTR lpszPathName
  2367. )
  2368. /*++
  2369. Routine Description:
  2370. This routine first waits until the quorum resource becomes
  2371. online. Then, it attempts to backup the quorum log file and the
  2372. checkpoint file to the specified directory path. This function
  2373. is called with the local resource lock held.
  2374. Arguments:
  2375. pQuoResource - Pointer to the quorum resource.
  2376. lpszPathName - The directory path name where the files have to be
  2377. backed up. This path must be visible to the node
  2378. on which the quorum resource is online.
  2379. Comments:
  2380. The order in which the locks are acquired is very crucial here.
  2381. Carelessness in following this strict order of acquisition can lead
  2382. to potential deadlocks. The order that is followed is
  2383. (1) Local resource lock - pQuoResource->Group->Lock acquired
  2384. outside this function.
  2385. (2) Global quorum resource lock - gQuoLock acquired here
  2386. (3) Global Dm root lock - gLockDmpRoot acquired in
  2387. DmBackupClusterDatabase( ).
  2388. --*/
  2389. {
  2390. DWORD retry = 200;
  2391. DWORD Status = ERROR_SUCCESS;
  2392. CL_ASSERT( pQuoResource->Group->OwnerNode == NmLocalNode );
  2393. //
  2394. // Chittur Subbaraman (chitturs) - 10/12/1998
  2395. //
  2396. // If quorum logging is not turned on, then log an error
  2397. // and exit immediately.
  2398. //
  2399. if ( CsNoQuorumLogging )
  2400. {
  2401. Status = ERROR_QUORUMLOG_OPEN_FAILED;
  2402. CL_LOGFAILURE( ERROR_QUORUMLOG_OPEN_FAILED );
  2403. ClRtlLogPrint(LOG_NOISE,
  2404. "[FM] FmpBackupClusterDatabase: Quorum logging is not turned on, can't backup...\r\n");
  2405. goto FnExit;
  2406. }
  2407. CheckQuorumState:
  2408. ACQUIRE_EXCLUSIVE_LOCK( gQuoLock );
  2409. //
  2410. // Check the state of the quorum resource. If it has failed or is
  2411. // offline, release the lock and exit immediately !
  2412. //
  2413. if ( pQuoResource->State == ClusterResourceFailed )
  2414. {
  2415. Status = ERROR_QUORUM_RESOURCE_ONLINE_FAILED;
  2416. CL_LOGFAILURE( ERROR_QUORUM_RESOURCE_ONLINE_FAILED );
  2417. ClRtlLogPrint(LOG_NOISE,
  2418. "[FM] FmpBackupClusterDatabase: Quorum resource is in failed state, exiting...\r\n");
  2419. RELEASE_LOCK( gQuoLock );
  2420. goto FnExit;
  2421. }
  2422. //
  2423. // Check if the quorum resource is online. If the quorum resource
  2424. // is marked as waiting and offlinepending, it is actually online.
  2425. // If the quorum resource still needs to come online, release the
  2426. // lock and wait.
  2427. //
  2428. if ( ( ( pQuoResource->State != ClusterResourceOnline ) &&
  2429. ( ( pQuoResource->State != ClusterResourceOfflinePending ) ||
  2430. ( !( pQuoResource->Flags & RESOURCE_WAITING ) ) ) )
  2431. )
  2432. {
  2433. //
  2434. // We release the lock here since the quorum resource
  2435. // state transition from pending needs to acquire the lock.
  2436. // In general it is a bad idea to do a wait holding locks.
  2437. //
  2438. RELEASE_LOCK( gQuoLock );
  2439. ClRtlLogPrint(LOG_NOISE,
  2440. "[FM] FmpBackupClusterDatabase: Release ghQuoLock and wait on ghQuoOnlineEvent...\r\n");
  2441. Status = WaitForSingleObject( ghQuoOnlineEvent, 500 );
  2442. if ( Status == WAIT_OBJECT_0 )
  2443. {
  2444. //
  2445. // If we are going to retry, wait a little bit and retry.
  2446. //
  2447. Sleep( 500 );
  2448. }
  2449. if ( retry-- )
  2450. {
  2451. goto CheckQuorumState;
  2452. }
  2453. CL_LOGFAILURE( ERROR_QUORUM_RESOURCE_ONLINE_FAILED ) ;
  2454. ClRtlLogPrint(LOG_NOISE,
  2455. "[FM] FmpBackupClusterDatabase: All retries to check for quorum resource online failed, exiting...\r\n");
  2456. return( ERROR_QUORUM_RESOURCE_ONLINE_FAILED );
  2457. }
  2458. Status = DmBackupClusterDatabase( lpszPathName );
  2459. RELEASE_LOCK( gQuoLock );
  2460. FnExit:
  2461. return ( Status );
  2462. } // FmpBackupClusterDatabase
  2463. /****
  2464. @func WORD| FmCheckQuorumState| If the quorum resource is online
  2465. on this node right now, it calls the callback and the boolean
  2466. value passed in is set to FALSE. If not, the boolean is
  2467. set to TRUE.
  2468. @parm LPWSTR | szQuorumLogPath | A pointer to a wide string of size MAX_PATH.
  2469. @parm DWORD | dwSize | The size of szQuorumLogPath in bytes.
  2470. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  2471. @comm If the quorum resource is not cabaple of logging this should not be set.
  2472. @xref
  2473. ****/
  2474. void FmCheckQuorumState(
  2475. FM_ONLINE_ONTHISNODE_CB OnlineOnThisNodeCb,
  2476. PBOOL pbOfflineOnThisNode)
  2477. {
  2478. BOOL bLocked = FALSE;
  2479. DWORD dwRetryCount = 1200; // Wait 10 min max
  2480. //
  2481. // SS: The mutual exclusion between this event handler and
  2482. // the synchronous resource online/offline callback is
  2483. // achieved by using the quorum change lock(gQuoChangeLock)
  2484. //
  2485. //
  2486. // Chittur Subbaraman (chitturs) - 7/5/99
  2487. //
  2488. // Modify group lock acquisition to release gQuoChangeLock and
  2489. // retry lock acquisition. This is necessary to take care of the
  2490. // case in which the quorum online notification is stuck in
  2491. // FmpHandleResourceTransition waiting for the gQuoChangeLock and
  2492. // some other resource in the quorum group is stuck in FmpRmOnlineResource
  2493. // holding the quorum group lock and waiting for the quorum resource
  2494. // to go online.
  2495. //
  2496. try_acquire_lock:
  2497. ACQUIRE_EXCLUSIVE_LOCK( gQuoChangeLock );
  2498. FmpTryAcquireLocalGroupLock( gpQuoResource->Group, bLocked );
  2499. if ( bLocked == FALSE )
  2500. {
  2501. RELEASE_LOCK( gQuoChangeLock );
  2502. ClRtlLogPrint(LOG_NOISE,
  2503. "[FM] FmCheckQuorumState - Release gQuoChangeLock, sleep and retry group lock acquisition...\r\n");
  2504. if ( dwRetryCount == 0 )
  2505. {
  2506. ClRtlLogPrint(LOG_CRITICAL,
  2507. "[FM] FmCheckQuorumState - Unable to get quorum group lock for 10 min, halting...\r\n");
  2508. CsInconsistencyHalt( ERROR_LOCK_FAILED );
  2509. }
  2510. dwRetryCount --;
  2511. Sleep( 500 );
  2512. goto try_acquire_lock;
  2513. }
  2514. CL_ASSERT( bLocked == TRUE );
  2515. *pbOfflineOnThisNode = FALSE;
  2516. if (gpQuoResource->Group->OwnerNode == NmLocalNode)
  2517. {
  2518. ClRtlLogPrint(LOG_NOISE,
  2519. "[FM] FmCheckQuorumState - I am owner, check the state of the resource .\r\n");
  2520. //if the quorum resource is not online right now
  2521. //it might be in the middle of a move and this node
  2522. //might be the target of the move
  2523. //set a flag to indicate that a checkpoint is necessary
  2524. //when it does come online
  2525. if(gpQuoResource->State != ClusterResourceOnline)
  2526. {
  2527. ClRtlLogPrint(LOG_NOISE,
  2528. "[FM] FmCheckQuorumState - Quorum is owned but not online on this node.\r\n");
  2529. *pbOfflineOnThisNode = TRUE;
  2530. }
  2531. else
  2532. {
  2533. (*OnlineOnThisNodeCb)();
  2534. }
  2535. }
  2536. else
  2537. {
  2538. ClRtlLogPrint(LOG_NOISE,
  2539. "[FM] FmCheckQuorumState - Quorum is owned by another node.\r\n");
  2540. *pbOfflineOnThisNode = TRUE;
  2541. }
  2542. FmpReleaseLocalGroupLock(gpQuoResource->Group);
  2543. RELEASE_LOCK(gQuoChangeLock);
  2544. }
  2545. /****
  2546. @func WORD| FmDoesQuorumAllowJoin| If the quorum resource doesnt support
  2547. multiple nodes, return error. Added to officially support local quorum resources.
  2548. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  2549. @comm If the quorum resource is not cabaple of logging this should not be set.
  2550. @xref
  2551. ****/
  2552. DWORD FmDoesQuorumAllowJoin(
  2553. IN PCWSTR pszJoinerNodeId )
  2554. {
  2555. DWORD dwStatus = ERROR_SUCCESS;
  2556. ACQUIRE_SHARED_LOCK(gQuoChangeLock);
  2557. ClRtlLogPrint(LOG_NOISE,
  2558. "[FM] FmDoesQuorumAllowJoin - Entry\r\n");
  2559. //get the characteristics for the new quorum resource
  2560. dwStatus = FmpGetResourceCharacteristics(gpQuoResource,
  2561. &(gpQuoResource->Characteristic));
  2562. if (dwStatus != ERROR_SUCCESS)
  2563. {
  2564. ClRtlLogPrint(LOG_UNUSUAL,
  2565. "[FM] FmDoesQuorumAllowJoin - couldnt get quorum characteristics %1!u!\r\n",
  2566. dwStatus);
  2567. goto FnExit;
  2568. }
  2569. if ((gpQuoResource->Characteristic & CLUS_CHAR_LOCAL_QUORUM) &&
  2570. !(gpQuoResource->Characteristic & CLUS_CHAR_LOCAL_QUORUM_DEBUG))
  2571. {
  2572. //Note :: we need an error code?
  2573. dwStatus = ERROR_OPERATION_ABORTED;
  2574. goto FnExit;
  2575. }
  2576. // JAF: RAID 513705: if a site is being started with ForceQuorum, and a 2nd site
  2577. // comes online automatically after, e.g., a power failure, they will attempt to join
  2578. // and will have a different idea of what constitutes a majority.
  2579. // Do not allow them to join if ForceQuorum is true.
  2580. if ( CsForceQuorum && ( CsForceQuorumNodes != NULL ))
  2581. {
  2582. if ( !FmpIsNodeInForceQuorumNodes( pszJoinerNodeId ))
  2583. {
  2584. ClRtlLogPrint(LOG_UNUSUAL,
  2585. "[FM] Disallowing join of %1!ws! since it is not in the list of forceQuorum nodes.\n",
  2586. pszJoinerNodeId );
  2587. dwStatus = ERROR_OPERATION_ABORTED;
  2588. goto FnExit;
  2589. }
  2590. else {
  2591. ClRtlLogPrint(LOG_NOISE,
  2592. "[FM] Node %1!ws! is in the list of forceQuorum nodes; allowing join to proceed.\n",
  2593. pszJoinerNodeId );
  2594. }
  2595. }
  2596. FnExit:
  2597. RELEASE_LOCK(gQuoChangeLock);
  2598. ClRtlLogPrint(LOG_NOISE,
  2599. "[FM] FmDoesQuorumAllowJoin - Exit, Status=%1!u!\r\n",
  2600. dwStatus);
  2601. return(dwStatus);
  2602. }
  2603. /****
  2604. @func WORD| FmDoesQuorumAllowLogging| If the quorum resource doesnt support
  2605. multiple nodes, return error. Added to officially support local quorum resources.
  2606. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  2607. @comm If the quorum resource is not cabaple of logging this should not be set.
  2608. @xref
  2609. ****/
  2610. DWORD FmDoesQuorumAllowLogging(
  2611. IN DWORD dwQuorumResourceCharacteristics OPTIONAL
  2612. )
  2613. {
  2614. DWORD dwStatus = ERROR_SUCCESS;
  2615. ACQUIRE_SHARED_LOCK(gQuoChangeLock);
  2616. ClRtlLogPrint(LOG_NOISE,
  2617. "[FM] FmDoesQuorumAllowLogging - Entry\r\n");
  2618. if ( dwQuorumResourceCharacteristics == CLUS_CHAR_UNKNOWN )
  2619. {
  2620. //get the characteristics for the new quorum resource
  2621. dwStatus = FmpGetResourceCharacteristics(gpQuoResource,
  2622. &(gpQuoResource->Characteristic));
  2623. if (dwStatus != ERROR_SUCCESS)
  2624. {
  2625. ClRtlLogPrint(LOG_UNUSUAL,
  2626. "[FM] FmDoesQuorumAllowLogging - couldnt get quorum characteristics %1!u!\r\n",
  2627. dwStatus);
  2628. goto FnExit;
  2629. }
  2630. } else
  2631. {
  2632. gpQuoResource->Characteristic = dwQuorumResourceCharacteristics;
  2633. ClRtlLogPrint(LOG_NOISE,
  2634. "[FM] FmDoesQuorumAllowLogging - Using passed in characteristics 0x%1!08lx!\n",
  2635. dwQuorumResourceCharacteristics);
  2636. }
  2637. if (gpQuoResource->Characteristic & CLUS_CHAR_LOCAL_QUORUM)
  2638. {
  2639. WCHAR szQuorumFileName[MAX_PATH];
  2640. //Note :: we need an error code?
  2641. //if the path is an smb path name, we should allow logging
  2642. //else we should disable it
  2643. dwStatus = DmGetQuorumLogPath(szQuorumFileName, sizeof(szQuorumFileName));
  2644. if ((szQuorumFileName[0] == L'\\') && (szQuorumFileName[1] == L'\\'))
  2645. {
  2646. //assume this is an smb path
  2647. //allow logging
  2648. dwStatus = ERROR_SUCCESS;
  2649. }
  2650. else
  2651. {
  2652. dwStatus = ERROR_OPERATION_ABORTED;
  2653. }
  2654. }
  2655. FnExit:
  2656. RELEASE_LOCK(gQuoChangeLock);
  2657. ClRtlLogPrint(LOG_NOISE,
  2658. "[FM] FmDoesQuorumAllowLogging - Exit, status=%1!u!\r\n",
  2659. dwStatus);
  2660. return(dwStatus);
  2661. }
  2662. DWORD
  2663. FmpCanonicalizePath(
  2664. IN OUT LPWSTR lpszPath,
  2665. OUT PBOOL pfIsPathUNC
  2666. )
  2667. /*++
  2668. Routine Description:
  2669. This routine converts a path of the form \\xyz\share to \\?\UNC\xyz\share.
  2670. Arguments:
  2671. lpszPathName - The path that must be converted.
  2672. pfIsPathUNC - Is the path of UNC type.
  2673. Return value:
  2674. None.
  2675. --*/
  2676. {
  2677. DWORD dwStatus = ERROR_SUCCESS;
  2678. WCHAR szUNC[] = L"\\\\?\\UNC\\";
  2679. WCHAR szSlash[] = L"\\\\";
  2680. WCHAR szTempPath[MAX_PATH];
  2681. LPCWSTR lpszUNCStart, lpszSlashStart;
  2682. //
  2683. // Optimistically assume it is a UNC path. If it is not a UNC path, we set it back to
  2684. // FALSE. In a failure case, we don't care about the value of the boolean variable.
  2685. //
  2686. *pfIsPathUNC = TRUE;
  2687. //
  2688. // First check if the path starts with a "\\". If not, you are done.
  2689. //
  2690. lpszSlashStart = wcsstr( lpszPath, szSlash );
  2691. if ( lpszSlashStart == NULL )
  2692. {
  2693. *pfIsPathUNC = FALSE;
  2694. goto FnExit;
  2695. }
  2696. //
  2697. // Next, make sure there are not more than 2 slashes any where in the path except at
  2698. // the start.
  2699. //
  2700. lpszSlashStart = wcsstr( lpszPath+1, szSlash );
  2701. if ( lpszSlashStart != NULL )
  2702. {
  2703. ClRtlLogPrint(LOG_ERROR, "[FM] FmpCanonicalizePath: Supplied path %1!ws! is invalid...\n",
  2704. lpszPath);
  2705. dwStatus = ERROR_INVALID_PARAMETER;
  2706. goto FnExit;
  2707. }
  2708. //
  2709. // Next, check if the path already has UNC at the beginning. If so, you are done.
  2710. //
  2711. lpszUNCStart = wcsstr( lpszPath, szUNC );
  2712. if ( lpszUNCStart != NULL )
  2713. {
  2714. if ( lpszUNCStart != lpszPath )
  2715. {
  2716. ClRtlLogPrint(LOG_ERROR, "[FM] FmpCanonicalizePath: Supplied path %1!ws! is invalid...\n",
  2717. lpszPath);
  2718. dwStatus = ERROR_INVALID_PARAMETER;
  2719. }
  2720. goto FnExit;
  2721. }
  2722. lstrcpy( szTempPath, szUNC );
  2723. lstrcat( szTempPath, lpszPath+2 );
  2724. lstrcpy( lpszPath, szTempPath );
  2725. FnExit:
  2726. ClRtlLogPrint(LOG_NOISE, "[FM] FmpCanonicalizePath: Exit Status %1!u!, Return path = %2!ws!\n",
  2727. dwStatus,
  2728. lpszPath);
  2729. return ( dwStatus );
  2730. } // FmpCanonicalizePath
  2731. DWORD FmpGetClusterNameChangeParams(
  2732. IN LPCWSTR lpszNewName,
  2733. OUT PFM_RESOURCE *ppCoreNetNameResource,
  2734. OUT PVOID *ppPropList,
  2735. OUT LPDWORD pdwPropListSize
  2736. )
  2737. {
  2738. PFM_RESOURCE pResource = NULL;
  2739. DWORD dwSize = 0;
  2740. DWORD dwStatus;
  2741. LPWSTR lpszClusterNameResource = NULL;
  2742. CLUSPROP_BUFFER_HELPER ListEntry;
  2743. PVOID pPropList = NULL;
  2744. DWORD cbListSize = 0;
  2745. DWORD dwBufferSize;
  2746. //initialize the returns
  2747. *ppCoreNetNameResource = NULL;
  2748. *pdwPropListSize = 0;
  2749. *ppPropList = NULL;
  2750. ClRtlLogPrint(LOG_NOISE,
  2751. "[FM] FmpGetClusterNameChangeParams: Entry !\n");
  2752. dwStatus = DmQuerySz( DmClusterParametersKey,
  2753. CLUSREG_NAME_CLUS_CLUSTER_NAME_RES,
  2754. &lpszClusterNameResource,
  2755. &dwSize,
  2756. &dwSize );
  2757. if ( dwStatus != ERROR_SUCCESS )
  2758. {
  2759. ClRtlLogPrint(LOG_CRITICAL,
  2760. "[FM] FmpGetClusterNameChangeParams: Failed to get cluster name resource from registry, error %1!u!...\n",
  2761. dwStatus);
  2762. goto FnExit;
  2763. }
  2764. //
  2765. // Reference the specified resource ID.
  2766. //
  2767. pResource = OmReferenceObjectById( ObjectTypeResource,
  2768. lpszClusterNameResource );
  2769. if ( pResource == NULL )
  2770. {
  2771. dwStatus = ERROR_RESOURCE_NOT_FOUND;
  2772. ClRtlLogPrint(LOG_CRITICAL,
  2773. "[FM] FmGetClusterNameChangeParams: Failed to find cluster name resource, %1!u!...\n",
  2774. dwStatus);
  2775. goto FnExit;
  2776. }
  2777. dwBufferSize = sizeof( ListEntry.pList->nPropertyCount ) +
  2778. sizeof( *ListEntry.pName ) +
  2779. ALIGN_CLUSPROP( ( lstrlenW( CLUSREG_NAME_NET_NAME ) + 1 ) * sizeof( WCHAR ) ) +
  2780. sizeof( *ListEntry.pStringValue ) +
  2781. ALIGN_CLUSPROP( ( lstrlenW( lpszNewName ) + 1 ) * sizeof( WCHAR ) ) +
  2782. sizeof( *ListEntry.pSyntax );
  2783. ListEntry.pb = (PBYTE) LocalAlloc( LPTR, dwBufferSize );
  2784. if ( ListEntry.pb == NULL )
  2785. {
  2786. dwStatus = GetLastError();
  2787. ClRtlLogPrint(LOG_CRITICAL,
  2788. "[FM] FmGetClusterNameChangeParams: Error %1!u! in allocating memory...\n",
  2789. dwStatus);
  2790. goto FnExit;
  2791. }
  2792. pPropList = ListEntry.pb;
  2793. ListEntry.pList->nPropertyCount = 1;
  2794. cbListSize += sizeof( ListEntry.pList->nPropertyCount );
  2795. ListEntry.pb += sizeof( ListEntry.pList->nPropertyCount );
  2796. ListEntry.pName->Syntax.dw = CLUSPROP_SYNTAX_NAME;
  2797. ListEntry.pName->cbLength = ( lstrlenW( CLUSREG_NAME_NET_NAME ) + 1 ) * sizeof( WCHAR );
  2798. lstrcpyW( ListEntry.pName->sz, CLUSREG_NAME_NET_NAME );
  2799. cbListSize += sizeof( *ListEntry.pName ) + ALIGN_CLUSPROP( ListEntry.pName->cbLength );
  2800. ListEntry.pb += sizeof( *ListEntry.pName ) + ALIGN_CLUSPROP( ListEntry.pName->cbLength );
  2801. ListEntry.pStringValue->Syntax.dw = CLUSPROP_SYNTAX_LIST_VALUE_SZ;
  2802. ListEntry.pStringValue->cbLength = ( lstrlenW( lpszNewName ) + 1 ) * sizeof( WCHAR );
  2803. lstrcpyW( ListEntry.pStringValue->sz, lpszNewName );
  2804. cbListSize += sizeof( *ListEntry.pStringValue ) + ALIGN_CLUSPROP( ListEntry.pName->cbLength );
  2805. ListEntry.pb += sizeof( *ListEntry.pStringValue ) + ALIGN_CLUSPROP( ListEntry.pName->cbLength );
  2806. ListEntry.pSyntax->dw = CLUSPROP_SYNTAX_ENDMARK;
  2807. cbListSize += sizeof( *ListEntry.pSyntax );
  2808. ListEntry.pb += sizeof( *ListEntry.pSyntax );
  2809. *ppCoreNetNameResource = pResource;
  2810. *ppPropList = pPropList;
  2811. *pdwPropListSize = dwBufferSize;
  2812. FnExit:
  2813. if (lpszClusterNameResource)
  2814. LocalFree(lpszClusterNameResource);
  2815. if (dwStatus != ERROR_SUCCESS)
  2816. {
  2817. if (pResource) OmDereferenceObject(pResource);
  2818. if (pPropList) LocalFree(pPropList);
  2819. }
  2820. ClRtlLogPrint(LOG_NOISE,
  2821. "[FM] FmpGetClusterNameChangeParams: Exit !\n");
  2822. return(dwStatus);
  2823. }
  2824. /****
  2825. @func DWORD| FmpValideCoreNetNameChange| Send a control code to the core
  2826. netname resource to validate the change.
  2827. @param IN PFM_RESOURCE | pResource | A pointer to the core netname resource.
  2828. @param IN PVOID | pPropList | Pointer to a property list.
  2829. @param IN DWORD | cbListSize | Size of the property list.
  2830. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  2831. @comm
  2832. @xref
  2833. ****/
  2834. DWORD FmpValidateCoreNetNameChange(
  2835. IN PFM_RESOURCE pResource,
  2836. IN PVOID pPropList,
  2837. IN DWORD cbListSize
  2838. )
  2839. {
  2840. DWORD dwBytesReturned;
  2841. DWORD dwRequired;
  2842. DWORD dwStatus;
  2843. ClRtlLogPrint(LOG_NOISE,
  2844. "[FM] FmpValidateCoreNetNameChange : Calling Core netname to validate\r\n");
  2845. dwStatus = FmResourceControl( pResource,
  2846. NULL,
  2847. CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES,
  2848. (PUCHAR)pPropList,
  2849. cbListSize,
  2850. NULL,
  2851. 0,
  2852. &dwBytesReturned,
  2853. &dwRequired );
  2854. return(dwStatus);
  2855. }
  2856. /****
  2857. @func WORD| FmCoreNetNameChange| Asks the core network name resource
  2858. to perform all the network name change related operations.
  2859. @param IN PFM_RESOURCE | pResource | A pointer to the core netname resource.
  2860. @param IN PVOID | pPropList | Pointer to a property list.
  2861. @param IN DWORD | cbListSize | Size of the property list.
  2862. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  2863. @comm
  2864. @xref
  2865. ****/
  2866. DWORD FmpCoreNetNameChange(
  2867. IN PFM_RESOURCE pResource,
  2868. IN PVOID pPropList,
  2869. IN DWORD cbListSize
  2870. )
  2871. {
  2872. DWORD dwBytesReturned;
  2873. DWORD dwRequired;
  2874. DWORD dwStatus;
  2875. ClRtlLogPrint(LOG_NOISE,
  2876. "[FM] FmpCoreNetNameChange : Invoking the core netname resource dll\r\n");
  2877. dwStatus = FmResourceControl( pResource,
  2878. NULL,
  2879. CLUSCTL_RESOURCE_CLUSTER_NAME_CHANGED,
  2880. (PUCHAR)pPropList,
  2881. cbListSize,
  2882. NULL,
  2883. 0,
  2884. &dwBytesReturned,
  2885. &dwRequired );
  2886. return(dwStatus);
  2887. }