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.

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