Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

803 lines
18 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. fmval.c
  5. Abstract:
  6. Cluster manager api validation/support routines.
  7. Author:
  8. Sunita Shrivastava (sunitas) 29-April-1999.
  9. Revision History:
  10. --*/
  11. #include "fmp.h"
  12. #define LOG_MODULE FMVAL
  13. ////////////////////////////////////////////////////////
  14. //
  15. // Validation routines for Group operations.
  16. //
  17. ////////////////////////////////////////////////////////
  18. DWORD
  19. FmpValOnlineGroup(
  20. IN PFM_GROUP Group
  21. )
  22. /*++
  23. Routine Description:
  24. Validation routine before group is brought online.
  25. Arguments:
  26. Group - Supplies a pointer to the group structure to bring online.
  27. Comments:
  28. Is called with the localgroup lock held
  29. Returns:
  30. ERROR_SUCCESS if the validation is successful.
  31. A Win32 error code if the validation fails.
  32. --*/
  33. {
  34. DWORD dwStatus = ERROR_SUCCESS;
  35. PLIST_ENTRY listEntry;
  36. //if the group has been marked for delete, then fail this call
  37. if (!IS_VALID_FM_GROUP(Group))
  38. {
  39. dwStatus = ERROR_GROUP_NOT_AVAILABLE;
  40. goto FnExit;
  41. }
  42. //
  43. // Make sure the owning node can run the group.
  44. //
  45. if ( !FmpInPreferredList( Group, Group->OwnerNode ) )
  46. {
  47. dwStatus = ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST;
  48. goto FnExit;
  49. }
  50. //
  51. // Make sure the owning node is not paused.
  52. //
  53. if (NmGetNodeState(Group->OwnerNode) == ClusterNodePaused)
  54. {
  55. dwStatus = ERROR_SHARING_PAUSED;
  56. goto FnExit;
  57. }
  58. FnExit:
  59. return(dwStatus);
  60. } // FmpValOnlineGroup
  61. DWORD
  62. FmpValMoveGroup(
  63. IN PFM_GROUP Group,
  64. IN PNM_NODE DestinationNode OPTIONAL
  65. )
  66. /*++
  67. Routine Description:
  68. Validation routine for group move.
  69. Arguments:
  70. Group - Supplies a pointer to the group structure to move.
  71. DestinationNode - Supplies the node object to move the group to. If not
  72. present, then move it to THE OTHER node.
  73. Returns:
  74. ERROR_SUCCESS if the validation is successful.
  75. A Win32 error code if the validation fails.
  76. --*/
  77. {
  78. DWORD dwStatus = ERROR_SUCCESS;
  79. //if the group has been marked for delete, then fail this call
  80. if (!IS_VALID_FM_GROUP(Group))
  81. {
  82. dwStatus = ERROR_GROUP_NOT_AVAILABLE;
  83. goto FnExit;
  84. }
  85. if ( FmpIsGroupPending(Group) )
  86. {
  87. dwStatus = ERROR_GROUP_NOT_AVAILABLE;
  88. goto FnExit;
  89. }
  90. if ( Group->OwnerNode == NULL )
  91. {
  92. dwStatus = ERROR_HOST_NODE_NOT_AVAILABLE;
  93. goto FnExit;
  94. }
  95. FnExit:
  96. return(dwStatus);
  97. } // FmpValMoveGroup
  98. ////////////////////////////////////////////////////////
  99. //
  100. // Validation routines for resource operations
  101. //
  102. ////////////////////////////////////////////////////////
  103. DWORD
  104. FmpValCreateResource(
  105. IN PFM_GROUP Group,
  106. IN LPWSTR ResourceId,
  107. IN LPCWSTR ResourceName,
  108. OUT PGUM_CREATE_RESOURCE *ppGumResource,
  109. OUT PDWORD pdwBufSize
  110. )
  111. /*++
  112. Routine Description:
  113. Validation routine for resource creation.
  114. Arguments:
  115. Group - Supplies the group in which this resource belongs.
  116. ResourceId - Supplies the Id of the resource to create.
  117. ResourceName - Supplies the 'user-friendly' name of the resource.
  118. ppGumResource - Message buffer to hold resource info.
  119. pdwBufSize - Message buffer size.
  120. Returns:
  121. ERROR_SUCCESS if the validation is successful.
  122. A Win32 error code if the validation fails.
  123. --*/
  124. {
  125. DWORD dwStatus = ERROR_SUCCESS;
  126. PFM_RESOURCE Resource;
  127. LPCWSTR GroupId;
  128. PGUM_CREATE_RESOURCE GumResource;
  129. DWORD GroupIdLen;
  130. DWORD ResourceIdLen;
  131. DWORD ResourceNameLen;
  132. DWORD BufSize;
  133. HDMKEY ResourceKey;
  134. HDMKEY ParamsKey;
  135. DWORD Disposition;
  136. *ppGumResource = NULL;
  137. *pdwBufSize = 0;
  138. //
  139. // First create the parameters field.
  140. //
  141. ResourceKey = DmOpenKey( DmResourcesKey,
  142. ResourceId,
  143. MAXIMUM_ALLOWED );
  144. if ( ResourceKey == NULL )
  145. {
  146. ClRtlLogPrint(LOG_NOISE,
  147. "[FM] CreateResource: Failed to open registry key for %1!ws!, status = %2!u!.\n",
  148. ResourceId,
  149. GetLastError() );
  150. dwStatus = GetLastError();
  151. goto FnExit;
  152. }
  153. ParamsKey = DmCreateKey( ResourceKey,
  154. CLUSREG_KEYNAME_PARAMETERS,
  155. 0,
  156. KEY_READ | KEY_WRITE,
  157. NULL,
  158. &Disposition );
  159. if ( ParamsKey != NULL )
  160. {
  161. DmCloseKey( ParamsKey );
  162. }
  163. DmCloseKey( ResourceKey );
  164. //
  165. // Allocate a message buffer.
  166. //
  167. GroupId = OmObjectId(Group);
  168. GroupIdLen = (lstrlenW(GroupId)+1) * sizeof(WCHAR);
  169. ResourceIdLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR);
  170. ResourceNameLen = (lstrlenW(ResourceName)+1) * sizeof(WCHAR);
  171. BufSize = sizeof(GUM_CREATE_RESOURCE) - sizeof(WCHAR) +
  172. GroupIdLen + ResourceIdLen + ResourceNameLen;
  173. GumResource = LocalAlloc(LMEM_FIXED, BufSize);
  174. if (GumResource == NULL) {
  175. CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
  176. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  177. goto FnExit;
  178. }
  179. //
  180. // Fill in message buffer.
  181. //
  182. GumResource->Resource = NULL;
  183. GumResource->GroupIdLen = GroupIdLen;
  184. GumResource->ResourceIdLen = ResourceIdLen;
  185. CopyMemory(GumResource->GroupId, GroupId, GroupIdLen);
  186. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen,
  187. ResourceId,
  188. ResourceIdLen);
  189. CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen + ResourceIdLen,
  190. ResourceName,
  191. ResourceNameLen);
  192. *ppGumResource = GumResource;
  193. *pdwBufSize = BufSize;
  194. FnExit:
  195. return(dwStatus);
  196. } // FmpValCreateResource
  197. DWORD
  198. FmpValDeleteResource(
  199. IN PFM_RESOURCE pResource
  200. )
  201. /*++
  202. Routine Description:
  203. Validation routine for delete resource.
  204. Arguments:
  205. Resource - Supplies the resource to delete.
  206. Returns:
  207. ERROR_SUCCESS if the validation is successful.
  208. A Win32 error code if the validation fails.
  209. --*/
  210. {
  211. DWORD dwStatus = ERROR_SUCCESS;
  212. //
  213. // Check if this is the quorum resource.
  214. //
  215. if ( pResource->QuorumResource )
  216. {
  217. dwStatus = ERROR_QUORUM_RESOURCE;
  218. goto FnExit;
  219. }
  220. //other core resources cannot be deleted either
  221. if (pResource->ExFlags & CLUS_FLAG_CORE)
  222. {
  223. dwStatus = ERROR_CORE_RESOURCE;
  224. goto FnExit;
  225. }
  226. //
  227. // Check the state of the resource, before attempting to delete it.
  228. // It must be offline or failed in order to perform the delete.
  229. //
  230. if ((pResource->State != ClusterResourceOffline) &&
  231. (pResource->State != ClusterResourceFailed))
  232. {
  233. dwStatus = ERROR_RESOURCE_ONLINE;
  234. goto FnExit;
  235. }
  236. //
  237. // Check whether this resource provides for any other resources.
  238. // If so, it cannot be deleted.
  239. //
  240. if (!IsListEmpty(&pResource->ProvidesFor))
  241. {
  242. dwStatus = ERROR_DEPENDENT_RESOURCE_EXISTS;
  243. goto FnExit;
  244. }
  245. if (pResource->Group->MovingList)
  246. {
  247. dwStatus = ERROR_INVALID_STATE;
  248. goto FnExit;
  249. }
  250. FnExit:
  251. return(dwStatus);
  252. } // FmpValDeleteResource
  253. DWORD
  254. FmpValOnlineResource(
  255. IN PFM_RESOURCE pResource
  256. )
  257. /*++
  258. Routine Description:
  259. This routine validates if a resource can be brought online.
  260. Arguments:
  261. Resource - A pointer to the resource to bring online.
  262. Returns:
  263. ERROR_SUCCESS if the validation is successful.
  264. A Win32 error code if the validation fails.
  265. --*/
  266. {
  267. DWORD dwStatus = ERROR_SUCCESS;
  268. //if the resource has been marked for delete, then dont let
  269. //it be brought online
  270. if (!IS_VALID_FM_RESOURCE(pResource))
  271. {
  272. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  273. goto FnExit;
  274. }
  275. //
  276. // Check if the resource has been initialized. If not, attempt
  277. // to initialize the resource now.
  278. //
  279. if ( pResource->Monitor == NULL )
  280. {
  281. dwStatus = FmpInitializeResource( pResource, TRUE );
  282. }
  283. FnExit:
  284. return(dwStatus);
  285. } // FmpValOnlineResource
  286. DWORD
  287. FmpValOfflineResource(
  288. IN PFM_RESOURCE pResource
  289. )
  290. /*++
  291. Routine Description:
  292. This routine validates if a given resource can be taken offline.
  293. Arguments:
  294. Resource - A pointer to the resource to take offline.
  295. Returns:
  296. ERROR_SUCCESS if the validation is successful.
  297. A Win32 error code if the validation fails.
  298. --*/
  299. {
  300. DWORD dwStatus = ERROR_SUCCESS;
  301. //if the resource has been marked for delete, then fail this call
  302. if (!IS_VALID_FM_RESOURCE(pResource))
  303. {
  304. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  305. goto FnExit;
  306. }
  307. //
  308. // Check if this is the quorum resource.
  309. //
  310. if ( pResource->QuorumResource )
  311. {
  312. dwStatus = ERROR_QUORUM_RESOURCE;
  313. goto FnExit;
  314. }
  315. //
  316. // Check if the resource has been initialized. If not, return
  317. // success because the resource is not online.
  318. //
  319. if ( pResource->Monitor == NULL )
  320. {
  321. dwStatus = ERROR_SUCCESS;
  322. goto FnExit;
  323. }
  324. //
  325. // Chittur Subbaraman (chitturs) - 4/8/99
  326. //
  327. // Don't attempt to do anything if the resource has failed. You could
  328. // get into some funny cases in which the resource switches between
  329. // offline pending and failed states for ever.
  330. //
  331. if ( pResource->State == ClusterResourceFailed )
  332. {
  333. dwStatus = ERROR_INVALID_STATE;
  334. goto FnExit;
  335. }
  336. FnExit:
  337. return(dwStatus);
  338. } // FmpValOfflineResource
  339. DWORD
  340. FmpValAddResourceDependency(
  341. IN PFM_RESOURCE pResource,
  342. IN PFM_RESOURCE pDependentResource
  343. )
  344. /*++
  345. Routine Description:
  346. Validation routine for dependency addition.
  347. Arguments:
  348. Resource - The resource to add the dependent resource.
  349. DependentResource - The dependent resource.
  350. Returns:
  351. ERROR_SUCCESS if the validation is successful.
  352. A Win32 error code if the validation fails.
  353. --*/
  354. {
  355. DWORD dwStatus = ERROR_SUCCESS;
  356. //if the resource has been marked for delete, then dont let
  357. //it be brought online
  358. if (!IS_VALID_FM_RESOURCE(pResource))
  359. {
  360. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  361. goto FnExit;
  362. }
  363. if (pResource->QuorumResource)
  364. {
  365. dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED;
  366. goto FnExit;
  367. }
  368. //
  369. // If the resources are not in the same group, fail the
  370. // call. Also fail if some one tries to make a resource
  371. // dependent upon itself.
  372. //
  373. if ((pResource->Group != pDependentResource->Group) ||
  374. (pResource == pDependentResource))
  375. {
  376. dwStatus = ERROR_INVALID_PARAMETER;
  377. goto FnExit;
  378. }
  379. // The resource to which the dependency is being added must be offline
  380. // Otherwise, it looks like the dependency is in effect when the depending
  381. // resource was not really brought online at the time the dependency existed
  382. // must also be offline or failed.
  383. // SS: For instance if a network name is dependent on two ip addresesses and
  384. // is online and a third ip address resource dependency is added, the
  385. // network name must be brought offline and online for the dependency
  386. // to be truly in effect
  387. //
  388. if ((pResource->State != ClusterResourceOffline) &&
  389. (pResource->State != ClusterResourceFailed))
  390. {
  391. dwStatus = ERROR_RESOURCE_ONLINE;
  392. goto FnExit;
  393. }
  394. //
  395. // Make sure that we don't have any circular dependencies!
  396. //
  397. if ( FmDependentResource( pDependentResource, pResource, FALSE ) )
  398. {
  399. dwStatus = ERROR_CIRCULAR_DEPENDENCY;
  400. goto FnExit;
  401. }
  402. //
  403. // Make sure that this dependency does not already exist!
  404. //
  405. if ( FmDependentResource(pResource, pDependentResource, TRUE))
  406. {
  407. dwStatus = ERROR_DEPENDENCY_ALREADY_EXISTS;
  408. goto FnExit;
  409. }
  410. FnExit:
  411. return(dwStatus);
  412. } // FmpValAddResourceDependency
  413. DWORD
  414. FmpValChangeResourceNode(
  415. IN PFM_RESOURCE pResource,
  416. IN LPCWSTR pszNodeId,
  417. IN BOOL bAdd,
  418. OUT PGUM_CHANGE_POSSIBLE_NODE *ppGumChange,
  419. OUT PDWORD pdwBufSize
  420. )
  421. /*++
  422. Routine Description:
  423. Validation routine for changing the possible owner node of a resource.
  424. Arguments:
  425. pResource - A pointer to the resource structure.
  426. pszNodeId - A pointer to the node id
  427. bAdd - Indicates add or remove
  428. ppGumChange - Message buffer to hold the resource info
  429. pdwBufSize - Size of the message buffer
  430. Comments:
  431. Lock must be held when this routine is called
  432. Returns:
  433. ERROR_SUCCESS if the validation is successful.
  434. A Win32 error code if the validation fails.
  435. --*/
  436. {
  437. DWORD dwStatus = ERROR_SUCCESS;
  438. PLIST_ENTRY pListEntry;
  439. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry = NULL;
  440. BOOL bNodeSupportsResType = FALSE;
  441. LPCWSTR pszResourceId;
  442. DWORD dwResourceLen;
  443. DWORD dwNodeLen;
  444. DWORD dwBufSize;
  445. PGUM_CHANGE_POSSIBLE_NODE pGumChange;
  446. *ppGumChange = NULL;
  447. *pdwBufSize = 0;
  448. //if the resource has been marked for delete, then perform
  449. //any operations on it
  450. if (!IS_VALID_FM_RESOURCE(pResource))
  451. {
  452. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  453. goto FnExit;
  454. }
  455. if ( pResource->QuorumResource )
  456. {
  457. dwStatus = ERROR_INVALID_OPERATION_ON_QUORUM;
  458. goto FnExit;
  459. }
  460. //
  461. // We can't allow the owner node to be removed if the state
  462. // of the resource or the group is not offline or failed.
  463. //
  464. if ( !bAdd &&
  465. (pszNodeId == OmObjectId(NmLocalNode)) &&
  466. (((pResource->State != ClusterResourceOffline) &&
  467. (pResource->State != ClusterResourceFailed)) ||
  468. (FmpGetGroupState( pResource->Group, TRUE ) != ClusterGroupOffline)) )
  469. {
  470. dwStatus = ERROR_INVALID_STATE;
  471. goto FnExit;
  472. }
  473. //make sure the node is on the list of possible nodes for this
  474. // resource type
  475. if (bAdd)
  476. {
  477. pListEntry = &(pResource->Type->PossibleNodeList);
  478. for (pListEntry = pListEntry->Flink;
  479. pListEntry != &(pResource->Type->PossibleNodeList);
  480. pListEntry = pListEntry->Flink)
  481. {
  482. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  483. PossibleLinkage);
  484. if (!lstrcmpW(OmObjectId(pResTypePosEntry->PossibleNode), pszNodeId))
  485. {
  486. bNodeSupportsResType = TRUE;
  487. break;
  488. }
  489. }
  490. if (!bNodeSupportsResType)
  491. {
  492. dwStatus = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
  493. goto FnExit;
  494. }
  495. }
  496. pszResourceId = OmObjectId(pResource);
  497. dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
  498. dwNodeLen = (lstrlenW(pszNodeId)+1)*sizeof(WCHAR);
  499. dwBufSize = sizeof(GUM_CHANGE_POSSIBLE_NODE) - sizeof(WCHAR) +
  500. dwResourceLen + dwNodeLen;
  501. pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize);
  502. if (pGumChange == NULL) {
  503. CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
  504. return(ERROR_NOT_ENOUGH_MEMORY);
  505. }
  506. pGumChange->ResourceIdLen = dwResourceLen;
  507. CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen);
  508. CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen,
  509. pszNodeId,
  510. dwNodeLen);
  511. *ppGumChange = pGumChange;
  512. *pdwBufSize = dwBufSize;
  513. FnExit:
  514. return(dwStatus);
  515. } // FmpValChangeResourceNode
  516. DWORD
  517. FmpValChangeResourceGroup(
  518. IN PFM_RESOURCE pResource,
  519. IN PFM_GROUP pNewGroup,
  520. OUT PGUM_CHANGE_GROUP *ppGumChange,
  521. OUT LPDWORD pdwBufSize)
  522. /*++
  523. Routine Description:
  524. Validation routine for changing a resource's group.
  525. Arguments:
  526. pResource - Pointer to the resource structure
  527. pNewGroup - Pointer to the group to which the resource is moved to
  528. ppGumChange - Message buffer to hold the resource info
  529. pdwBufSize - Size of the message buffer
  530. Comments:
  531. Lock must be held when this routine is called
  532. Returns:
  533. ERROR_SUCCESS if validation is successful.
  534. A Win32 error code otherwise.
  535. --*/
  536. {
  537. DWORD dwBufSize;
  538. LPCWSTR pszResourceId;
  539. DWORD dwResourceLen;
  540. LPCWSTR pszGroupId;
  541. DWORD dwGroupLen;
  542. DWORD dwStatus = ERROR_SUCCESS;
  543. PGUM_CHANGE_GROUP pGumChange;
  544. *pdwBufSize = 0;
  545. *ppGumChange = NULL;
  546. // we need to validate here as well
  547. // this is called by the server side
  548. // this will help avoid a gum call if things have changed
  549. // since the request started from the originator
  550. // and got to the server
  551. //if the resource has been marked for delete, then fail this call
  552. if (!IS_VALID_FM_RESOURCE(pResource))
  553. {
  554. dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
  555. goto FnExit;
  556. }
  557. //
  558. // Check if we're moving to same group.
  559. //
  560. if (pResource->Group == pNewGroup)
  561. {
  562. dwStatus = ERROR_ALREADY_EXISTS;
  563. goto FnExit;
  564. }
  565. //
  566. // For now... both Groups must be owned by the same node.
  567. //
  568. if ( pResource->Group->OwnerNode != pNewGroup->OwnerNode )
  569. {
  570. dwStatus = ERROR_HOST_NODE_NOT_GROUP_OWNER;
  571. goto FnExit;
  572. }
  573. pszResourceId = OmObjectId(pResource);
  574. dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
  575. pszGroupId = OmObjectId(pNewGroup);
  576. dwGroupLen = (lstrlenW(pszGroupId)+1)*sizeof(WCHAR);
  577. dwBufSize = sizeof(GUM_CHANGE_GROUP) - sizeof(WCHAR) + dwResourceLen + dwGroupLen;
  578. pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize);
  579. if (pGumChange == NULL) {
  580. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  581. goto FnExit;
  582. }
  583. pGumChange->ResourceIdLen = dwResourceLen;
  584. CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen);
  585. CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen,
  586. pszGroupId,
  587. dwGroupLen);
  588. *ppGumChange = pGumChange;
  589. *pdwBufSize = dwBufSize;
  590. FnExit:
  591. return(dwStatus);
  592. } // FmpValChangeResourceGroup