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.

1776 lines
52 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. resmon.c
  5. Abstract:
  6. Cluster resource manager interface routines for the resource monitor.
  7. Author:
  8. Rod Gamache (rodga) 17-Apr-1996
  9. Notes:
  10. WARNING: All of the routines in this file assume that the resource
  11. lock is held when they are called.
  12. Revision History:
  13. --*/
  14. #include "fmp.h"
  15. #define LOG_MODULE RESMONF
  16. //
  17. // Global Data
  18. //
  19. //
  20. // Local function prototypes
  21. //
  22. /////////////////////////////////////////////////////////////////////////////
  23. //
  24. // Resource Control Routines (via Resource Monitor)
  25. //
  26. /////////////////////////////////////////////////////////////////////////////
  27. DWORD
  28. FmpRmExceptionFilter(
  29. DWORD ExceptionCode
  30. )
  31. /*++
  32. Routine Description:
  33. Exception filter for calls to the Resource Monitor. These calls will
  34. often raise an exception if the RPC path to the Resource Monitor fails.
  35. Arguments:
  36. ExceptionCode - the exception to process.
  37. Returns:
  38. EXCEPTION_EXECUTE_HANDLE if the exception handler should handle this failure
  39. EXCEPTION_CONTINUE_SEARCH if the exception is a fatal exception and the handler
  40. should not handle it.
  41. --*/
  42. {
  43. ClRtlLogPrint(LOG_UNUSUAL,
  44. "[FM] FmpRmExceptionFilter: Unusual exception %1!u! occurred.\n",
  45. ExceptionCode);
  46. return(I_RpcExceptionFilter(ExceptionCode));
  47. } // FmpRmExceptionFilter
  48. DWORD
  49. FmpRmCreateResource(
  50. PFM_RESOURCE Resource
  51. )
  52. /*++
  53. Routine Description:
  54. Add a resource to the list of resources managed by the resource monitor.
  55. Arguments:
  56. Resource - The resource to add.
  57. Returns:
  58. ERROR_SUCCESS if successful.
  59. Win32 error code on failure.
  60. --*/
  61. {
  62. DWORD status;
  63. PRESMON monitor;
  64. LPWSTR debugPrefix;
  65. ClRtlLogPrint(LOG_NOISE,
  66. "[FM] FmpRmCreateResource: creating resource %1!ws! in %2!ws! resource monitor\n",
  67. OmObjectId(Resource),
  68. Resource->Flags & RESOURCE_SEPARATE_MONITOR ?
  69. L"separate" : L"shared");
  70. if (Resource->Flags & RESOURCE_SEPARATE_MONITOR) {
  71. if ( Resource->DebugPrefix != NULL ) {
  72. debugPrefix = Resource->DebugPrefix;
  73. } else {
  74. debugPrefix = Resource->Type->DebugPrefix;
  75. }
  76. Resource->Monitor = FmpCreateMonitor(debugPrefix, TRUE);
  77. if (Resource->Monitor == NULL) {
  78. return(GetLastError());
  79. }
  80. } else {
  81. CL_ASSERT(FmpDefaultMonitor != NULL);
  82. Resource->Monitor = FmpDefaultMonitor;
  83. }
  84. try {
  85. Resource->Id = RmCreateResource(Resource->Monitor->Binding,
  86. Resource->Type->DllName,
  87. OmObjectId(Resource->Type),
  88. OmObjectId(Resource),
  89. Resource->LooksAlivePollInterval,
  90. Resource->IsAlivePollInterval,
  91. (RM_NOTIFY_KEY)Resource,
  92. Resource->PendingTimeout,
  93. &status);
  94. }
  95. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  96. DWORD code = GetExceptionCode();
  97. ClRtlLogPrint(LOG_NOISE,"[FM] RmCreateResource issued exception %1!u!\n", code);
  98. //
  99. // Stop this resource monitor if it is a separate resource monitor.
  100. //
  101. if (Resource->Flags & RESOURCE_SEPARATE_MONITOR) {
  102. monitor = Resource->Monitor;
  103. #if 0
  104. CL_ASSERT( monitor->NotifyThread != NULL );
  105. CL_ASSERT( monitor->Process != NULL );
  106. // Terminate Thread call removed: ( monitor->NotifyThread, 1 );
  107. CloseHandle( monitor->NotifyThread );
  108. TerminateProcess( monitor->Process, 1 );
  109. LocalFree( monitor );
  110. #endif
  111. FmpShutdownMonitor( monitor );
  112. }
  113. Resource->Monitor = NULL;
  114. return(code);
  115. }
  116. if (Resource->Id != 0) {
  117. Resource->Flags |= RESOURCE_CREATED;
  118. ClRtlLogPrint(LOG_NOISE,
  119. "[FM] FmpRmCreateResource: created resource %1!ws!, resid %2!u!\n",
  120. OmObjectId(Resource),
  121. Resource->Id);
  122. return(ERROR_SUCCESS);
  123. }
  124. ClRtlLogPrint(LOG_NOISE,
  125. "[FM] FmpRmCreateResource: unable to create resource %1!ws!\n",
  126. OmObjectId(Resource));
  127. //
  128. // Stop this resource monitor if it is a separate resource monitor.
  129. //
  130. if (Resource->Flags & RESOURCE_SEPARATE_MONITOR) {
  131. monitor = Resource->Monitor;
  132. #if 0
  133. CL_ASSERT( monitor->NotifyThread != NULL );
  134. CL_ASSERT( monitor->Process != NULL );
  135. // Terminate Thread call removed: ( monitor->NotifyThread, 1 );
  136. CloseHandle( monitor->NotifyThread );
  137. TerminateProcess( monitor->Process, 1 );
  138. LocalFree( monitor );
  139. #endif
  140. FmpShutdownMonitor( monitor );
  141. }
  142. Resource->Monitor = NULL;
  143. return(status);
  144. } // FmpRmCreateResource
  145. DWORD
  146. FmpRmOnlineResource(
  147. PFM_RESOURCE Resource
  148. )
  149. /*++
  150. Routine Description:
  151. This routine requests the Resource Monitor to bring a resource online.
  152. Arguments:
  153. Resource - A pointer to the resource to bring online.
  154. Comments :
  155. If this is the quorum resource, the exclusive quorum lock should be
  156. held when this routine is called. Else the quorum lock should be held
  157. in shared mode. This routine release the lock.
  158. Returns:
  159. ERROR_SUCCESS - if the request was successful.
  160. ERROR_IO_PENDING - if the request is pending.
  161. A Win32 error if the request failed.
  162. --*/
  163. {
  164. CLUSTER_RESOURCE_STATE state;
  165. DWORD Status=ERROR_SUCCESS;
  166. DWORD retry = 200;
  167. #if 0
  168. PVOID callersAddress;
  169. PVOID callersCaller;
  170. RtlGetCallersAddress(
  171. &callersAddress,
  172. &callersCaller );
  173. ClRtlLogPrint(LOG_NOISE,
  174. "[FM] RmOnlineResource for <%1!ws!> called from %2!lx! and %3!lx!\n",
  175. OmObjectId( Resource ),
  176. callersAddress, callersCaller );
  177. #endif
  178. if ( Resource->State > ClusterResourcePending ) {
  179. Status = ERROR_IO_PENDING;
  180. return(Status);
  181. }
  182. if ( Resource->State == ClusterResourceOnline ) {
  183. Status = ERROR_SUCCESS;
  184. return(Status);
  185. }
  186. CL_ASSERT((Resource->State == ClusterResourceOffline) ||
  187. (Resource->State == ClusterResourceFailed));
  188. ClRtlLogPrint(LOG_NOISE,
  189. "[FM] FmpRmOnlineResource: bringing resource %1!ws! (resid %2!u!) online.\n",
  190. OmObjectId(Resource),
  191. Resource->Id);
  192. //if this is the quorum resource acquire the quolock
  193. // For registry replication to work, the resource should
  194. // not be brought online while the quorum resource is offline
  195. // what do we do for fixquorum mode
  196. OmNotifyCb(Resource, NOTIFY_RESOURCE_PREONLINE);
  197. //SS:initialize state so that in case of a failure, a failed state is
  198. // propagated.
  199. state = ClusterResourceFailed;
  200. CheckQuorumState:
  201. //CL_ASSERT( (LONG)gdwQuoBlockingResources >= 0 );
  202. if (Resource->QuorumResource) {
  203. ACQUIRE_EXCLUSIVE_LOCK(gQuoLock);
  204. } else {
  205. DWORD dwOldBlockingFlag;
  206. ACQUIRE_SHARED_LOCK(gQuoLock);
  207. // if it is not the quorum resource,
  208. // check the state of the quorum resource
  209. // check if the quorum resource is failed
  210. // we must exit from here and let the recovery for the
  211. // quorum resource to kick in
  212. if (gpQuoResource->State == ClusterResourceFailed)
  213. {
  214. Status = ERROR_QUORUM_RESOURCE_ONLINE_FAILED;
  215. CL_LOGFAILURE(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  216. //we dont halt, we will try online again at a later time
  217. FmpCallResourceNotifyCb(Resource, state);
  218. FmpPropagateResourceState( Resource, state );
  219. goto FnExit;
  220. }
  221. // check if the quorum resource is online,
  222. // if the quorum resource is marked as waiting and offlinepending,
  223. // it is actually online
  224. // if the quorum resource still needs to come online
  225. // release the lock and wait
  226. if (((gpQuoResource->State != ClusterResourceOnline) &&
  227. ((gpQuoResource->State != ClusterResourceOfflinePending) ||
  228. (!(gpQuoResource->Flags & RESOURCE_WAITING))))
  229. && !CsNoQuorum)
  230. {
  231. // we release the lock here since the quorum resource
  232. // state transition from pending needs to acquire the lock
  233. // In general it is a bad idea to do a wait holding locks
  234. RELEASE_LOCK(gQuoLock);
  235. ClRtlLogPrint(LOG_NOISE,
  236. "[FM] FmpRmOnlineResource: release quolock/group lock and wait on ghQuoOnlineEvent\r\n");
  237. Status = WaitForSingleObject(ghQuoOnlineEvent, 500);
  238. if ( Status == WAIT_OBJECT_0 ) {
  239. // If we're going to retry - make sure we wait a little.
  240. Sleep( 500 );
  241. }
  242. if ( retry-- ) {
  243. goto CheckQuorumState;
  244. }
  245. #if DBG
  246. if ( IsDebuggerPresent() ) {
  247. DbgBreakPoint();
  248. }
  249. #endif
  250. CL_LOGFAILURE(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  251. //we dont halt, we will try online again at a later time
  252. FmpCallResourceNotifyCb(Resource, state);
  253. FmpPropagateResourceState( Resource, state );
  254. return(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  255. //CsInconsistencyHalt(ERROR_INVALID_STATE);
  256. }
  257. //
  258. // assume that we'll be pending... mark the resource as having
  259. // bumped the QuoBlockResource count.
  260. //
  261. ClRtlLogPrint(LOG_NOISE,
  262. "[FM] FmpRmOnlineResource: called InterlockedIncrement on gdwQuoBlockingResources for resource %1!ws!\n",
  263. OmObjectId(Resource));
  264. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 1 );
  265. CL_ASSERT( dwOldBlockingFlag == 0 );
  266. InterlockedIncrement(&gdwQuoBlockingResources);
  267. //
  268. // everything is now fine on the local node... if any other
  269. // component (CP) needs to synchronize with the quorum resource, then
  270. // should acquire the shared lock on the quorum node as part of
  271. // their operation. If that fails, then they should assume the quorum
  272. // resource moved, and they should retry.
  273. //
  274. }
  275. // By now we have either the shared or the exclusive lock on the
  276. // quorum resource.
  277. // If we have the shared lock then the quorum resource is online(somewhere).
  278. // Unlesss there is a failure, it should not go offline.
  279. Status = ERROR_SUCCESS;
  280. if (Resource->QuorumResource) {
  281. Status = FmpRmArbitrateResource( Resource );
  282. }
  283. if (Status == ERROR_SUCCESS) {
  284. Status = RmOnlineResource( Resource->Id,
  285. (LPDWORD)&state // cast to quiet win64 warning
  286. );
  287. if (Resource->QuorumResource && Status != ERROR_SUCCESS) {
  288. MMSetQuorumOwner( MM_INVALID_NODE , /* Block = */ FALSE, NULL );
  289. }
  290. }
  291. FmpCallResourceNotifyCb(Resource, state);
  292. //SS: the synchronous state propagation must happen when it goes offline
  293. FmpPropagateResourceState( Resource, state );
  294. //
  295. // Cleanup for the non-quorum resource case.
  296. //
  297. if ( !Resource->QuorumResource &&
  298. Resource->State < ClusterResourcePending ) {
  299. DWORD dwOldBlockingFlag;
  300. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 0 );
  301. if ( dwOldBlockingFlag ) {
  302. //
  303. // If the Transition Thread processed the request, then we can't
  304. // perform the decrement.
  305. //
  306. ClRtlLogPrint(LOG_NOISE,
  307. "[FM] FmpRmOnlineResource: InterlockedDecrement on gdwQuoBlockingResources for resource %1!ws!\n",
  308. OmObjectId(Resource));
  309. InterlockedDecrement(&gdwQuoBlockingResources);
  310. }
  311. }
  312. if (Status != ERROR_SUCCESS)
  313. {
  314. ClRtlLogPrint(LOG_NOISE,
  315. "[FM] FmpRmOnlineResource: RmOnlineResource Failed. Resource %1!ws!, status %2!u!\n",
  316. OmObjectId(Resource),
  317. Status);
  318. }
  319. //if RmOnlineResource is successful, do the post processing
  320. if ( Resource->State == ClusterResourceOnline ) {
  321. ClRtlLogPrint(LOG_NOISE,
  322. "[FM] FmpRmOnlineResource: %1!ws! is now online\n",
  323. OmObjectId(Resource));
  324. //if this is the quorum resource and it goes into online state
  325. //immediately, wake other threads
  326. if (Resource->QuorumResource)
  327. SetEvent(ghQuoOnlineEvent);
  328. } else if ( Resource->State > ClusterResourcePending ) {
  329. ClRtlLogPrint(LOG_NOISE,
  330. "[FM] FmpRmOnlineResource: Resource %1!ws! pending\n",
  331. OmObjectId(Resource));
  332. //SS: what should we tell the callbacks
  333. //FmpNotifyResourceCb(Resource,??);
  334. //will they eventually get called if so how ?
  335. if (Resource->QuorumResource)
  336. {
  337. //the quorum resource is coming online, unsignal the event so that
  338. //all threads that need quorum resource to be online will block
  339. ResetEvent(ghQuoOnlineEvent);
  340. }
  341. Status = ERROR_IO_PENDING;
  342. } else {
  343. ClRtlLogPrint(LOG_NOISE,
  344. "[FM] FmpRmOnlineResource: Failed. Resource %1!ws!, state %2!u!\n",
  345. OmObjectId(Resource),
  346. Resource->State);
  347. //
  348. // rjain: for a synchronous resource we must post RESOURCE_FAILED event
  349. // so thatfailback policies are correctly followed
  350. // Also pretend that the old state to be online to actually force the
  351. // restart behaviour. See: FmpProcessResourceEvents.
  352. //
  353. OmReferenceObject(Resource);
  354. FmpPostWorkItem(FM_EVENT_RES_RESOURCE_FAILED,
  355. Resource,
  356. ClusterResourceOnline);
  357. Status = ERROR_RESMON_ONLINE_FAILED;
  358. }
  359. FnExit:
  360. RELEASE_LOCK(gQuoLock);
  361. ClRtlLogPrint(LOG_NOISE,
  362. "[FM] FmpRmOnlineResource: Returning. Resource %1!ws!, state %2!u!, status %3!u!.\n",
  363. OmObjectId(Resource),
  364. Resource->State,
  365. Status);
  366. return (Status);
  367. } // FmpRmOnlineResource
  368. VOID
  369. FmpRmTerminateResource(
  370. PFM_RESOURCE Resource
  371. )
  372. /*++
  373. Routine Description:
  374. Terminates (immediately) a resource.
  375. Arguments:
  376. Resource - A pointer to the resource to terminate.
  377. Returns:
  378. None.
  379. --*/
  380. {
  381. DWORD dwOldBlockingFlag;
  382. //notify callbacks that need preprocessing before a resource is
  383. //brought offline-call this here since all resources may not go
  384. //thru the offline pending transition
  385. //SS - what if the resource never even goes to offline
  386. //pending state - then should we renotify the callbacks that it
  387. //is still online?
  388. OmNotifyCb(Resource, NOTIFY_RESOURCE_PREOFFLINE);
  389. //
  390. // Try to terminate the resource.
  391. //
  392. try {
  393. if (Resource->QuorumResource) {
  394. MMSetQuorumOwner( MM_INVALID_NODE, /* Block = */ FALSE, NULL );
  395. }
  396. RmTerminateResource(Resource->Id);
  397. // if FmpRmterminate was called for a failed resource, mark
  398. // the resource as Failed and not Offline.
  399. if (Resource->State == ClusterResourceFailed)
  400. {
  401. FmpCallResourceNotifyCb(Resource, ClusterResourceFailed);
  402. FmpPropagateResourceState( Resource, ClusterResourceFailed );
  403. }
  404. else
  405. {
  406. FmpCallResourceNotifyCb(Resource, ClusterResourceOffline);
  407. FmpPropagateResourceState( Resource, ClusterResourceOffline );
  408. }
  409. }
  410. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  411. DWORD code = GetExceptionCode();
  412. ClRtlLogPrint(LOG_NOISE,"[FM] RmTerminateResource issued exception %1!u!\n", code);
  413. return;
  414. }
  415. //if terminate was called during a pending state, this resource may be
  416. //blocking the quorum resource, decrement the blocking count
  417. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 0 );
  418. if ( dwOldBlockingFlag ) {
  419. ClRtlLogPrint(LOG_NOISE,
  420. "[FM] FmpRmTerminateResource: InterlockedDecrement on gdwQuoBlockingResources, Resource %1!ws!\n",
  421. OmObjectId(Resource));
  422. InterlockedDecrement(&gdwQuoBlockingResources);
  423. }
  424. ClRtlLogPrint(LOG_NOISE,
  425. "[FM] RmTerminateResource: %1!ws! is now offline\n",
  426. OmObjectId(Resource));
  427. return;
  428. } // FmpRmTerminateResource
  429. DWORD
  430. FmpRmOfflineResource(
  431. PFM_RESOURCE Resource
  432. )
  433. /*++
  434. Routine Description:
  435. Calls the Resource Monitor to take a resource offline.
  436. Arguments:
  437. Resource - A pointer to the resource to terminate.
  438. Returns:
  439. ERROR_SUCCESS if the request is successful.
  440. ERROR_IO_PENDING if the request is pending.
  441. Win32 error code on failure.
  442. --*/
  443. {
  444. CLUSTER_RESOURCE_STATE state;
  445. DWORD status;
  446. DWORD retry = 200;
  447. #if DBG
  448. PLIST_ENTRY listEntry;
  449. #endif
  450. if ( Resource->State > ClusterResourcePending ) {
  451. ClRtlLogPrint(LOG_NOISE,"[FM] FmpRmOfflineResource: pending condition\n");
  452. return(ERROR_IO_PENDING);
  453. }
  454. CL_ASSERT(Resource->State != ClusterResourceOffline);
  455. #if DBG
  456. // everything else in the same group must be offline if this is the
  457. // quorum resource
  458. if ( Resource->QuorumResource ) {
  459. PFM_GROUP group = Resource->Group;
  460. PFM_RESOURCE resource;
  461. for ( listEntry = group->Contains.Flink;
  462. listEntry != &(group->Contains);
  463. listEntry = listEntry->Flink ) {
  464. resource = CONTAINING_RECORD(listEntry,
  465. FM_RESOURCE,
  466. ContainsLinkage );
  467. if ( (Resource != resource) &&
  468. (resource->State != ClusterResourceOffline) &&
  469. (resource->State != ClusterResourceFailed) &&
  470. (resource->State != ClusterResourceOfflinePending) ) {
  471. ClRtlLogPrint(LOG_NOISE,
  472. "[FM] RmOfflineResource: resource <%1!ws!> not offline when the quorum resource was shutting down.\n",
  473. OmObjectId(resource));
  474. CsInconsistencyHalt(ERROR_INVALID_STATE);
  475. }
  476. }
  477. } else {
  478. // this is not the quorum resource... but if the quorum resource is in
  479. // this group, it must not be offline!
  480. PFM_GROUP group = Resource->Group;
  481. PFM_RESOURCE resource;
  482. for ( listEntry = group->Contains.Flink;
  483. listEntry != &(group->Contains);
  484. listEntry = listEntry->Flink ) {
  485. resource = CONTAINING_RECORD(listEntry,
  486. FM_RESOURCE,
  487. ContainsLinkage );
  488. if ( (resource->QuorumResource) &&
  489. ((resource->State == ClusterResourceOffline) ||
  490. (resource->State == ClusterResourceFailed) ||
  491. ((resource->State == ClusterResourceOfflinePending) &&
  492. (!resource->Flags & RESOURCE_WAITING))) ) {
  493. ClRtlLogPrint(LOG_NOISE,
  494. "[FM] RmOfflineResource: quorum resource <%1!ws!> offline when resource <%2!ws!> was shutting down.\n",
  495. OmObjectId(resource),
  496. OmObjectId(Resource));
  497. CsInconsistencyHalt(ERROR_INVALID_STATE);
  498. }
  499. }
  500. }
  501. #endif
  502. state = ClusterResourceFailed;
  503. CheckQuorumState:
  504. //if this is the quorum resource acquire the quolock
  505. // For registry replication to work, the resource should
  506. // not be brought online while the quorum resource is offline
  507. // what do we do for fixquorum mode
  508. if (Resource->QuorumResource) {
  509. ACQUIRE_EXCLUSIVE_LOCK(gQuoLock);
  510. } else {
  511. ACQUIRE_SHARED_LOCK(gQuoLock);
  512. }
  513. //if it is not the quorum resource, check the state of the quorum resource
  514. if (!Resource->QuorumResource)
  515. {
  516. DWORD dwOldBlockingFlag;
  517. // check if the quorum resource is failed
  518. // we must exit from here and allow the recovery for the
  519. // quorum resource to kick in, which can only happen when
  520. // the group lock is released
  521. if (gpQuoResource->State == ClusterResourceFailed)
  522. {
  523. status = ERROR_QUORUM_RESOURCE_ONLINE_FAILED;
  524. CL_LOGFAILURE(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  525. RELEASE_LOCK(gQuoLock);
  526. FmpCallResourceNotifyCb(Resource, state);
  527. FmpPropagateResourceState( Resource, state );
  528. return(status);
  529. }
  530. // check if the quorum resource is online,
  531. // if the quorum resource is marked as waiting and offlinepending,
  532. // it is actually online.
  533. // if the quorum resource still needs to come online,
  534. // release the lock and wait
  535. if (((gpQuoResource->State != ClusterResourceOnline) &&
  536. ((gpQuoResource->State != ClusterResourceOfflinePending) ||
  537. (!(gpQuoResource->Flags & RESOURCE_WAITING))))
  538. && !CsNoQuorum)
  539. {
  540. RELEASE_LOCK(gQuoLock);
  541. ClRtlLogPrint(LOG_NOISE,
  542. "[FM] FmpRmOfflineResource: release quolock/group lock and wait on ghQuoOnlineEvent\r\n");
  543. WaitForSingleObject(ghQuoOnlineEvent, 500);
  544. if ( retry-- ) {
  545. Sleep(500);
  546. goto CheckQuorumState;
  547. }
  548. #if DBG
  549. if ( IsDebuggerPresent() ) {
  550. DbgBreakPoint();
  551. }
  552. #endif
  553. CL_LOGFAILURE(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  554. // Should we halt? What about the pre-online notification above?
  555. FmpCallResourceNotifyCb(Resource, state);
  556. FmpPropagateResourceState( Resource, state );
  557. return(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  558. //CsInconsistencyHalt(ERROR_INVALID_STATE);
  559. }
  560. //
  561. // assume that we'll be pending... mark the resource as having
  562. // bumped the QuoBlockResource count.
  563. //
  564. ClRtlLogPrint(LOG_NOISE,
  565. "[FM] FmpRmOfflineResource: InterlockedIncrement on gdwQuoBlockingResources for resource %1!ws!\n",
  566. OmObjectId(Resource));
  567. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 1 );
  568. CL_ASSERT( dwOldBlockingFlag == 0 );
  569. InterlockedIncrement(&gdwQuoBlockingResources);
  570. }
  571. else
  572. {
  573. DWORD dwNumBlockingResources;
  574. //allow resources about 30 seconds to finish a pending
  575. //operation
  576. retry = 60;
  577. // This is for a quorum resource.
  578. CheckPendingResources:
  579. // this is the quorum resource, wait for other resources
  580. // to get out of their pending states
  581. // new resources are not allowed to queue since the quorum
  582. // lock is held exclusively
  583. dwNumBlockingResources =
  584. InterlockedCompareExchange( &gdwQuoBlockingResources, 0, 0 );
  585. if (dwNumBlockingResources)
  586. {
  587. ClRtlLogPrint(LOG_NOISE,
  588. "[FM] FmpRmOfflineResource: Quorum resource waiting to be brought offline-sleep.BlckingRes=%1!u!\r\n",
  589. dwNumBlockingResources);
  590. //sleep for 500 msec
  591. Sleep(500);
  592. if ( retry-- ) {
  593. goto CheckPendingResources;
  594. }
  595. //if some resources are still pending, go ahead and offline
  596. //the quorum, the checkpointing code will simply retry when
  597. //it finds that the quorum resource is not available
  598. #if 0
  599. if ( IsDebuggerPresent() ) {
  600. DbgBreakPoint();
  601. }
  602. #endif
  603. ClRtlLogPrint(LOG_NOISE,
  604. "[FM] FmpRmOfflineResource: Quorum resource is being brought offline despite %1!u! pending resources...\r\n",
  605. dwNumBlockingResources);
  606. }
  607. }
  608. status = ERROR_SUCCESS;
  609. if (Resource->QuorumResource) {
  610. state = Resource->State;
  611. status = MMSetQuorumOwner( MM_INVALID_NODE, /* Block = */ TRUE, NULL );
  612. }
  613. if (status == ERROR_SUCCESS) {
  614. //notify callbacks that need preprocessing before a resource is
  615. //brought offline-call this here since all resources may not go
  616. //thru the offline pending transition
  617. //SS - what if the resource never even goes to offline
  618. //pending state - then should we renotify the callbacks that it
  619. //is still online?
  620. state = ClusterResourceOffline;
  621. OmNotifyCb(Resource, NOTIFY_RESOURCE_PREOFFLINE);
  622. status = RmOfflineResource( Resource->Id,
  623. (LPDWORD)&state // cast to quiet win64 warning
  624. );
  625. }
  626. //
  627. // Cleanup for the non-quorum resource case
  628. // if the resource has gone offline, decrement the count
  629. //
  630. if ( !Resource->QuorumResource &&
  631. state < ClusterResourcePending ) {
  632. DWORD dwOldBlockingFlag;
  633. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 0 );
  634. if ( dwOldBlockingFlag ) {
  635. //
  636. // If the Transition Thread processed the request, then we can't
  637. // perform the decrement.
  638. //
  639. ClRtlLogPrint(LOG_NOISE,
  640. "[FM] FmpRmOfflineResource: InterlockedDecrement on gdwQuoBlockingResources for resource %1!ws!\n",
  641. OmObjectId(Resource));
  642. InterlockedDecrement(&gdwQuoBlockingResources);
  643. }
  644. }
  645. if (status == ERROR_SUCCESS)
  646. {
  647. //
  648. // If the new state is pending, then we must wait.
  649. //
  650. if ( state == ClusterResourceOffline ) {
  651. ClRtlLogPrint(LOG_NOISE,
  652. "[FM] FmpRmOfflineResource: %1!ws! is now offline\n",
  653. OmObjectId(Resource));
  654. } else if ( state == ClusterResourceOfflinePending ) {
  655. ClRtlLogPrint(LOG_NOISE,
  656. "[FM] FmpRmOfflineResource: %1!ws! offline pending\n",
  657. OmObjectId(Resource));
  658. status = ERROR_IO_PENDING;
  659. }
  660. }
  661. else
  662. {
  663. ClRtlLogPrint(LOG_NOISE,
  664. "[FM] FmpRmOfflineResource: RmOffline() for %1!ws! returned error %2!u!\r\n",
  665. OmObjectId(Resource), status);
  666. }
  667. FmpCallResourceNotifyCb(Resource, state);
  668. FmpPropagateResourceState( Resource, state );
  669. RELEASE_LOCK(gQuoLock);
  670. return(status);
  671. } // FmpRmOfflineResource
  672. DWORD
  673. FmpRmCloseResource(
  674. PFM_RESOURCE Resource
  675. )
  676. /*++
  677. Routine Description:
  678. Removes a resource from those being managed by the resource monitor.
  679. Arguments:
  680. Resource - The resource to remove.
  681. Returns:
  682. ERROR_SUCCESS if successful.
  683. Win32 error code on failure.
  684. --*/
  685. {
  686. DWORD status;
  687. PRESMON monitor;
  688. if (Resource->Id == 0) {
  689. //
  690. // This resource was never fully created.
  691. //
  692. return(ERROR_SUCCESS);
  693. }
  694. monitor = Resource->Monitor;
  695. Resource->Monitor = NULL;
  696. if ( Resource->QuorumResource ) {
  697. RmReleaseResource( Resource->Id );
  698. Resource->QuorumResource = FALSE;
  699. }
  700. try {
  701. RmCloseResource(&Resource->Id);
  702. }
  703. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  704. DWORD status = GetExceptionCode();
  705. ClRtlLogPrint(LOG_NOISE,"[FM] RmDestroyResource issued exception %1!u!\n", status);
  706. }
  707. if ( monitor &&
  708. Resource->Flags & RESOURCE_SEPARATE_MONITOR) {
  709. //
  710. // Shutdown the resource monitor as well.
  711. //
  712. ClRtlLogPrint(LOG_NOISE,
  713. "[FM] Shutting down separate resource monitor!\n");
  714. FmpShutdownMonitor(monitor);
  715. }
  716. Resource->Id = 0;
  717. return(ERROR_SUCCESS);
  718. } // FmpRmCloseResource
  719. DWORD
  720. FmpRmArbitrateResource(
  721. IN PFM_RESOURCE Resource
  722. )
  723. /*++
  724. Routine Description:
  725. Arbitrate for the given resource.
  726. Arguments:
  727. Resource - The resource to arbitrate.
  728. Return Value:
  729. ERROR_SUCCESS if successful.
  730. Win32 error code on failure.
  731. --*/
  732. {
  733. DWORD status = ERROR_SUCCESS;
  734. if (Resource->Id == 0) {
  735. //
  736. // This resource was never fully created.
  737. //
  738. return(ERROR_RESOURCE_NOT_AVAILABLE);
  739. }
  740. try {
  741. if (Resource->QuorumResource) {
  742. status = MMSetQuorumOwner( NmGetNodeId(NmLocalNode), /* Block = */ TRUE, NULL );
  743. }
  744. if (status == ERROR_SUCCESS) {
  745. status = RmArbitrateResource(Resource->Id);
  746. if (status != ERROR_SUCCESS) {
  747. if (Resource->QuorumResource) {
  748. MMSetQuorumOwner( MM_INVALID_NODE , /* Block = */ FALSE, NULL );
  749. }
  750. }
  751. }
  752. }
  753. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  754. DWORD status = GetExceptionCode();
  755. ClRtlLogPrint(LOG_NOISE,
  756. "[FM] RmArbitrateResource issued exception %1!u!\n",
  757. status);
  758. }
  759. return(status);
  760. } // FmpRmArbitrateResource
  761. DWORD
  762. FmpRmReleaseResource(
  763. IN PFM_RESOURCE Resource
  764. )
  765. /*++
  766. Routine Description:
  767. Release arbitration on a given resource.
  768. Arguments:
  769. Resource - The resource to release.
  770. Return Value:
  771. ERROR_SUCCESS if successful.
  772. Win32 error code on failure.
  773. --*/
  774. {
  775. DWORD status = ERROR_SUCCESS;
  776. if (Resource->Id == 0) {
  777. //
  778. // This resource was never fully created.
  779. //
  780. return(ERROR_RESOURCE_NOT_AVAILABLE);
  781. }
  782. try {
  783. status = RmReleaseResource(Resource->Id);
  784. }
  785. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  786. DWORD status = GetExceptionCode();
  787. ClRtlLogPrint(LOG_NOISE,
  788. "[FM] RmReleaseResource issued exception %1!u!\n",
  789. status);
  790. }
  791. return(status);
  792. } // FmpRmReleaseResource
  793. DWORD
  794. FmpRmFailResource(
  795. IN PFM_RESOURCE Resource
  796. )
  797. /*++
  798. Routine Description:
  799. Fail a given resource.
  800. Arguments:
  801. Resource - The resource to fail.
  802. Return Value:
  803. ERROR_SUCCESS if successful.
  804. Win32 error code on failure.
  805. --*/
  806. {
  807. if (Resource->QuorumResource) {
  808. MMSetQuorumOwner( MM_INVALID_NODE, /* Block = */ FALSE, NULL );
  809. }
  810. return(RmFailResource(Resource->Id));
  811. } // FmpRmFailResource
  812. DWORD FmpRmLoadResTypeDll(
  813. IN PFM_RESTYPE pResType
  814. )
  815. {
  816. PRESMON monitor;
  817. DWORD dwStatus;
  818. LPWSTR pszDebugPrefix;
  819. // Read the DebugControlFunction registry value.
  820. //
  821. if ( pResType->Flags & RESTYPE_DEBUG_CONTROL_FUNC ) {
  822. if ( pResType->DebugPrefix != NULL ) {
  823. pszDebugPrefix = pResType->DebugPrefix;
  824. } else {
  825. pszDebugPrefix = pResType->DebugPrefix;
  826. }
  827. monitor = FmpCreateMonitor(pszDebugPrefix, TRUE);
  828. if (monitor == NULL) {
  829. dwStatus = GetLastError();
  830. goto FnExit;
  831. }
  832. } else {
  833. CL_ASSERT(FmpDefaultMonitor != NULL);
  834. monitor = FmpDefaultMonitor;
  835. }
  836. dwStatus = RmLoadResourceTypeDll(monitor->Binding, OmObjectId(pResType),
  837. pResType->DllName);
  838. if (dwStatus != ERROR_SUCCESS)
  839. {
  840. ClRtlLogPrint(LOG_NOISE,
  841. "[FM] RmLoadResourceTypeDll call failed %1!u!\n",
  842. dwStatus);
  843. }
  844. if ( pResType->Flags & RESTYPE_DEBUG_CONTROL_FUNC )
  845. {
  846. //
  847. // Stop this resource monitor if it is a separate resource monitor.
  848. //
  849. CL_ASSERT( monitor->NotifyThread != NULL );
  850. CL_ASSERT( monitor->Process != NULL );
  851. FmpShutdownMonitor( monitor );
  852. }
  853. FnExit:
  854. return(dwStatus);
  855. }
  856. DWORD
  857. FmpRmChangeResourceParams(
  858. IN PFM_RESOURCE Resource
  859. )
  860. /*++
  861. Routine Description:
  862. Tell the resource monitor to change parameters for the given resource.
  863. Arguments:
  864. Resource - The resource to change parameters.
  865. Return Value:
  866. ERROR_SUCCESS if successful.
  867. A Win32 error code on failure.
  868. --*/
  869. {
  870. ClRtlLogPrint(LOG_NOISE,
  871. "[FM] FmpRmChangeResourceParams for resource <%1!ws!> called...\n",
  872. OmObjectId(Resource));
  873. return(RmChangeResourceParams(
  874. Resource->Id,
  875. Resource->LooksAlivePollInterval,
  876. Resource->IsAlivePollInterval,
  877. Resource->PendingTimeout ) );
  878. } // FmpRmChangeResourceParams
  879. DWORD
  880. FmpRmResourceControl(
  881. IN PFM_RESOURCE Resource,
  882. IN DWORD ControlCode,
  883. IN PUCHAR InBuffer,
  884. IN DWORD InBufferSize,
  885. OUT PUCHAR OutBuffer,
  886. IN DWORD OutBufferSize,
  887. OUT LPDWORD BytesReturned,
  888. OUT LPDWORD Required
  889. )
  890. /*++
  891. Routine Description:
  892. Provides for arbitrary communication and control between an application
  893. and a specific instance of a resource.
  894. Arguments:
  895. Resource - Supplies the resource to be controlled.
  896. ControlCode- Supplies the control code that defines the
  897. structure and action of the resource control.
  898. Values of ControlCode between 0 and 0x10000000 are reserved
  899. for future definition and use by Microsoft. All other values
  900. are available for use by ISVs
  901. InBuffer- Supplies a pointer to the input buffer to be passed
  902. to the resource.
  903. InBufferSize- Supplies the size, in bytes, of the data pointed
  904. to by lpInBuffer..
  905. OutBuffer- Supplies a pointer to the output buffer to be
  906. filled in by the resource..
  907. OutBufferSize- Supplies the size, in bytes, of the available
  908. space pointed to by lpOutBuffer.
  909. BytesReturned - Returns the number of bytes of lpOutBuffer
  910. actually filled in by the resource..
  911. Required - The number of bytes required if OutBuffer is not big enough.
  912. Return Value:
  913. ERROR_SUCCESS if successful
  914. Win32 error code otherwise
  915. --*/
  916. {
  917. DWORD status;
  918. DWORD Dummy;
  919. DWORD dwTmpBytesReturned;
  920. DWORD dwTmpBytesRequired;
  921. CLUSPROP_BUFFER_HELPER props;
  922. DWORD bufSize;
  923. CL_ASSERT( Resource->Group != NULL );
  924. //
  925. // Handle any requests that must be done without locks helds.
  926. //
  927. switch ( ControlCode ) {
  928. case CLUSCTL_RESOURCE_GET_NAME:
  929. if ( (Resource->Monitor == NULL) ||
  930. (OmObjectName( Resource ) == NULL) ) {
  931. return(ERROR_NOT_READY);
  932. }
  933. props.pb = OutBuffer;
  934. bufSize = (lstrlenW( OmObjectName( Resource ) ) + 1) * sizeof(WCHAR);
  935. if ( bufSize > OutBufferSize ) {
  936. *Required = bufSize;
  937. *BytesReturned = 0;
  938. status = ERROR_MORE_DATA;
  939. } else {
  940. lstrcpyW( props.psz, OmObjectName( Resource ) );
  941. *BytesReturned = bufSize;
  942. *Required = 0;
  943. status = ERROR_SUCCESS;
  944. }
  945. return(status);
  946. case CLUSCTL_RESOURCE_GET_ID:
  947. if ( (Resource->Monitor == NULL) ||
  948. (OmObjectId( Resource ) == NULL) ) {
  949. return(ERROR_NOT_READY);
  950. }
  951. props.pb = OutBuffer;
  952. bufSize = (lstrlenW( OmObjectId( Resource ) ) + 1) * sizeof(WCHAR);
  953. if ( bufSize > OutBufferSize ) {
  954. *Required = bufSize;
  955. *BytesReturned = 0;
  956. status = ERROR_MORE_DATA;
  957. } else {
  958. lstrcpyW( props.psz, OmObjectId( Resource ) );
  959. *BytesReturned = bufSize;
  960. *Required = 0;
  961. status = ERROR_SUCCESS;
  962. }
  963. return(status);
  964. case CLUSCTL_RESOURCE_GET_RESOURCE_TYPE:
  965. if ( (Resource->Monitor == NULL) ||
  966. (OmObjectId( Resource->Type ) == NULL) ) {
  967. return(ERROR_NOT_READY);
  968. }
  969. props.pb = OutBuffer;
  970. bufSize = (lstrlenW( OmObjectId( Resource->Type ) ) + 1) * sizeof(WCHAR);
  971. if ( bufSize > OutBufferSize ) {
  972. *Required = bufSize;
  973. *BytesReturned = 0;
  974. status = ERROR_MORE_DATA;
  975. } else {
  976. lstrcpyW( props.psz, OmObjectId( Resource->Type ) );
  977. *BytesReturned = bufSize;
  978. *Required = 0;
  979. status = ERROR_SUCCESS;
  980. }
  981. return(status);
  982. case CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT:
  983. case CLUSCTL_RESOURCE_DELETE_REGISTRY_CHECKPOINT:
  984. {
  985. LPWSTR RegistryKey;
  986. DWORD LastChar;
  987. //
  988. // Validate the input buffer
  989. //
  990. RegistryKey = (LPWSTR)InBuffer;
  991. LastChar = (InBufferSize/sizeof(WCHAR)) - 1;
  992. //
  993. // If the length of the input buffer is zero, or not a integral
  994. // number of WCHARs, or the last character is not NULL, the
  995. // request is invalid.
  996. //
  997. if ((InBufferSize < sizeof(WCHAR)) ||
  998. ((InBufferSize % sizeof(WCHAR)) != 0) ||
  999. (RegistryKey == NULL) ||
  1000. (RegistryKey[LastChar] != L'\0')) {
  1001. return(ERROR_INVALID_PARAMETER);
  1002. }
  1003. //
  1004. // If we are not the owner of this resource, don't let the set
  1005. // happen.
  1006. //
  1007. if (Resource->Group->OwnerNode != NmLocalNode) {
  1008. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  1009. }
  1010. //
  1011. // Call the checkpoint manager to perform the change.
  1012. //
  1013. if (ControlCode == CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT) {
  1014. status = CpAddRegistryCheckpoint(Resource, RegistryKey);
  1015. } else {
  1016. status = CpDeleteRegistryCheckpoint(Resource, RegistryKey);
  1017. }
  1018. }
  1019. *BytesReturned = 0;
  1020. return(status);
  1021. case CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT:
  1022. case CLUSCTL_RESOURCE_DELETE_CRYPTO_CHECKPOINT:
  1023. {
  1024. //
  1025. // If we are not the owner of this resource, don't let the set
  1026. // happen.
  1027. //
  1028. if (Resource->Group->OwnerNode != NmLocalNode) {
  1029. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  1030. }
  1031. //
  1032. // Call the checkpoint manager to perform the change.
  1033. //
  1034. if (ControlCode == CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT) {
  1035. status = CpckAddCryptoCheckpoint(Resource, InBuffer, InBufferSize);
  1036. } else {
  1037. status = CpckDeleteCryptoCheckpoint(Resource, InBuffer, InBufferSize);
  1038. }
  1039. }
  1040. *BytesReturned = 0;
  1041. return(status);
  1042. case CLUSCTL_RESOURCE_GET_REGISTRY_CHECKPOINTS:
  1043. //
  1044. // Call the checkpoint manager to retrieve the list of checkpoints
  1045. //
  1046. status = CpGetRegistryCheckpoints(Resource,
  1047. OutBuffer,
  1048. OutBufferSize,
  1049. BytesReturned,
  1050. Required);
  1051. return(status);
  1052. case CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS:
  1053. //
  1054. // Call the checkpoint manager to retrieve the list of checkpoints
  1055. //
  1056. status = CpckGetCryptoCheckpoints(Resource,
  1057. OutBuffer,
  1058. OutBufferSize,
  1059. BytesReturned,
  1060. Required);
  1061. return(status);
  1062. case CLUSCTL_RESOURCE_UPGRADE_DLL:
  1063. status = FmpUpgradeResourceDLL(Resource,
  1064. ( LPWSTR ) InBuffer);
  1065. return(status);
  1066. default:
  1067. break;
  1068. }
  1069. OmReferenceObject( Resource );
  1070. FmpAcquireLocalResourceLock( Resource );
  1071. //if the resource has been marked for delete, then fail this call
  1072. if (!IS_VALID_FM_RESOURCE(Resource))
  1073. {
  1074. status = ERROR_RESOURCE_NOT_AVAILABLE;
  1075. FmpReleaseLocalResourceLock( Resource );
  1076. goto FnExit;
  1077. }
  1078. if ( Resource->Monitor == NULL ) {
  1079. status = FmpInitializeResource( Resource, TRUE );
  1080. if ( status != ERROR_SUCCESS ) {
  1081. FmpReleaseLocalResourceLock( Resource );
  1082. goto FnExit;
  1083. }
  1084. }
  1085. FmpReleaseLocalResourceLock( Resource );
  1086. //to take care of the output reference pointer which cannot be NULL.
  1087. if (!OutBuffer)
  1088. {
  1089. OutBuffer = (PUCHAR)&Dummy;
  1090. OutBufferSize = 0;
  1091. }
  1092. if (!BytesReturned)
  1093. BytesReturned = &dwTmpBytesReturned;
  1094. if (!Required)
  1095. Required = &dwTmpBytesRequired;
  1096. try {
  1097. status = RmResourceControl(Resource->Id,
  1098. ControlCode,
  1099. InBuffer,
  1100. InBufferSize,
  1101. OutBuffer,
  1102. OutBufferSize,
  1103. BytesReturned,
  1104. Required
  1105. );
  1106. }
  1107. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  1108. status = GetExceptionCode();
  1109. ClRtlLogPrint(LOG_NOISE,
  1110. "[FM] RmResourceControl issued exception %1!u!\n",
  1111. status);
  1112. }
  1113. if ( ( status != ERROR_SUCCESS ) &&
  1114. ( status != ERROR_MORE_DATA ) &&
  1115. ( status != ERROR_INVALID_FUNCTION ) )
  1116. {
  1117. ClRtlLogPrint(LOG_NOISE,
  1118. "[FM] FmpRmResourceControl: RmResourceControl returned %1!u! for resource %2!ws!, resid=%3!u!...\n",
  1119. status,
  1120. OmObjectId(Resource),
  1121. Resource->Id);
  1122. }
  1123. //for core resource we may need special handling
  1124. if ((status == ERROR_SUCCESS) || (status == ERROR_RESOURCE_PROPERTIES_STORED))
  1125. {
  1126. DWORD dwPostProcessStatus;
  1127. dwPostProcessStatus = FmpPostProcessResourceControl( Resource,
  1128. ControlCode,
  1129. InBuffer,
  1130. InBufferSize,
  1131. OutBuffer,
  1132. OutBufferSize,
  1133. BytesReturned,
  1134. Required );
  1135. if ( dwPostProcessStatus != ERROR_SUCCESS ) status = dwPostProcessStatus;
  1136. }
  1137. if ( ((status == ERROR_SUCCESS) ||
  1138. (status == ERROR_RESOURCE_PROPERTIES_STORED)) &&
  1139. (ControlCode & CLCTL_MODIFY_MASK) ) {
  1140. //
  1141. // We cannot just broadcast a cluster wide event... which is what
  1142. // we want to do. Unfortunately, this code path can be activated
  1143. // from within a GUM call, and we cannot call GUM back until we
  1144. // have dispatched the current event.
  1145. //
  1146. //
  1147. // Reference the resource object to keep it around while we
  1148. // perform the post notification. The dereference must occur
  1149. // in the post routine after the event posting.
  1150. //
  1151. OmReferenceObject( Resource );
  1152. FmpPostWorkItem( FM_EVENT_RESOURCE_PROPERTY_CHANGE,
  1153. Resource,
  1154. 0 );
  1155. }
  1156. FnExit:
  1157. OmDereferenceObject( Resource );
  1158. //FmpReleaseLocalResourceLock( Resource );
  1159. return(status);
  1160. } // FmpRmResourceControl
  1161. DWORD
  1162. FmpRmResourceTypeControl(
  1163. IN LPCWSTR ResourceTypeName,
  1164. IN DWORD ControlCode,
  1165. IN PUCHAR InBuffer,
  1166. IN DWORD InBufferSize,
  1167. OUT PUCHAR OutBuffer,
  1168. IN DWORD OutBufferSize,
  1169. OUT LPDWORD BytesReturned,
  1170. OUT LPDWORD Required
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. Provides for arbitrary communication and control between an application
  1175. and a specific instance of a resource type.
  1176. Arguments:
  1177. ResourceTypeName - Supplies the name of the resource type to be
  1178. controlled.
  1179. ControlCode- Supplies the control code that defines the
  1180. structure and action of the resource control.
  1181. Values of dwControlCode between 0 and 0x10000000 are reserved
  1182. for future definition and use by Microsoft. All other values
  1183. are available for use by ISVs
  1184. InBuffer- Supplies a pointer to the input buffer to be passed
  1185. to the resource.
  1186. InBufferSize- Supplies the size, in bytes, of the data pointed
  1187. to by lpInBuffer..
  1188. OutBuffer- Supplies a pointer to the output buffer to be
  1189. filled in by the resource..
  1190. OutBufferSize- Supplies the size, in bytes, of the available
  1191. space pointed to by lpOutBuffer.
  1192. BytesReturned - Returns the number of bytes of lpOutBuffer
  1193. actually filled in by the resource..
  1194. Required - The number of bytes required if OutBuffer is not big enough.
  1195. Return Value:
  1196. ERROR_SUCCESS if successful
  1197. Win32 error code otherwise
  1198. --*/
  1199. {
  1200. DWORD status;
  1201. PRESMON monitor;
  1202. PFM_RESTYPE type = NULL;
  1203. LPWSTR debugPrefix;
  1204. DWORD Dummy;
  1205. DWORD dwTmpBytesReturned;
  1206. DWORD dwTmpBytesRequired;
  1207. //
  1208. // Find the resource type structure associated with this resource type name
  1209. //
  1210. OmEnumObjects( ObjectTypeResType,
  1211. FmpReturnResourceType,
  1212. &type,
  1213. (PVOID)ResourceTypeName );
  1214. if ( type == NULL ) {
  1215. return(ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND);
  1216. }
  1217. //
  1218. // Read the DebugControlFunction registry value.
  1219. //
  1220. if ( type->Flags & RESTYPE_DEBUG_CONTROL_FUNC ) {
  1221. if ( type->DebugPrefix != NULL ) {
  1222. debugPrefix = type->DebugPrefix;
  1223. } else {
  1224. debugPrefix = type->DebugPrefix;
  1225. }
  1226. monitor = FmpCreateMonitor(debugPrefix, TRUE);
  1227. if (monitor == NULL) {
  1228. return(GetLastError());
  1229. }
  1230. } else {
  1231. CL_ASSERT(FmpDefaultMonitor != NULL);
  1232. monitor = FmpDefaultMonitor;
  1233. }
  1234. //to take care of the output reference pointer which cannot be NULL.
  1235. if (!OutBuffer)
  1236. {
  1237. OutBuffer = (PUCHAR)&Dummy;
  1238. OutBufferSize = 0;
  1239. }
  1240. if (!BytesReturned)
  1241. BytesReturned = &dwTmpBytesReturned;
  1242. if (!Required)
  1243. Required = &dwTmpBytesRequired;
  1244. try {
  1245. status = RmResourceTypeControl(monitor->Binding,
  1246. ResourceTypeName,
  1247. type->DllName,
  1248. ControlCode,
  1249. InBuffer,
  1250. InBufferSize,
  1251. OutBuffer,
  1252. OutBufferSize,
  1253. BytesReturned,
  1254. Required
  1255. );
  1256. }
  1257. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  1258. status = GetExceptionCode();
  1259. ClRtlLogPrint(LOG_NOISE,
  1260. "[FM] RmResourceTypeControl issued exception %1!u!\n",
  1261. status);
  1262. }
  1263. if ( type->Flags & RESTYPE_DEBUG_CONTROL_FUNC ) {
  1264. //
  1265. // Stop this resource monitor if it is a separate resource monitor.
  1266. //
  1267. CL_ASSERT( monitor->NotifyThread != NULL );
  1268. CL_ASSERT( monitor->Process != NULL );
  1269. FmpShutdownMonitor( monitor );
  1270. }
  1271. //
  1272. // If we successfully processed this request then re-fetch any changed
  1273. // data items.
  1274. //
  1275. if ( (status == ERROR_SUCCESS ||
  1276. (status == ERROR_RESOURCE_PROPERTIES_STORED)) &&
  1277. (ControlCode & CLCTL_MODIFY_MASK) ) {
  1278. FmpHandleResourceTypeControl( type,
  1279. ControlCode,
  1280. InBuffer,
  1281. InBufferSize,
  1282. OutBuffer,
  1283. OutBufferSize,
  1284. BytesReturned,
  1285. Required );
  1286. // ignore status
  1287. }
  1288. OmDereferenceObject(type);
  1289. return(status);
  1290. } // FmpRmResourceTypeControl
  1291. /****
  1292. @func BOOL | FmpPostProcessResourceControl| For core resource, if the control
  1293. code is handled successfully by the resource dll, the fm handles
  1294. any special handling in this function.
  1295. @parm PFM_RESOURCE | Resource | Supplies the resource to be controlled.
  1296. @parm DWORD| ControlCode | Supplies the control code that defines the
  1297. structure and action of the resource control.
  1298. Values of ControlCode between 0 and 0x10000000 are reserved
  1299. for future definition and use by Microsoft. All other values
  1300. are available for use by ISVs
  1301. @parm PUCHAR | InBuffer | Supplies a pointer to the input buffer to be passed
  1302. to the resource.
  1303. @parm DWORD | InBufferSize | Supplies the size, in bytes, of the data pointed
  1304. to by lpInBuffer..
  1305. @parm PUCHAR | OutBuffer | Supplies a pointer to the output buffer to be
  1306. filled in by the resource..
  1307. @parm DWORD | OutBufferSize | Supplies the size, in bytes, of the available
  1308. space pointed to by lpOutBuffer.
  1309. @parm LPDWORD | BytesReturned | Returns the number of bytes of lpOutBuffer
  1310. actually filled in by the resource..
  1311. @parm LPDWORD | Required | The number of bytes required if OutBuffer is not big enough.
  1312. @comm Called only for core resources.
  1313. @xref
  1314. ****/
  1315. DWORD
  1316. FmpPostProcessResourceControl(
  1317. IN PFM_RESOURCE Resource,
  1318. IN DWORD ControlCode,
  1319. IN PUCHAR InBuffer,
  1320. IN DWORD InBufferSize,
  1321. OUT PUCHAR OutBuffer,
  1322. IN DWORD OutBufferSize,
  1323. OUT LPDWORD BytesReturned,
  1324. OUT LPDWORD Required
  1325. )
  1326. {
  1327. DWORD dwStatus=ERROR_SUCCESS;
  1328. //handle cluster name change
  1329. switch(ControlCode)
  1330. {
  1331. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1332. {
  1333. LPWSTR pszClusterName=NULL;
  1334. PFM_RESTYPE pResType;
  1335. //need to check this only for core resources
  1336. if (Resource->ExFlags & CLUS_FLAG_CORE)
  1337. {
  1338. pResType = Resource->Type;
  1339. //SS: chk follow the name
  1340. if (!lstrcmpiW(OmObjectId(pResType), CLUS_RESTYPE_NAME_NETNAME))
  1341. {
  1342. dwStatus = FmNetNameParseProperties(InBuffer, InBufferSize,
  1343. &pszClusterName);
  1344. if (dwStatus == ERROR_SUCCESS && pszClusterName)
  1345. {
  1346. dwStatus = FmpRegUpdateClusterName(pszClusterName);
  1347. LocalFree(pszClusterName);
  1348. } else if ( dwStatus == ERROR_FILE_NOT_FOUND ) {
  1349. dwStatus = ERROR_SUCCESS;
  1350. }
  1351. }
  1352. }
  1353. break;
  1354. }
  1355. case CLUSCTL_RESOURCE_GET_CHARACTERISTICS:
  1356. {
  1357. LPDWORD pdwCharacteristics = ( LPDWORD ) OutBuffer;
  1358. //
  1359. // If the resource has dependencies, remove the quorum capable flag
  1360. //
  1361. if ( ( pdwCharacteristics != NULL ) &&
  1362. ( ( *BytesReturned ) == sizeof ( DWORD ) ) &&
  1363. ( ( *pdwCharacteristics ) & ( CLUS_CHAR_QUORUM ) ) )
  1364. {
  1365. FmpAcquireLocalResourceLock( Resource );
  1366. //
  1367. // The resource says it is quorum capable, however it has a dependency so it
  1368. // cant be a quorum.
  1369. //
  1370. if ( !IsListEmpty( &Resource->DependsOn ) )
  1371. {
  1372. //
  1373. // We will mask the quorum capable bit
  1374. //
  1375. *pdwCharacteristics = ( *pdwCharacteristics ) & ( ~CLUS_CHAR_QUORUM );
  1376. }
  1377. FmpReleaseLocalResourceLock( Resource );
  1378. }
  1379. break;
  1380. }
  1381. default:
  1382. break;
  1383. }
  1384. return(dwStatus);
  1385. }