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.

1324 lines
40 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. Resource and Resource Type control functions.
  7. Author:
  8. John Vert (jvert) 10/16/1996
  9. Revision History:
  10. --*/
  11. #include "fmp.h"
  12. #define LOG_MODULE IOCTL
  13. DWORD
  14. WINAPI
  15. FmResourceControl(
  16. IN PFM_RESOURCE Resource,
  17. IN PNM_NODE Node OPTIONAL,
  18. IN DWORD ControlCode,
  19. IN PUCHAR InBuffer,
  20. IN DWORD InBufferSize,
  21. OUT PUCHAR OutBuffer,
  22. IN DWORD OutBufferSize,
  23. OUT LPDWORD BytesReturned,
  24. OUT LPDWORD Required
  25. )
  26. /*++
  27. Routine Description:
  28. Provides for arbitrary communication and control between an application
  29. and a specific instance of a resource.
  30. Arguments:
  31. Resource - Supplies the resource to be controlled.
  32. Node - Supplies the node on which the resource control should
  33. be delivered. If this is NULL, then if the owner is up, it
  34. is used. Else one of the other possible nodes is used.
  35. Else, one of the nodes that can support a resource of this type is used.
  36. ControlCode- Supplies the control code that defines the
  37. structure and action of the resource control.
  38. Values of ControlCode between 0 and 0x10000000 are reserved
  39. for future definition and use by Microsoft. All other values
  40. are available for use by ISVs
  41. InBuffer- Supplies a pointer to the input buffer to be passed
  42. to the resource.
  43. InBufferSize- Supplies the size, in bytes, of the data pointed
  44. to by lpInBuffer..
  45. OutBuffer- Supplies a pointer to the output buffer to be
  46. filled in by the resource..
  47. OutBufferSize- Supplies the size, in bytes, of the available
  48. space pointed to by lpOutBuffer.
  49. BytesReturned - Returns the number of bytes of lpOutBuffer
  50. actually filled in by the resource..
  51. Required - Returns the number of bytes if the OutBuffer is not big
  52. enough.
  53. Return Value:
  54. ERROR_SUCCESS if successful
  55. Win32 error code otherwise
  56. --*/
  57. {
  58. DWORD status;
  59. PNM_NODE node;
  60. PLIST_ENTRY pListEntry;
  61. //SS: dont require FM to be online, since these calls
  62. //can be made by the Open() call in resource dlls which
  63. //is called before the resource is online.
  64. //FmpMustBeOnline( );
  65. //
  66. // TODO - we should verify the access mode - in the future!
  67. //
  68. if ( CLUSCTL_GET_CONTROL_OBJECT( ControlCode ) != CLUS_OBJECT_RESOURCE ) {
  69. return(ERROR_INVALID_FUNCTION);
  70. }
  71. //
  72. // Check if this is an internal, private control code.
  73. //
  74. if ( ControlCode & CLCTL_INTERNAL_MASK ) {
  75. return(ERROR_PRIVILEGE_NOT_HELD);
  76. }
  77. //
  78. // If a Node was specified, then ship the request off to that node.
  79. //
  80. if ( Node != NULL ) {
  81. if ( Node == NmLocalNode ) {
  82. status = FmpRmResourceControl( Resource,
  83. ControlCode,
  84. InBuffer,
  85. InBufferSize,
  86. OutBuffer,
  87. OutBufferSize,
  88. BytesReturned,
  89. Required
  90. );
  91. } else {
  92. status = FmcResourceControl( Node,
  93. Resource,
  94. ControlCode,
  95. InBuffer,
  96. InBufferSize,
  97. OutBuffer,
  98. OutBufferSize,
  99. BytesReturned,
  100. Required
  101. );
  102. }
  103. } else {
  104. PLIST_ENTRY pListEntry;
  105. PPOSSIBLE_ENTRY pPossibleEntry;
  106. pListEntry = &Resource->PossibleOwners;
  107. node = Node;
  108. //
  109. // If there is no supplied node, then use a possible node that is up.
  110. //
  111. for (pListEntry = pListEntry->Flink; pListEntry != &Resource->PossibleOwners;
  112. pListEntry = pListEntry->Flink)
  113. {
  114. pPossibleEntry = CONTAINING_RECORD(pListEntry, POSSIBLE_ENTRY,
  115. PossibleLinkage);
  116. // if Node is not given, then attempt to use a node that is
  117. // UP - giving preference to the group owner node node.
  118. node = pPossibleEntry->PossibleNode;
  119. if ( node == Resource->Group->OwnerNode ) {
  120. break;
  121. }
  122. if ( NmGetNodeState(node) != ClusterNodeUp ) {
  123. node = NULL;
  124. // try again
  125. }
  126. }
  127. //if no such node was found, find a node that can host this resource type
  128. if (!node)
  129. {
  130. PFM_RESTYPE pResType;
  131. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry;
  132. PNM_NODE prev_node = NULL;
  133. pResType = Resource->Type;
  134. // protect with the ResType lock
  135. ACQUIRE_SHARED_LOCK(gResTypeLock);
  136. pListEntry = &pResType->PossibleNodeList;
  137. //
  138. // If there is no supplied node, then use a possible node that is up.
  139. //
  140. for (pListEntry = pListEntry->Flink; pListEntry != &pResType->PossibleNodeList;
  141. pListEntry = pListEntry->Flink)
  142. {
  143. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  144. PossibleLinkage);
  145. // if Node is not given, then attempt to use a node that is
  146. // UP - giving preference to the local node.
  147. node = pResTypePosEntry->PossibleNode;
  148. if ( node == NmLocalNode ) {
  149. break;
  150. }
  151. if ( NmGetNodeState(node) != ClusterNodeUp ) {
  152. node = NULL;
  153. // try again
  154. }
  155. else
  156. if (prev_node == NULL)
  157. prev_node = node;
  158. }
  159. RELEASE_LOCK(gResTypeLock);
  160. if(!node && prev_node)
  161. node=prev_node;
  162. }
  163. //if we still dont have a node, we have to throw up a failure
  164. if ( !node ) {
  165. // either the restype is not supported - or the supporting node is
  166. // not up!
  167. status = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
  168. return(status);
  169. }
  170. //
  171. // If we are the owner, then do the work, otherwise...
  172. // Ship the request off to the owner node.
  173. //
  174. if ( node == NmLocalNode ) {
  175. status = FmpRmResourceControl( Resource,
  176. ControlCode,
  177. InBuffer,
  178. InBufferSize,
  179. OutBuffer,
  180. OutBufferSize,
  181. BytesReturned,
  182. Required
  183. );
  184. } else {
  185. status = FmcResourceControl( node,
  186. Resource,
  187. ControlCode,
  188. InBuffer,
  189. InBufferSize,
  190. OutBuffer,
  191. OutBufferSize,
  192. BytesReturned,
  193. Required
  194. );
  195. }
  196. }
  197. return(status);
  198. } // FmResourceControl
  199. DWORD
  200. WINAPI
  201. FmResourceTypeControl(
  202. IN LPCWSTR ResourceTypeName,
  203. IN PNM_NODE Node OPTIONAL,
  204. IN DWORD ControlCode,
  205. IN PUCHAR InBuffer,
  206. IN DWORD InBufferSize,
  207. OUT PUCHAR OutBuffer,
  208. IN DWORD OutBufferSize,
  209. OUT LPDWORD BytesReturned,
  210. OUT LPDWORD Required
  211. )
  212. /*++
  213. Routine Description:
  214. Provides for arbitrary communication and control between an application
  215. and a specific instance of a resource type.
  216. Arguments:
  217. ResourceTypeName - Supplies the name of the resource type to be
  218. controlled.
  219. Node - Supplies the node on which the resource control should be
  220. delivered. If this is NULL, the local node is used.
  221. ControlCode- Supplies the control code that defines the
  222. structure and action of the resource type control.
  223. Values of dwControlCode between 0 and 0x10000000 are reserved
  224. for future definition and use by Microsoft. All other values
  225. are available for use by ISVs
  226. InBuffer- Supplies a pointer to the input buffer to be passed
  227. to the resource.
  228. InBufferSize- Supplies the size, in bytes, of the data pointed
  229. to by lpInBuffer..
  230. OutBuffer- Supplies a pointer to the output buffer to be
  231. filled in by the resource..
  232. OutBufferSize- Supplies the size, in bytes, of the available
  233. space pointed to by lpOutBuffer.
  234. BytesReturned - Returns the number of bytes of lpOutBuffer
  235. actually filled in by the resource..
  236. Required - Returns the number of bytes if the OutBuffer is not big
  237. enough.
  238. Return Value:
  239. ERROR_SUCCESS if successful
  240. Win32 error code otherwise
  241. --*/
  242. {
  243. DWORD status;
  244. DWORD retry = TRUE;
  245. PNM_NODE node = NULL;
  246. PNM_NODE prev_node=NULL;
  247. PFM_RESTYPE pResType = NULL;
  248. FmpMustBeOnline( );
  249. //
  250. // TODO - we should verify the access mode - in the future!
  251. //
  252. if ( CLUSCTL_GET_CONTROL_OBJECT( ControlCode ) != CLUS_OBJECT_RESOURCE_TYPE ) {
  253. status = ERROR_INVALID_FUNCTION;
  254. goto FnExit;
  255. }
  256. //
  257. // Check if this is an internal, private control code.
  258. //
  259. if ( ControlCode & CLCTL_INTERNAL_MASK ) {
  260. status = ERROR_PRIVILEGE_NOT_HELD;
  261. goto FnExit;
  262. }
  263. //find a node that can handle this resource type control
  264. pResType = OmReferenceObjectById(ObjectTypeResType,
  265. ResourceTypeName);
  266. if (!pResType)
  267. {
  268. status = ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND;
  269. goto FnExit;
  270. }
  271. retry_search:
  272. prev_node = NULL;
  273. //if node wasnt specified choose a node
  274. if ( !Node )
  275. {
  276. PLIST_ENTRY pListEntry;
  277. PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry;
  278. // protect with the ResType lock
  279. ACQUIRE_SHARED_LOCK(gResTypeLock);
  280. pListEntry = &pResType->PossibleNodeList;
  281. //
  282. // If there is no supplied node, then use a possible node that is up.
  283. //
  284. for (pListEntry = pListEntry->Flink; pListEntry != &pResType->PossibleNodeList;
  285. pListEntry = pListEntry->Flink)
  286. {
  287. pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
  288. PossibleLinkage);
  289. // if Node is not given, then attempt to use a node that is
  290. // UP - giving preference to the local node.
  291. node = pResTypePosEntry->PossibleNode;
  292. if ( node == NmLocalNode ) {
  293. break;
  294. }
  295. if ( NmGetNodeState(node) != ClusterNodeUp ) {
  296. node = NULL;
  297. // try again
  298. }
  299. else
  300. if (prev_node == NULL)
  301. prev_node = node;
  302. }
  303. RELEASE_LOCK(gResTypeLock);
  304. if(!node && prev_node)
  305. node=prev_node;
  306. // node should now contain a valid node to use or NULL!
  307. // if NULL, then let's see if the required ResDLL has been updated
  308. // on some other nodes.
  309. if ( !node &&
  310. retry ) {
  311. retry = FALSE;
  312. ClRtlLogPrint(LOG_NOISE,
  313. "[FM] FmResourceTypeControl: No possible nodes for restype %1!ws!, "
  314. "calling FmpSetPossibleNodeForRestype\r\n",
  315. ResourceTypeName);
  316. FmpSetPossibleNodeForResType( ResourceTypeName, TRUE );
  317. // ignore status
  318. goto retry_search;
  319. }
  320. // node should now contain a valid node to use or NULL!
  321. // if NULL, then it is hopeless!
  322. if ( !node ) {
  323. // either the restype is not supported - or the supporting node is
  324. // not up!
  325. status = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
  326. goto FnExit;
  327. }
  328. }
  329. else
  330. {
  331. // If the supplied node is on the list of possible nodes, then use it.
  332. // else return error
  333. if (!FmpInPossibleListForResType(pResType, Node))
  334. {
  335. // either the restype is not supported - or the supporting node is
  336. // not up!
  337. status = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
  338. goto FnExit;
  339. }
  340. node = Node;
  341. }
  342. CL_ASSERT(node != NULL);
  343. if ( (node != NmLocalNode) &&
  344. (NmGetNodeState(node) != ClusterNodeUp) ) {
  345. status = ERROR_HOST_NODE_NOT_AVAILABLE;
  346. goto FnExit;
  347. }
  348. //
  349. // If the node is remote, then ship the request off to that node, else
  350. // do the work locally.
  351. //
  352. if ( node == NmLocalNode )
  353. {
  354. status = FmpRmResourceTypeControl( ResourceTypeName,
  355. ControlCode,
  356. InBuffer,
  357. InBufferSize,
  358. OutBuffer,
  359. OutBufferSize,
  360. BytesReturned,
  361. Required
  362. );
  363. //if no node was specified and the local node doesnt support the resource
  364. //dll, remove it from the list and then retry
  365. if ((Node == NULL) &&
  366. ((status == ERROR_MOD_NOT_FOUND) || (status == ERROR_PROC_NOT_FOUND)))
  367. {
  368. ClRtlLogPrint(LOG_NOISE,
  369. "[FM] FmResourceTypeControl: Removing Local Node from Possible Owners List for %1!ws! restype because of error %2!u! \r\n",
  370. ResourceTypeName,status);
  371. FmpRemovePossibleNodeForResType(ResourceTypeName, NmLocalNode);
  372. node = NULL;
  373. retry = FALSE;
  374. goto retry_search;
  375. }
  376. }
  377. else
  378. {
  379. status = FmcResourceTypeControl( node,
  380. ResourceTypeName,
  381. ControlCode,
  382. InBuffer,
  383. InBufferSize,
  384. OutBuffer,
  385. OutBufferSize,
  386. BytesReturned,
  387. Required
  388. );
  389. if ((Node == NULL) &&
  390. ((status == ERROR_MOD_NOT_FOUND) || (status == ERROR_PROC_NOT_FOUND)))
  391. {
  392. node = NULL;
  393. retry = FALSE;
  394. goto retry_search;
  395. }
  396. }
  397. FnExit:
  398. if (pResType)
  399. OmDereferenceObject(pResType);
  400. return(status);
  401. } // FmResourceTypeControl
  402. DWORD
  403. WINAPI
  404. FmGroupControl(
  405. IN PFM_GROUP Group,
  406. IN PNM_NODE Node OPTIONAL,
  407. IN DWORD ControlCode,
  408. IN PUCHAR InBuffer,
  409. IN DWORD InBufferSize,
  410. OUT PUCHAR OutBuffer,
  411. IN DWORD OutBufferSize,
  412. OUT LPDWORD BytesReturned,
  413. OUT LPDWORD Required
  414. )
  415. /*++
  416. Routine Description:
  417. Provides for arbitrary communication and control between an application
  418. and a specific instance of a group.
  419. Arguments:
  420. Group - Supplies the group to be controlled.
  421. Node - Supplies the node on which the resource control should
  422. be delivered. If this is NULL, the node where the group
  423. is owned is used.
  424. ControlCode- Supplies the control code that defines the
  425. structure and action of the group control.
  426. Values of ControlCode between 0 and 0x10000000 are reserved
  427. for future definition and use by Microsoft. All other values
  428. are available for use by ISVs
  429. InBuffer- Supplies a pointer to the input buffer to be passed
  430. to the group.
  431. InBufferSize- Supplies the size, in bytes, of the data pointed
  432. to by lpInBuffer.
  433. OutBuffer- Supplies a pointer to the output buffer to be
  434. filled in by the group.
  435. OutBufferSize- Supplies the size, in bytes, of the available
  436. space pointed to by lpOutBuffer.
  437. BytesReturned - Returns the number of bytes of lpOutBuffer
  438. actually filled in by the group.
  439. Required - Returns the number of bytes if the OutBuffer is not big
  440. enough.
  441. Return Value:
  442. ERROR_SUCCESS if successful
  443. Win32 error code otherwise
  444. --*/
  445. {
  446. DWORD status;
  447. FmpMustBeOnline( );
  448. //
  449. // TODO - we should verify the access mode - in the future!
  450. //
  451. if ( CLUSCTL_GET_CONTROL_OBJECT( ControlCode ) != CLUS_OBJECT_GROUP ) {
  452. return(ERROR_INVALID_FUNCTION);
  453. }
  454. //
  455. // Check if this is an internal, private control code.
  456. //
  457. if ( ControlCode & CLCTL_INTERNAL_MASK ) {
  458. return(ERROR_PRIVILEGE_NOT_HELD);
  459. }
  460. //
  461. // If a Node was specified, then ship the request off to that node, else
  462. //
  463. // If we are the owner, then do the work, otherwise...
  464. // Ship the request off to the owner node.
  465. //
  466. if ( (Node != NULL) && (Node != NmLocalNode) )
  467. {
  468. status = FmcGroupControl( Node,
  469. Group,
  470. ControlCode,
  471. InBuffer,
  472. InBufferSize,
  473. OutBuffer,
  474. OutBufferSize,
  475. BytesReturned,
  476. Required
  477. );
  478. }
  479. else
  480. {
  481. CL_ASSERT( Group != NULL );
  482. if ( (Node == NULL) &&
  483. (Group->OwnerNode != NmLocalNode) )
  484. {
  485. status = FmcGroupControl( Group->OwnerNode,
  486. Group,
  487. ControlCode,
  488. InBuffer,
  489. InBufferSize,
  490. OutBuffer,
  491. OutBufferSize,
  492. BytesReturned,
  493. Required
  494. );
  495. }
  496. else
  497. {
  498. status = FmpGroupControl( Group, ControlCode, InBuffer,
  499. InBufferSize, OutBuffer, OutBufferSize, BytesReturned, Required);
  500. }
  501. }
  502. return(status);
  503. } // FmGroupControl
  504. DWORD
  505. FmpGroupControl(
  506. IN PFM_GROUP Group,
  507. IN DWORD ControlCode,
  508. IN PUCHAR InBuffer,
  509. IN DWORD InBufferSize,
  510. OUT PUCHAR OutBuffer,
  511. IN DWORD OutBufferSize,
  512. OUT LPDWORD BytesReturned,
  513. OUT LPDWORD Required
  514. )
  515. {
  516. CLUSPROP_BUFFER_HELPER props;
  517. DWORD bufSize;
  518. DWORD status;
  519. //
  520. // Handle any requests that must be done without locks helds.
  521. //
  522. switch ( ControlCode ) {
  523. case CLUSCTL_GROUP_GET_COMMON_PROPERTY_FMTS:
  524. status = ClRtlGetPropertyFormats( FmpGroupCommonProperties,
  525. OutBuffer,
  526. OutBufferSize,
  527. BytesReturned,
  528. Required );
  529. break;
  530. case CLUSCTL_GROUP_GET_NAME:
  531. if ( OmObjectName( Group ) == NULL ) {
  532. return(ERROR_NOT_READY);
  533. }
  534. props.pb = OutBuffer;
  535. bufSize = (lstrlenW( OmObjectName( Group ) ) + 1) * sizeof(WCHAR);
  536. if ( bufSize > OutBufferSize ) {
  537. *Required = bufSize;
  538. *BytesReturned = 0;
  539. status = ERROR_MORE_DATA;
  540. } else {
  541. lstrcpyW( props.psz, OmObjectName( Group ) );
  542. *BytesReturned = bufSize;
  543. *Required = 0;
  544. status = ERROR_SUCCESS;
  545. }
  546. return(status);
  547. case CLUSCTL_GROUP_GET_ID:
  548. if ( OmObjectId( Group ) == NULL ) {
  549. return(ERROR_NOT_READY);
  550. }
  551. props.pb = OutBuffer;
  552. bufSize = (lstrlenW( OmObjectId( Group ) ) + 1) * sizeof(WCHAR);
  553. if ( bufSize > OutBufferSize ) {
  554. *Required = bufSize;
  555. *BytesReturned = 0;
  556. status = ERROR_MORE_DATA;
  557. } else {
  558. lstrcpyW( props.psz, OmObjectId( Group ) );
  559. *BytesReturned = bufSize;
  560. *Required = 0;
  561. status = ERROR_SUCCESS;
  562. }
  563. return(status);
  564. default:
  565. break;
  566. }
  567. FmpAcquireLocalGroupLock( Group );
  568. status = FmpHandleGroupControl( Group,
  569. ControlCode,
  570. InBuffer,
  571. InBufferSize,
  572. OutBuffer,
  573. OutBufferSize,
  574. BytesReturned,
  575. Required
  576. );
  577. FmpReleaseLocalGroupLock( Group );
  578. if ( ((status == ERROR_SUCCESS) ||
  579. (status == ERROR_RESOURCE_PROPERTIES_STORED)) &&
  580. (ControlCode & CLCTL_MODIFY_MASK) ) {
  581. ClusterWideEvent(
  582. CLUSTER_EVENT_GROUP_PROPERTY_CHANGE,
  583. Group
  584. );
  585. }
  586. return(status);
  587. }
  588. DWORD
  589. WINAPI
  590. FmpHandleGroupControl(
  591. IN PFM_GROUP Group,
  592. IN DWORD ControlCode,
  593. IN PUCHAR InBuffer,
  594. IN DWORD InBufferSize,
  595. OUT PUCHAR OutBuffer,
  596. IN DWORD OutBufferSize,
  597. OUT LPDWORD BytesReturned,
  598. OUT LPDWORD Required
  599. )
  600. /*++
  601. Routine Description:
  602. Provides for arbitrary communication and control between an application
  603. and a specific instance of a group.
  604. Arguments:
  605. Group - Supplies the group to be controlled.
  606. ControlCode- Supplies the control code that defines the
  607. structure and action of the group control.
  608. Values of ControlCode between 0 and 0x10000000 are reserved
  609. for future definition and use by Microsoft. All other values
  610. are available for use by ISVs
  611. InBuffer- Supplies a pointer to the input buffer to be passed
  612. to the group.
  613. InBufferSize- Supplies the size, in bytes, of the data pointed
  614. to by lpInBuffer.
  615. OutBuffer- Supplies a pointer to the output buffer to be
  616. filled in by the group.
  617. OutBufferSize- Supplies the size, in bytes, of the available
  618. space pointed to by lpOutBuffer.
  619. BytesReturned - Returns the number of bytes of lpOutBuffer
  620. actually filled in by the group.
  621. Required - Returns the number of bytes if the OutBuffer is not big
  622. enough.
  623. Return Value:
  624. ERROR_SUCCESS if successful
  625. Win32 error code otherwise
  626. --*/
  627. {
  628. DWORD status;
  629. switch ( ControlCode ) {
  630. case CLUSCTL_GROUP_UNKNOWN:
  631. *BytesReturned = 0;
  632. status = ERROR_SUCCESS;
  633. break;
  634. case CLUSCTL_GROUP_GET_FLAGS:
  635. status = FmpGroupGetFlags( Group,
  636. OutBuffer,
  637. OutBufferSize,
  638. BytesReturned,
  639. Required );
  640. break;
  641. case CLUSCTL_GROUP_ENUM_COMMON_PROPERTIES:
  642. status = FmpGroupEnumCommonProperties( OutBuffer,
  643. OutBufferSize,
  644. BytesReturned,
  645. Required );
  646. break;
  647. case CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES:
  648. status = FmpGroupGetCommonProperties( Group,
  649. TRUE,
  650. OutBuffer,
  651. OutBufferSize,
  652. BytesReturned,
  653. Required );
  654. break;
  655. case CLUSCTL_GROUP_GET_COMMON_PROPERTIES:
  656. status = FmpGroupGetCommonProperties( Group,
  657. FALSE,
  658. OutBuffer,
  659. OutBufferSize,
  660. BytesReturned,
  661. Required );
  662. break;
  663. case CLUSCTL_GROUP_VALIDATE_COMMON_PROPERTIES:
  664. status = FmpGroupValidateCommonProperties( Group,
  665. InBuffer,
  666. InBufferSize );
  667. break;
  668. case CLUSCTL_GROUP_SET_COMMON_PROPERTIES:
  669. status = FmpGroupSetCommonProperties( Group,
  670. InBuffer,
  671. InBufferSize );
  672. break;
  673. case CLUSCTL_GROUP_GET_RO_PRIVATE_PROPERTIES:
  674. if ( OutBufferSize < sizeof(DWORD) ) {
  675. *BytesReturned = 0;
  676. *Required = sizeof(DWORD);
  677. if ( OutBuffer == NULL ) {
  678. status = ERROR_SUCCESS;
  679. } else {
  680. status = ERROR_MORE_DATA;
  681. }
  682. } else {
  683. LPDWORD ptrDword = (LPDWORD) OutBuffer;
  684. *ptrDword = 0;
  685. *BytesReturned = sizeof(DWORD);
  686. status = ERROR_SUCCESS;
  687. }
  688. break;
  689. case CLUSCTL_GROUP_ENUM_PRIVATE_PROPERTIES:
  690. status = FmpGroupEnumPrivateProperties( Group,
  691. OutBuffer,
  692. OutBufferSize,
  693. BytesReturned,
  694. Required );
  695. break;
  696. case CLUSCTL_GROUP_GET_PRIVATE_PROPERTIES:
  697. status = FmpGroupGetPrivateProperties( Group,
  698. OutBuffer,
  699. OutBufferSize,
  700. BytesReturned,
  701. Required );
  702. break;
  703. case CLUSCTL_GROUP_VALIDATE_PRIVATE_PROPERTIES:
  704. status = FmpGroupValidatePrivateProperties( Group,
  705. InBuffer,
  706. InBufferSize );
  707. break;
  708. case CLUSCTL_GROUP_SET_PRIVATE_PROPERTIES:
  709. status = FmpGroupSetPrivateProperties( Group,
  710. InBuffer,
  711. InBufferSize );
  712. break;
  713. case CLUSCTL_GROUP_GET_CHARACTERISTICS:
  714. if ( OutBufferSize < sizeof(DWORD) ) {
  715. *BytesReturned = 0;
  716. *Required = sizeof(DWORD);
  717. if ( OutBuffer == NULL ) {
  718. status = ERROR_SUCCESS;
  719. } else {
  720. status = ERROR_MORE_DATA;
  721. }
  722. } else {
  723. *BytesReturned = sizeof(DWORD);
  724. *(LPDWORD)OutBuffer = 0;
  725. status = ERROR_SUCCESS;
  726. }
  727. break;
  728. default:
  729. status = ERROR_INVALID_FUNCTION;
  730. break;
  731. }
  732. return(status);
  733. } // FmpHandleGroupControl
  734. /****
  735. @func DWORD | FmNetNameParseProperties| Updates the cluster name in
  736. the cluster database.
  737. @parm PUCHAR | InBuffer | A pointer to special property list.
  738. @parm DWORD | InBufferSize | The size of the InBuffer in bytes.
  739. @parm LPCWSTR | * ppszClusterName | A cluster name string is returned via this.
  740. @comm The string must be freed by the caller using LocalFree().
  741. @rdesc returns ERROR_SUCCESS if successful in getting the cluster name
  742. from the private properties.
  743. @xref
  744. ****/
  745. DWORD
  746. FmNetNameParseProperties(
  747. IN PUCHAR InBuffer,
  748. IN DWORD InBufferSize,
  749. OUT LPWSTR *ppszClusterName)
  750. {
  751. //
  752. // Find the Cluster Name property
  753. //
  754. *ppszClusterName = NULL;
  755. return (ClRtlpFindSzProperty(
  756. InBuffer,
  757. InBufferSize,
  758. CLUSREG_NAME_NET_NAME,
  759. ppszClusterName,
  760. TRUE
  761. ));
  762. } // FmNetNameParseProperties
  763. /****
  764. @func DWORD | FmGetDiskInfoParseProperties| Updates the cluster name in
  765. the cluster database.
  766. @parm PUCHAR | InBuffer | A pointer to special property list.
  767. @parm DWORD | InBufferSize | The size of the InBuffer in bytes.
  768. @parm LPWSTR | pszPath | If this a null string, the first drive letter
  769. on the disk resource is returned, else you can validate
  770. a path of form "g:" on this storage class resource.
  771. @comm The string must be freed by the caller using LocalFree().
  772. @rdesc returns ERROR_SUCCESS if successful in getting the cluster name
  773. from the private properties.
  774. @xref
  775. ****/
  776. DWORD FmpGetDiskInfoParseProperties(
  777. IN PUCHAR InBuffer,
  778. IN DWORD InBufferSize,
  779. IN OUT LPWSTR pszPath)
  780. {
  781. DWORD status = ERROR_INVALID_PARAMETER;
  782. DWORD dwValueSize;
  783. CLUSPROP_BUFFER_HELPER props;
  784. PCLUSPROP_PARTITION_INFO pPartitionInfo;
  785. WCHAR szRootPath[MAX_PATH];
  786. props.pb = InBuffer;
  787. szRootPath[0] = L'\0';
  788. //
  789. // Set defaults in the parameter block.
  790. //
  791. // Loop through each property.
  792. while ( (InBufferSize > sizeof(CLUSPROP_SYNTAX)) &&
  793. (props.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) )
  794. {
  795. // Get the size of this value and verify there is enough buffer left.
  796. dwValueSize = sizeof(*props.pValue) + ALIGN_CLUSPROP( props.pValue->cbLength );
  797. if ( dwValueSize > InBufferSize )
  798. {
  799. break;
  800. }
  801. if ( props.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO )
  802. {
  803. // Validate the data. There must be a device name.
  804. pPartitionInfo = props.pPartitionInfoValue;
  805. if ( (dwValueSize != sizeof(*pPartitionInfo)) ||
  806. (pPartitionInfo->szDeviceName[0] == L'\0'))
  807. {
  808. break;
  809. }
  810. if (!(pPartitionInfo->dwFlags & CLUSPROP_PIFLAG_USABLE))
  811. {
  812. //check that it is formatted with NTFS.
  813. //if it is not usable,skip to the next one
  814. goto SkipToNext;
  815. }
  816. if (pszPath[0] == L'\0')
  817. {
  818. //
  819. // Chittur Subbaraman (chitturs) - 12/12/2000
  820. //
  821. // Save the first available NTFS partition if the user does not explicitly
  822. // indicate any partition in the SetClusterQuorumResource API. This path will be
  823. // returned in two cases.
  824. //
  825. // (1) This cluster is a Whistler-Win2K cluster and the quorum disk
  826. // is currently owned by the Win2K node. The Win2K disk resource does not
  827. // set the CLUSPROP_PIFLAG_DEFAULT_QUORUM flags and so we have to revert the
  828. // behavior of the SetClusterQuorumResource API to the old behavior.
  829. //
  830. // (2) A pre-Whistler third party implemented quorum resource is used in a
  831. // Whistler cluster. In this case, this resource may not support the
  832. // CLUSPROP_PIFLAG_DEFAULT_QUORUM flags and so we have to revert the
  833. // behavior of the SetClusterQuorumResource API to the old behavior.
  834. //
  835. if ( szRootPath[0] == L'\0' )
  836. {
  837. lstrcpyW( szRootPath, pPartitionInfo->szDeviceName );
  838. }
  839. //
  840. // See whether you can find a default quorum partition (one that is
  841. // larger than 50 MB and still the minimum among the usable partitions.)
  842. //
  843. if ( !( pPartitionInfo->dwFlags & CLUSPROP_PIFLAG_DEFAULT_QUORUM ) )
  844. {
  845. goto SkipToNext;
  846. }
  847. // Construct a path from the device name.
  848. lstrcpyW( pszPath, pPartitionInfo->szDeviceName );
  849. status = ERROR_SUCCESS;
  850. break;
  851. }
  852. else
  853. {
  854. // Construct a path from the device name.
  855. if (!lstrcmpiW( pszPath, pPartitionInfo->szDeviceName ))
  856. {
  857. status = ERROR_SUCCESS;
  858. break;
  859. }
  860. }
  861. }
  862. SkipToNext:
  863. InBufferSize -= dwValueSize;
  864. props.pb += dwValueSize;
  865. }
  866. //
  867. // No path was found. However, a usable path got saved. So, use this saved path.
  868. //
  869. if ( ( status != ERROR_SUCCESS ) && ( szRootPath[0] != L'\0' ) )
  870. {
  871. lstrcpyW( pszPath, szRootPath );
  872. ClRtlLogPrint(LOG_NOISE, "[FM] FmpGetDiskInfoParseProperties: Using saved path %1!ws!...\n",
  873. pszPath);
  874. status = ERROR_SUCCESS;
  875. }
  876. return(status);
  877. } // FmpGetDiskInfoParseProperties
  878. DWORD
  879. FmpBroadcastDeleteControl(
  880. IN PFM_RESOURCE Resource
  881. )
  882. /*++
  883. Routine Description:
  884. Broadcasts a resource control to each node that notifies it that
  885. the resource is being deleted.
  886. Arguments:
  887. Resource - Supplies the resource that is being deleted.
  888. Return Value:
  889. ERROR_SUCCESS if successful.
  890. A Win32 error code on failure.
  891. --*/
  892. {
  893. DWORD status;
  894. DWORD characteristics;
  895. DWORD i;
  896. PNM_NODE Node;
  897. //
  898. // Only perform the broadcast if delete notification is required.
  899. // Otherwise, just perform the notification on the local node.
  900. //
  901. status = FmpRmResourceControl( Resource,
  902. CLUSCTL_RESOURCE_GET_CHARACTERISTICS,
  903. NULL,
  904. 0,
  905. (PUCHAR)&characteristics,
  906. sizeof(DWORD),
  907. NULL,
  908. NULL );
  909. if ( (status != ERROR_SUCCESS) ||
  910. !(characteristics & CLUS_CHAR_DELETE_REQUIRES_ALL_NODES) ) {
  911. //
  912. // Note: the following 'local node only' notification is fairly useless.
  913. //
  914. FmpRmResourceControl( Resource,
  915. CLUSCTL_RESOURCE_DELETE,
  916. NULL,
  917. 0,
  918. NULL,
  919. 0,
  920. NULL,
  921. NULL );
  922. return(ERROR_SUCCESS);
  923. }
  924. //
  925. // All nodes must be up in the cluster in order to perform this operation.
  926. //
  927. for ( i = ClusterMinNodeId; i <= NmMaxNodeId; i++ ) {
  928. Node = NmReferenceNodeById(i);
  929. if ( Node != NULL ) {
  930. if ( NmGetNodeState(Node) != ClusterNodeUp ) {
  931. return(ERROR_ALL_NODES_NOT_AVAILABLE);
  932. }
  933. }
  934. }
  935. //
  936. // Passed all checks, now broadcast to all nodes in the cluster.
  937. //
  938. for ( i = ClusterMinNodeId; i <= NmMaxNodeId; i++ ) {
  939. //
  940. // If this is the local node, do the ioctl directly
  941. //
  942. if (i == NmLocalNodeId) {
  943. FmpRmResourceControl( Resource,
  944. CLUSCTL_RESOURCE_DELETE,
  945. NULL,
  946. 0,
  947. NULL,
  948. 0,
  949. NULL,
  950. NULL );
  951. } else {
  952. Node = NmReferenceNodeById(i);
  953. if ((Node != NULL) &&
  954. (NmGetNodeState(Node) == ClusterNodeUp)) {
  955. CL_ASSERT(Session[i] != NULL);
  956. FmcResourceControl( Node,
  957. Resource,
  958. CLUSCTL_RESOURCE_DELETE,
  959. NULL,
  960. 0,
  961. NULL,
  962. 0,
  963. NULL,
  964. NULL );
  965. OmDereferenceObject(Node);
  966. }
  967. }
  968. }
  969. return(ERROR_SUCCESS);
  970. } // FmpBroadcastDeleteControl
  971. DWORD
  972. FmpBroadcastDependencyChange(
  973. IN PFM_RESOURCE Resource,
  974. IN LPCWSTR DependsOnId,
  975. IN BOOL Remove
  976. )
  977. /*++
  978. Routine Description:
  979. Broadcasts a resource control to each node that notifies it that
  980. the resource has had a dependency added or removed.
  981. Arguments:
  982. Resource - Supplies the resource that has had the dependency added
  983. or removed
  984. DependsOnId - Supplies the id of the provider resource
  985. Remove - TRUE indicates that the dependency is being removed
  986. FALSE indicates that the dependency is being added.
  987. Return Value:
  988. ERROR_SUCCESS if successful.
  989. A Win32 error code on failure.
  990. --*/
  991. {
  992. DWORD i;
  993. PNM_NODE Node;
  994. DWORD Control;
  995. DWORD Length;
  996. PFM_RESOURCE providerResource;
  997. if (Remove) {
  998. Control = CLUSCTL_RESOURCE_REMOVE_DEPENDENCY;
  999. } else {
  1000. Control = CLUSCTL_RESOURCE_ADD_DEPENDENCY;
  1001. }
  1002. //
  1003. // Get the provider resource.
  1004. //
  1005. providerResource = OmReferenceObjectById( ObjectTypeResource,
  1006. DependsOnId );
  1007. if ( providerResource == NULL ) {
  1008. return(ERROR_RESOURCE_NOT_FOUND);
  1009. }
  1010. Length = (lstrlenW(OmObjectName(providerResource)) + 1) * sizeof(WCHAR);
  1011. //
  1012. // Broadcast to all nodes in the cluster.
  1013. //
  1014. for ( i = ClusterMinNodeId; i <= NmMaxNodeId; i++ ) {
  1015. //
  1016. // If this is the local node, do the ioctl directly
  1017. //
  1018. if (i == NmLocalNodeId) {
  1019. FmpRmResourceControl( Resource,
  1020. Control,
  1021. (PUCHAR)OmObjectName(providerResource),
  1022. Length,
  1023. NULL,
  1024. 0,
  1025. NULL,
  1026. NULL );
  1027. } else {
  1028. Node = NmReferenceNodeById(i);
  1029. if ((Node != NULL) &&
  1030. (NmGetNodeState(Node) == ClusterNodeUp)) {
  1031. CL_ASSERT(Session[i] != NULL);
  1032. FmcResourceControl( Node,
  1033. Resource,
  1034. Control,
  1035. (PUCHAR)OmObjectName(providerResource),
  1036. Length,
  1037. NULL,
  1038. 0,
  1039. NULL,
  1040. NULL );
  1041. OmDereferenceObject(Node);
  1042. }
  1043. }
  1044. }
  1045. OmDereferenceObject( providerResource );
  1046. return(ERROR_SUCCESS);
  1047. } // FmpBroadcastDeleteControl
  1048. /****
  1049. @func DWORD | FmpGetResourceCharacteristics| Gets the characteristics
  1050. for a given resource.
  1051. @parm IN PFM_RESOURCE | pResource | Points to a FM_RESOURCE.
  1052. @parm OUT LPDWORD | pdwCharacteristics | The ID of the dead node.
  1053. @comm This is used to get the quorum characteristics during join since
  1054. local quorums cant support multi-node clusters.
  1055. @rdesc Returns ERROR_SUCCESS.
  1056. ****/
  1057. DWORD FmpGetResourceCharacteristics(
  1058. IN PFM_RESOURCE pResource,
  1059. OUT LPDWORD pdwCharacteristics)
  1060. {
  1061. DWORD dwStatus;
  1062. dwStatus = FmpRmResourceControl( pResource,
  1063. CLUSCTL_RESOURCE_GET_CHARACTERISTICS,
  1064. NULL,
  1065. 0,
  1066. (PUCHAR)pdwCharacteristics,
  1067. sizeof(DWORD),
  1068. NULL,
  1069. NULL );
  1070. SetLastError(dwStatus);
  1071. return (dwStatus);
  1072. }