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.

1801 lines
55 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 = MmQuorumArbitrationTimeout * 4; // Wait for quorum online for twice the arb timeout
  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. // If the server died, then don't post any failure notifications since the resource monitor
  349. // crash detection thread will handle the failure.
  350. //
  351. if ( Status != RPC_S_SERVER_UNAVAILABLE )
  352. {
  353. //
  354. // rjain: for a synchronous resource we must post RESOURCE_FAILED event
  355. // so thatfailback policies are correctly followed
  356. // Also pretend that the old state to be online to actually force the
  357. // restart behaviour. See: FmpProcessResourceEvents.
  358. //
  359. OmReferenceObject(Resource);
  360. FmpPostWorkItem(FM_EVENT_RES_RESOURCE_FAILED,
  361. Resource,
  362. ClusterResourceOnline);
  363. Status = ERROR_RESMON_ONLINE_FAILED;
  364. }
  365. }
  366. FnExit:
  367. RELEASE_LOCK(gQuoLock);
  368. ClRtlLogPrint(LOG_NOISE,
  369. "[FM] FmpRmOnlineResource: Returning. Resource %1!ws!, state %2!u!, status %3!u!.\n",
  370. OmObjectId(Resource),
  371. Resource->State,
  372. Status);
  373. return (Status);
  374. } // FmpRmOnlineResource
  375. VOID
  376. FmpRmTerminateResource(
  377. PFM_RESOURCE Resource
  378. )
  379. /*++
  380. Routine Description:
  381. Terminates (immediately) a resource.
  382. Arguments:
  383. Resource - A pointer to the resource to terminate.
  384. Returns:
  385. None.
  386. --*/
  387. {
  388. DWORD dwOldBlockingFlag;
  389. //notify callbacks that need preprocessing before a resource is
  390. //brought offline-call this here since all resources may not go
  391. //thru the offline pending transition
  392. //SS - what if the resource never even goes to offline
  393. //pending state - then should we renotify the callbacks that it
  394. //is still online?
  395. OmNotifyCb(Resource, NOTIFY_RESOURCE_PREOFFLINE);
  396. //
  397. // Try to terminate the resource.
  398. //
  399. try {
  400. if (Resource->QuorumResource) {
  401. MMSetQuorumOwner( MM_INVALID_NODE, /* Block = */ FALSE, NULL );
  402. }
  403. RmTerminateResource(Resource->Id);
  404. // if FmpRmterminate was called for a failed resource, mark
  405. // the resource as Failed and not Offline.
  406. if (Resource->State == ClusterResourceFailed)
  407. {
  408. FmpCallResourceNotifyCb(Resource, ClusterResourceFailed);
  409. FmpPropagateResourceState( Resource, ClusterResourceFailed );
  410. }
  411. else
  412. {
  413. FmpCallResourceNotifyCb(Resource, ClusterResourceOffline);
  414. FmpPropagateResourceState( Resource, ClusterResourceOffline );
  415. }
  416. }
  417. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  418. DWORD code = GetExceptionCode();
  419. ClRtlLogPrint(LOG_NOISE,"[FM] RmTerminateResource issued exception %1!u!\n", code);
  420. return;
  421. }
  422. //if terminate was called during a pending state, this resource may be
  423. //blocking the quorum resource, decrement the blocking count
  424. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 0 );
  425. if ( dwOldBlockingFlag ) {
  426. ClRtlLogPrint(LOG_NOISE,
  427. "[FM] FmpRmTerminateResource: InterlockedDecrement on gdwQuoBlockingResources, Resource %1!ws!\n",
  428. OmObjectId(Resource));
  429. InterlockedDecrement(&gdwQuoBlockingResources);
  430. }
  431. ClRtlLogPrint(LOG_NOISE,
  432. "[FM] RmTerminateResource: %1!ws! is now offline\n",
  433. OmObjectId(Resource));
  434. return;
  435. } // FmpRmTerminateResource
  436. DWORD
  437. FmpRmOfflineResource(
  438. PFM_RESOURCE Resource
  439. )
  440. /*++
  441. Routine Description:
  442. Calls the Resource Monitor to take a resource offline.
  443. Arguments:
  444. Resource - A pointer to the resource to terminate.
  445. Returns:
  446. ERROR_SUCCESS if the request is successful.
  447. ERROR_IO_PENDING if the request is pending.
  448. Win32 error code on failure.
  449. --*/
  450. {
  451. CLUSTER_RESOURCE_STATE state;
  452. DWORD status;
  453. DWORD retry = MmQuorumArbitrationTimeout * 4; // Wait for quorum online for twice the arb timeout;
  454. #if DBG
  455. PLIST_ENTRY listEntry;
  456. #endif
  457. if ( Resource->State > ClusterResourcePending ) {
  458. ClRtlLogPrint(LOG_NOISE,"[FM] FmpRmOfflineResource: pending condition\n");
  459. return(ERROR_IO_PENDING);
  460. }
  461. CL_ASSERT(Resource->State != ClusterResourceOffline);
  462. #if DBG
  463. // everything else in the same group must be offline if this is the
  464. // quorum resource
  465. if ( Resource->QuorumResource ) {
  466. PFM_GROUP group = Resource->Group;
  467. PFM_RESOURCE resource;
  468. for ( listEntry = group->Contains.Flink;
  469. listEntry != &(group->Contains);
  470. listEntry = listEntry->Flink ) {
  471. resource = CONTAINING_RECORD(listEntry,
  472. FM_RESOURCE,
  473. ContainsLinkage );
  474. if ( (Resource != resource) &&
  475. (resource->State != ClusterResourceOffline) &&
  476. (resource->State != ClusterResourceFailed) &&
  477. (resource->State != ClusterResourceOfflinePending) ) {
  478. ClRtlLogPrint(LOG_NOISE,
  479. "[FM] RmOfflineResource: resource <%1!ws!> not offline when the quorum resource was shutting down.\n",
  480. OmObjectId(resource));
  481. CsInconsistencyHalt(ERROR_INVALID_STATE);
  482. }
  483. }
  484. } else {
  485. // this is not the quorum resource... but if the quorum resource is in
  486. // this group, it must not be offline!
  487. PFM_GROUP group = Resource->Group;
  488. PFM_RESOURCE resource;
  489. for ( listEntry = group->Contains.Flink;
  490. listEntry != &(group->Contains);
  491. listEntry = listEntry->Flink ) {
  492. resource = CONTAINING_RECORD(listEntry,
  493. FM_RESOURCE,
  494. ContainsLinkage );
  495. if ( (resource->QuorumResource) &&
  496. ((resource->State == ClusterResourceOffline) ||
  497. (resource->State == ClusterResourceFailed) ||
  498. ((resource->State == ClusterResourceOfflinePending) &&
  499. (!(resource->Flags & RESOURCE_WAITING))))) {
  500. ClRtlLogPrint(LOG_NOISE,
  501. "[FM] RmOfflineResource: quorum resource <%1!ws!> offline when resource <%2!ws!> was shutting down.\n",
  502. OmObjectId(resource),
  503. OmObjectId(Resource));
  504. CsInconsistencyHalt(ERROR_INVALID_STATE);
  505. }
  506. }
  507. }
  508. #endif
  509. state = ClusterResourceFailed;
  510. CheckQuorumState:
  511. //if this is the quorum resource acquire the quolock
  512. // For registry replication to work, the resource should
  513. // not be brought online while the quorum resource is offline
  514. // what do we do for fixquorum mode
  515. if (Resource->QuorumResource) {
  516. ACQUIRE_EXCLUSIVE_LOCK(gQuoLock);
  517. } else {
  518. ACQUIRE_SHARED_LOCK(gQuoLock);
  519. }
  520. //if it is not the quorum resource, check the state of the quorum resource
  521. if (!Resource->QuorumResource)
  522. {
  523. DWORD dwOldBlockingFlag;
  524. // check if the quorum resource is failed
  525. // we must exit from here and allow the recovery for the
  526. // quorum resource to kick in, which can only happen when
  527. // the group lock is released
  528. if (gpQuoResource->State == ClusterResourceFailed)
  529. {
  530. status = ERROR_QUORUM_RESOURCE_ONLINE_FAILED;
  531. CL_LOGFAILURE(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  532. RELEASE_LOCK(gQuoLock);
  533. FmpCallResourceNotifyCb(Resource, state);
  534. FmpPropagateResourceState( Resource, state );
  535. return(status);
  536. }
  537. // check if the quorum resource is online,
  538. // if the quorum resource is marked as waiting and offlinepending,
  539. // it is actually online.
  540. // if the quorum resource still needs to come online,
  541. // release the lock and wait
  542. if (((gpQuoResource->State != ClusterResourceOnline) &&
  543. ((gpQuoResource->State != ClusterResourceOfflinePending) ||
  544. (!(gpQuoResource->Flags & RESOURCE_WAITING))))
  545. && !CsNoQuorum)
  546. {
  547. RELEASE_LOCK(gQuoLock);
  548. ClRtlLogPrint(LOG_NOISE,
  549. "[FM] FmpRmOfflineResource: release quolock/group lock and wait on ghQuoOnlineEvent\r\n");
  550. WaitForSingleObject(ghQuoOnlineEvent, 500);
  551. if ( retry-- ) {
  552. Sleep(500);
  553. goto CheckQuorumState;
  554. }
  555. #if DBG
  556. if ( IsDebuggerPresent() ) {
  557. DbgBreakPoint();
  558. }
  559. #endif
  560. CL_LOGFAILURE(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  561. // Should we halt? What about the pre-online notification above?
  562. FmpCallResourceNotifyCb(Resource, state);
  563. FmpPropagateResourceState( Resource, state );
  564. return(ERROR_QUORUM_RESOURCE_ONLINE_FAILED);
  565. //CsInconsistencyHalt(ERROR_INVALID_STATE);
  566. }
  567. //
  568. // assume that we'll be pending... mark the resource as having
  569. // bumped the QuoBlockResource count.
  570. //
  571. ClRtlLogPrint(LOG_NOISE,
  572. "[FM] FmpRmOfflineResource: InterlockedIncrement on gdwQuoBlockingResources for resource %1!ws!\n",
  573. OmObjectId(Resource));
  574. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 1 );
  575. CL_ASSERT( dwOldBlockingFlag == 0 );
  576. InterlockedIncrement(&gdwQuoBlockingResources);
  577. }
  578. else
  579. {
  580. DWORD dwNumBlockingResources;
  581. //allow resources about 30 seconds to finish a pending
  582. //operation
  583. retry = 60;
  584. // This is for a quorum resource.
  585. CheckPendingResources:
  586. // this is the quorum resource, wait for other resources
  587. // to get out of their pending states
  588. // new resources are not allowed to queue since the quorum
  589. // lock is held exclusively
  590. dwNumBlockingResources =
  591. InterlockedCompareExchange( &gdwQuoBlockingResources, 0, 0 );
  592. if (dwNumBlockingResources)
  593. {
  594. ClRtlLogPrint(LOG_NOISE,
  595. "[FM] FmpRmOfflineResource: Quorum resource waiting to be brought offline-sleep.BlckingRes=%1!u!\r\n",
  596. dwNumBlockingResources);
  597. //sleep for 500 msec
  598. Sleep(500);
  599. if ( retry-- ) {
  600. goto CheckPendingResources;
  601. }
  602. //if some resources are still pending, go ahead and offline
  603. //the quorum, the checkpointing code will simply retry when
  604. //it finds that the quorum resource is not available
  605. #if 0
  606. if ( IsDebuggerPresent() ) {
  607. DbgBreakPoint();
  608. }
  609. #endif
  610. ClRtlLogPrint(LOG_NOISE,
  611. "[FM] FmpRmOfflineResource: Quorum resource is being brought offline despite %1!u! pending resources...\r\n",
  612. dwNumBlockingResources);
  613. }
  614. }
  615. //notify callbacks that need preprocessing before a resource is
  616. //brought offline-call this here since all resources may not go
  617. //thru the offline pending transition
  618. //SS - what if the resource never even goes to offline
  619. //pending state - then should we renotify the callbacks that it
  620. //is still online?
  621. state = ClusterResourceOffline;
  622. OmNotifyCb(Resource, NOTIFY_RESOURCE_PREOFFLINE);
  623. if (Resource->QuorumResource) {
  624. MMSetQuorumOwner( MM_INVALID_NODE, /* Block = */ TRUE, NULL );
  625. }
  626. status = RmOfflineResource( Resource->Id,
  627. (LPDWORD)&state // cast to quiet win64 warning
  628. );
  629. //
  630. // Cleanup for the non-quorum resource case
  631. // if the resource has gone offline, decrement the count
  632. //
  633. if ( !Resource->QuorumResource &&
  634. state < ClusterResourcePending ) {
  635. DWORD dwOldBlockingFlag;
  636. dwOldBlockingFlag = InterlockedExchange( &Resource->BlockingQuorum, 0 );
  637. if ( dwOldBlockingFlag ) {
  638. //
  639. // If the Transition Thread processed the request, then we can't
  640. // perform the decrement.
  641. //
  642. ClRtlLogPrint(LOG_NOISE,
  643. "[FM] FmpRmOfflineResource: InterlockedDecrement on gdwQuoBlockingResources for resource %1!ws!\n",
  644. OmObjectId(Resource));
  645. InterlockedDecrement(&gdwQuoBlockingResources);
  646. }
  647. }
  648. if (status == ERROR_SUCCESS)
  649. {
  650. //
  651. // If the new state is pending, then we must wait.
  652. //
  653. if ( state == ClusterResourceOffline ) {
  654. ClRtlLogPrint(LOG_NOISE,
  655. "[FM] FmpRmOfflineResource: %1!ws! is now offline\n",
  656. OmObjectId(Resource));
  657. } else if ( state == ClusterResourceOfflinePending ) {
  658. ClRtlLogPrint(LOG_NOISE,
  659. "[FM] FmpRmOfflineResource: %1!ws! offline pending\n",
  660. OmObjectId(Resource));
  661. status = ERROR_IO_PENDING;
  662. }
  663. }
  664. else
  665. {
  666. ClRtlLogPrint(LOG_NOISE,
  667. "[FM] FmpRmOfflineResource: RmOffline() for %1!ws! returned error %2!u!\r\n",
  668. OmObjectId(Resource), status);
  669. }
  670. FmpCallResourceNotifyCb(Resource, state);
  671. FmpPropagateResourceState( Resource, state );
  672. RELEASE_LOCK(gQuoLock);
  673. return(status);
  674. } // FmpRmOfflineResource
  675. DWORD
  676. FmpRmCloseResource(
  677. PFM_RESOURCE Resource
  678. )
  679. /*++
  680. Routine Description:
  681. Removes a resource from those being managed by the resource monitor.
  682. Arguments:
  683. Resource - The resource to remove.
  684. Returns:
  685. ERROR_SUCCESS if successful.
  686. Win32 error code on failure.
  687. --*/
  688. {
  689. DWORD status;
  690. PRESMON monitor;
  691. if (Resource->Id == 0) {
  692. //
  693. // This resource was never fully created.
  694. //
  695. return(ERROR_SUCCESS);
  696. }
  697. monitor = Resource->Monitor;
  698. Resource->Monitor = NULL;
  699. if ( Resource->QuorumResource ) {
  700. RmReleaseResource( Resource->Id );
  701. }
  702. try {
  703. RmCloseResource(&Resource->Id);
  704. }
  705. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  706. status = GetExceptionCode();
  707. ClRtlLogPrint(LOG_NOISE,"[FM] RmDestroyResource issued exception %1!u!\n", status);
  708. }
  709. if ( monitor &&
  710. Resource->Flags & RESOURCE_SEPARATE_MONITOR) {
  711. //
  712. // Shutdown the resource monitor as well.
  713. //
  714. ClRtlLogPrint(LOG_NOISE,
  715. "[FM] Shutting down separate resource monitor!\n");
  716. FmpShutdownMonitor(monitor);
  717. }
  718. Resource->Id = 0;
  719. return(ERROR_SUCCESS);
  720. } // FmpRmCloseResource
  721. DWORD
  722. FmpRmArbitrateResource(
  723. IN PFM_RESOURCE Resource
  724. )
  725. /*++
  726. Routine Description:
  727. Arbitrate for the given resource.
  728. Arguments:
  729. Resource - The resource to arbitrate.
  730. Return Value:
  731. ERROR_SUCCESS if successful.
  732. Win32 error code on failure.
  733. --*/
  734. {
  735. DWORD status = ERROR_SUCCESS;
  736. if (Resource->Id == 0) {
  737. //
  738. // This resource was never fully created.
  739. //
  740. return(ERROR_RESOURCE_NOT_AVAILABLE);
  741. }
  742. try {
  743. if (Resource->QuorumResource) {
  744. status = MMSetQuorumOwner( NmGetNodeId(NmLocalNode), /* Block = */ TRUE, NULL );
  745. }
  746. if (status == ERROR_SUCCESS) {
  747. status = RmArbitrateResource(Resource->Id);
  748. if (status != ERROR_SUCCESS) {
  749. if (Resource->QuorumResource) {
  750. MMSetQuorumOwner( MM_INVALID_NODE , /* Block = */ FALSE, NULL );
  751. }
  752. }
  753. }
  754. }
  755. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  756. status = GetExceptionCode();
  757. ClRtlLogPrint(LOG_NOISE,
  758. "[FM] RmArbitrateResource issued exception %1!u!\n",
  759. status);
  760. }
  761. return(status);
  762. } // FmpRmArbitrateResource
  763. DWORD
  764. FmpRmReleaseResource(
  765. IN PFM_RESOURCE Resource
  766. )
  767. /*++
  768. Routine Description:
  769. Release arbitration on a given resource.
  770. Arguments:
  771. Resource - The resource to release.
  772. Return Value:
  773. ERROR_SUCCESS if successful.
  774. Win32 error code on failure.
  775. --*/
  776. {
  777. DWORD status = ERROR_SUCCESS;
  778. if (Resource->Id == 0) {
  779. //
  780. // This resource was never fully created.
  781. //
  782. return(ERROR_RESOURCE_NOT_AVAILABLE);
  783. }
  784. try {
  785. status = RmReleaseResource(Resource->Id);
  786. }
  787. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  788. status = GetExceptionCode();
  789. ClRtlLogPrint(LOG_NOISE,
  790. "[FM] RmReleaseResource issued exception %1!u!\n",
  791. status);
  792. }
  793. return(status);
  794. } // FmpRmReleaseResource
  795. DWORD
  796. FmpRmFailResource(
  797. IN PFM_RESOURCE Resource
  798. )
  799. /*++
  800. Routine Description:
  801. Fail a given resource.
  802. Arguments:
  803. Resource - The resource to fail.
  804. Return Value:
  805. ERROR_SUCCESS if successful.
  806. Win32 error code on failure.
  807. --*/
  808. {
  809. if (Resource->QuorumResource) {
  810. MMSetQuorumOwner( MM_INVALID_NODE, /* Block = */ FALSE, NULL );
  811. }
  812. return(RmFailResource(Resource->Id));
  813. } // FmpRmFailResource
  814. DWORD FmpRmLoadResTypeDll(
  815. IN PFM_RESTYPE pResType
  816. )
  817. {
  818. PRESMON monitor;
  819. DWORD dwStatus;
  820. LPWSTR pszDebugPrefix;
  821. // Read the DebugControlFunction registry value.
  822. //
  823. if ( pResType->Flags & RESTYPE_DEBUG_CONTROL_FUNC ) {
  824. if ( pResType->DebugPrefix != NULL ) {
  825. pszDebugPrefix = pResType->DebugPrefix;
  826. } else {
  827. pszDebugPrefix = pResType->DebugPrefix;
  828. }
  829. monitor = FmpCreateMonitor(pszDebugPrefix, TRUE);
  830. if (monitor == NULL) {
  831. dwStatus = GetLastError();
  832. goto FnExit;
  833. }
  834. } else {
  835. CL_ASSERT(FmpDefaultMonitor != NULL);
  836. monitor = FmpDefaultMonitor;
  837. }
  838. dwStatus = RmLoadResourceTypeDll(monitor->Binding, OmObjectId(pResType),
  839. pResType->DllName);
  840. if (dwStatus != ERROR_SUCCESS)
  841. {
  842. ClRtlLogPrint(LOG_NOISE,
  843. "[FM] RmLoadResourceTypeDll call failed %1!u!\n",
  844. dwStatus);
  845. }
  846. if ( pResType->Flags & RESTYPE_DEBUG_CONTROL_FUNC )
  847. {
  848. //
  849. // Stop this resource monitor if it is a separate resource monitor.
  850. //
  851. CL_ASSERT( monitor->NotifyThread != NULL );
  852. CL_ASSERT( monitor->Process != NULL );
  853. FmpShutdownMonitor( monitor );
  854. }
  855. FnExit:
  856. return(dwStatus);
  857. }
  858. DWORD
  859. FmpRmChangeResourceParams(
  860. IN PFM_RESOURCE Resource
  861. )
  862. /*++
  863. Routine Description:
  864. Tell the resource monitor to change parameters for the given resource.
  865. Arguments:
  866. Resource - The resource to change parameters.
  867. Return Value:
  868. ERROR_SUCCESS if successful.
  869. A Win32 error code on failure.
  870. --*/
  871. {
  872. ClRtlLogPrint(LOG_NOISE,
  873. "[FM] FmpRmChangeResourceParams for resource <%1!ws!> called...\n",
  874. OmObjectId(Resource));
  875. return(RmChangeResourceParams(
  876. Resource->Id,
  877. Resource->LooksAlivePollInterval,
  878. Resource->IsAlivePollInterval,
  879. Resource->PendingTimeout ) );
  880. } // FmpRmChangeResourceParams
  881. DWORD
  882. FmpRmResourceControl(
  883. IN PFM_RESOURCE Resource,
  884. IN DWORD ControlCode,
  885. IN PUCHAR InBuffer,
  886. IN DWORD InBufferSize,
  887. OUT PUCHAR OutBuffer,
  888. IN DWORD OutBufferSize,
  889. OUT LPDWORD BytesReturned,
  890. OUT LPDWORD Required
  891. )
  892. /*++
  893. Routine Description:
  894. Provides for arbitrary communication and control between an application
  895. and a specific instance of a resource.
  896. Arguments:
  897. Resource - Supplies the resource to be controlled.
  898. ControlCode- Supplies the control code that defines the
  899. structure and action of the resource control.
  900. Values of ControlCode between 0 and 0x10000000 are reserved
  901. for future definition and use by Microsoft. All other values
  902. are available for use by ISVs
  903. InBuffer- Supplies a pointer to the input buffer to be passed
  904. to the resource.
  905. InBufferSize- Supplies the size, in bytes, of the data pointed
  906. to by lpInBuffer..
  907. OutBuffer- Supplies a pointer to the output buffer to be
  908. filled in by the resource..
  909. OutBufferSize- Supplies the size, in bytes, of the available
  910. space pointed to by lpOutBuffer.
  911. BytesReturned - Returns the number of bytes of lpOutBuffer
  912. actually filled in by the resource..
  913. Required - The number of bytes required if OutBuffer is not big enough.
  914. Return Value:
  915. ERROR_SUCCESS if successful
  916. Win32 error code otherwise
  917. --*/
  918. {
  919. DWORD status;
  920. DWORD Dummy;
  921. DWORD dwTmpBytesReturned;
  922. DWORD dwTmpBytesRequired;
  923. CLUSPROP_BUFFER_HELPER props;
  924. DWORD bufSize;
  925. CL_ASSERT( Resource->Group != NULL );
  926. //
  927. // Handle any requests that must be done without locks helds.
  928. //
  929. switch ( ControlCode ) {
  930. case CLUSCTL_RESOURCE_GET_NAME:
  931. if ( (Resource->Monitor == NULL) ||
  932. (OmObjectName( Resource ) == NULL) ) {
  933. return(ERROR_NOT_READY);
  934. }
  935. props.pb = OutBuffer;
  936. bufSize = (lstrlenW( OmObjectName( Resource ) ) + 1) * sizeof(WCHAR);
  937. if ( bufSize > OutBufferSize ) {
  938. *Required = bufSize;
  939. *BytesReturned = 0;
  940. status = ERROR_MORE_DATA;
  941. } else {
  942. lstrcpyW( props.psz, OmObjectName( Resource ) );
  943. *BytesReturned = bufSize;
  944. *Required = 0;
  945. status = ERROR_SUCCESS;
  946. }
  947. return(status);
  948. case CLUSCTL_RESOURCE_GET_ID:
  949. if ( (Resource->Monitor == NULL) ||
  950. (OmObjectId( Resource ) == NULL) ) {
  951. return(ERROR_NOT_READY);
  952. }
  953. props.pb = OutBuffer;
  954. bufSize = (lstrlenW( OmObjectId( Resource ) ) + 1) * sizeof(WCHAR);
  955. if ( bufSize > OutBufferSize ) {
  956. *Required = bufSize;
  957. *BytesReturned = 0;
  958. status = ERROR_MORE_DATA;
  959. } else {
  960. lstrcpyW( props.psz, OmObjectId( Resource ) );
  961. *BytesReturned = bufSize;
  962. *Required = 0;
  963. status = ERROR_SUCCESS;
  964. }
  965. return(status);
  966. case CLUSCTL_RESOURCE_GET_RESOURCE_TYPE:
  967. if ( (Resource->Monitor == NULL) ||
  968. (OmObjectId( Resource->Type ) == NULL) ) {
  969. return(ERROR_NOT_READY);
  970. }
  971. props.pb = OutBuffer;
  972. bufSize = (lstrlenW( OmObjectId( Resource->Type ) ) + 1) * sizeof(WCHAR);
  973. if ( bufSize > OutBufferSize ) {
  974. *Required = bufSize;
  975. *BytesReturned = 0;
  976. status = ERROR_MORE_DATA;
  977. } else {
  978. lstrcpyW( props.psz, OmObjectId( Resource->Type ) );
  979. *BytesReturned = bufSize;
  980. *Required = 0;
  981. status = ERROR_SUCCESS;
  982. }
  983. return(status);
  984. case CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT:
  985. case CLUSCTL_RESOURCE_DELETE_REGISTRY_CHECKPOINT:
  986. {
  987. LPWSTR RegistryKey;
  988. DWORD LastChar;
  989. //
  990. // Validate the input buffer
  991. //
  992. RegistryKey = (LPWSTR)InBuffer;
  993. LastChar = (InBufferSize/sizeof(WCHAR)) - 1;
  994. //
  995. // If the length of the input buffer is zero, or not a integral
  996. // number of WCHARs, or the last character is not NULL, the
  997. // request is invalid.
  998. //
  999. if ((InBufferSize < sizeof(WCHAR)) ||
  1000. ((InBufferSize % sizeof(WCHAR)) != 0) ||
  1001. (RegistryKey == NULL) ||
  1002. (RegistryKey[LastChar] != L'\0')) {
  1003. return(ERROR_INVALID_PARAMETER);
  1004. }
  1005. //
  1006. // If we are not the owner of this resource, don't let the set
  1007. // happen.
  1008. //
  1009. if (Resource->Group->OwnerNode != NmLocalNode) {
  1010. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  1011. }
  1012. //
  1013. // Call the checkpoint manager to perform the change.
  1014. //
  1015. if (ControlCode == CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT) {
  1016. status = CpAddRegistryCheckpoint(Resource, RegistryKey);
  1017. } else {
  1018. status = CpDeleteRegistryCheckpoint(Resource, RegistryKey);
  1019. }
  1020. }
  1021. *BytesReturned = 0;
  1022. return(status);
  1023. case CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT:
  1024. case CLUSCTL_RESOURCE_DELETE_CRYPTO_CHECKPOINT:
  1025. {
  1026. //
  1027. // If we are not the owner of this resource, don't let the set
  1028. // happen.
  1029. //
  1030. if (Resource->Group->OwnerNode != NmLocalNode) {
  1031. return(ERROR_HOST_NODE_NOT_RESOURCE_OWNER);
  1032. }
  1033. //
  1034. // Call the checkpoint manager to perform the change.
  1035. //
  1036. if (ControlCode == CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT) {
  1037. status = CpckAddCryptoCheckpoint(Resource, InBuffer, InBufferSize);
  1038. } else {
  1039. status = CpckDeleteCryptoCheckpoint(Resource, InBuffer, InBufferSize);
  1040. }
  1041. }
  1042. *BytesReturned = 0;
  1043. return(status);
  1044. case CLUSCTL_RESOURCE_GET_REGISTRY_CHECKPOINTS:
  1045. //
  1046. // Call the checkpoint manager to retrieve the list of checkpoints
  1047. //
  1048. status = CpGetRegistryCheckpoints(Resource,
  1049. OutBuffer,
  1050. OutBufferSize,
  1051. BytesReturned,
  1052. Required);
  1053. return(status);
  1054. case CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS:
  1055. //
  1056. // Call the checkpoint manager to retrieve the list of checkpoints
  1057. //
  1058. status = CpckGetCryptoCheckpoints(Resource,
  1059. OutBuffer,
  1060. OutBufferSize,
  1061. BytesReturned,
  1062. Required);
  1063. return(status);
  1064. case CLUSCTL_RESOURCE_UPGRADE_DLL:
  1065. status = FmpUpgradeResourceDLL(Resource,
  1066. ( LPWSTR ) InBuffer);
  1067. return(status);
  1068. case CLUSCTL_RESOURCE_INITIALIZE:
  1069. //
  1070. // Attempt to initialize the resource if it is not already initialized and return
  1071. // the initialization status to caller.
  1072. //
  1073. FmpAcquireLocalResourceLock( Resource );
  1074. if ( Resource->Monitor == NULL )
  1075. {
  1076. status = FmpInitializeResource( Resource, TRUE );
  1077. } else
  1078. {
  1079. status = ERROR_SUCCESS;
  1080. }
  1081. FmpReleaseLocalResourceLock( Resource );
  1082. return ( status );
  1083. default:
  1084. break;
  1085. }
  1086. OmReferenceObject( Resource );
  1087. FmpAcquireLocalResourceLock( Resource );
  1088. //if the resource has been marked for delete, then fail this call
  1089. if (!IS_VALID_FM_RESOURCE(Resource))
  1090. {
  1091. status = ERROR_RESOURCE_NOT_AVAILABLE;
  1092. FmpReleaseLocalResourceLock( Resource );
  1093. goto FnExit;
  1094. }
  1095. if ( Resource->Monitor == NULL ) {
  1096. status = FmpInitializeResource( Resource, TRUE );
  1097. if ( status != ERROR_SUCCESS ) {
  1098. FmpReleaseLocalResourceLock( Resource );
  1099. goto FnExit;
  1100. }
  1101. }
  1102. FmpReleaseLocalResourceLock( Resource );
  1103. //to take care of the output reference pointer which cannot be NULL.
  1104. if (!OutBuffer)
  1105. {
  1106. OutBuffer = (PUCHAR)&Dummy;
  1107. OutBufferSize = 0;
  1108. }
  1109. if (!BytesReturned)
  1110. BytesReturned = &dwTmpBytesReturned;
  1111. if (!Required)
  1112. Required = &dwTmpBytesRequired;
  1113. try {
  1114. status = RmResourceControl(Resource->Id,
  1115. ControlCode,
  1116. InBuffer,
  1117. InBufferSize,
  1118. OutBuffer,
  1119. OutBufferSize,
  1120. BytesReturned,
  1121. Required
  1122. );
  1123. }
  1124. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  1125. status = GetExceptionCode();
  1126. ClRtlLogPrint(LOG_NOISE,
  1127. "[FM] RmResourceControl issued exception %1!u!\n",
  1128. status);
  1129. }
  1130. if ( ( status != ERROR_SUCCESS ) &&
  1131. ( status != ERROR_MORE_DATA ) &&
  1132. ( status != ERROR_INVALID_FUNCTION ) )
  1133. {
  1134. ClRtlLogPrint(LOG_NOISE,
  1135. "[FM] FmpRmResourceControl: RmResourceControl returned %1!u! for resource %2!ws!, resid=%3!u!...\n",
  1136. status,
  1137. OmObjectId(Resource),
  1138. Resource->Id);
  1139. }
  1140. //for core resource we may need special handling
  1141. if ((status == ERROR_SUCCESS) || (status == ERROR_RESOURCE_PROPERTIES_STORED))
  1142. {
  1143. DWORD dwPostProcessStatus;
  1144. dwPostProcessStatus = FmpPostProcessResourceControl( Resource,
  1145. ControlCode,
  1146. InBuffer,
  1147. InBufferSize,
  1148. OutBuffer,
  1149. OutBufferSize,
  1150. BytesReturned,
  1151. Required );
  1152. if ( dwPostProcessStatus != ERROR_SUCCESS ) status = dwPostProcessStatus;
  1153. }
  1154. if ( ((status == ERROR_SUCCESS) ||
  1155. (status == ERROR_RESOURCE_PROPERTIES_STORED)) &&
  1156. (ControlCode & CLCTL_MODIFY_MASK) ) {
  1157. //
  1158. // We cannot just broadcast a cluster wide event... which is what
  1159. // we want to do. Unfortunately, this code path can be activated
  1160. // from within a GUM call, and we cannot call GUM back until we
  1161. // have dispatched the current event.
  1162. //
  1163. //
  1164. // Reference the resource object to keep it around while we
  1165. // perform the post notification. The dereference must occur
  1166. // in the post routine after the event posting.
  1167. //
  1168. OmReferenceObject( Resource );
  1169. FmpPostWorkItem( FM_EVENT_RESOURCE_PROPERTY_CHANGE,
  1170. Resource,
  1171. 0 );
  1172. }
  1173. FnExit:
  1174. OmDereferenceObject( Resource );
  1175. //FmpReleaseLocalResourceLock( Resource );
  1176. return(status);
  1177. } // FmpRmResourceControl
  1178. DWORD
  1179. FmpRmResourceTypeControl(
  1180. IN LPCWSTR ResourceTypeName,
  1181. IN DWORD ControlCode,
  1182. IN PUCHAR InBuffer,
  1183. IN DWORD InBufferSize,
  1184. OUT PUCHAR OutBuffer,
  1185. IN DWORD OutBufferSize,
  1186. OUT LPDWORD BytesReturned,
  1187. OUT LPDWORD Required
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. Provides for arbitrary communication and control between an application
  1192. and a specific instance of a resource type.
  1193. Arguments:
  1194. ResourceTypeName - Supplies the name of the resource type to be
  1195. controlled.
  1196. ControlCode- Supplies the control code that defines the
  1197. structure and action of the resource control.
  1198. Values of dwControlCode between 0 and 0x10000000 are reserved
  1199. for future definition and use by Microsoft. All other values
  1200. are available for use by ISVs
  1201. InBuffer- Supplies a pointer to the input buffer to be passed
  1202. to the resource.
  1203. InBufferSize- Supplies the size, in bytes, of the data pointed
  1204. to by lpInBuffer..
  1205. OutBuffer- Supplies a pointer to the output buffer to be
  1206. filled in by the resource..
  1207. OutBufferSize- Supplies the size, in bytes, of the available
  1208. space pointed to by lpOutBuffer.
  1209. BytesReturned - Returns the number of bytes of lpOutBuffer
  1210. actually filled in by the resource..
  1211. Required - The number of bytes required if OutBuffer is not big enough.
  1212. Return Value:
  1213. ERROR_SUCCESS if successful
  1214. Win32 error code otherwise
  1215. --*/
  1216. {
  1217. DWORD status;
  1218. PRESMON monitor;
  1219. PFM_RESTYPE type = NULL;
  1220. LPWSTR debugPrefix;
  1221. DWORD Dummy;
  1222. DWORD dwTmpBytesReturned;
  1223. DWORD dwTmpBytesRequired;
  1224. //
  1225. // Find the resource type structure associated with this resource type name
  1226. //
  1227. OmEnumObjects( ObjectTypeResType,
  1228. FmpReturnResourceType,
  1229. &type,
  1230. (PVOID)ResourceTypeName );
  1231. if ( type == NULL ) {
  1232. return(ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND);
  1233. }
  1234. //
  1235. // Read the DebugControlFunction registry value.
  1236. //
  1237. if ( type->Flags & RESTYPE_DEBUG_CONTROL_FUNC ) {
  1238. if ( type->DebugPrefix != NULL ) {
  1239. debugPrefix = type->DebugPrefix;
  1240. } else {
  1241. debugPrefix = type->DebugPrefix;
  1242. }
  1243. monitor = FmpCreateMonitor(debugPrefix, TRUE);
  1244. if (monitor == NULL) {
  1245. status = GetLastError();
  1246. goto FnExit;
  1247. }
  1248. } else {
  1249. CL_ASSERT(FmpDefaultMonitor != NULL);
  1250. monitor = FmpDefaultMonitor;
  1251. }
  1252. //to take care of the output reference pointer which cannot be NULL.
  1253. if (!OutBuffer)
  1254. {
  1255. OutBuffer = (PUCHAR)&Dummy;
  1256. OutBufferSize = 0;
  1257. }
  1258. if (!BytesReturned)
  1259. BytesReturned = &dwTmpBytesReturned;
  1260. if (!Required)
  1261. Required = &dwTmpBytesRequired;
  1262. try {
  1263. status = RmResourceTypeControl(monitor->Binding,
  1264. ResourceTypeName,
  1265. type->DllName,
  1266. ControlCode,
  1267. InBuffer,
  1268. InBufferSize,
  1269. OutBuffer,
  1270. OutBufferSize,
  1271. BytesReturned,
  1272. Required
  1273. );
  1274. }
  1275. except( FmpRmExceptionFilter(GetExceptionCode()) ) {
  1276. status = GetExceptionCode();
  1277. ClRtlLogPrint(LOG_NOISE,
  1278. "[FM] RmResourceTypeControl issued exception %1!u!\n",
  1279. status);
  1280. }
  1281. if ( type->Flags & RESTYPE_DEBUG_CONTROL_FUNC ) {
  1282. //
  1283. // Stop this resource monitor if it is a separate resource monitor.
  1284. //
  1285. CL_ASSERT( monitor->NotifyThread != NULL );
  1286. CL_ASSERT( monitor->Process != NULL );
  1287. FmpShutdownMonitor( monitor );
  1288. }
  1289. //
  1290. // If we successfully processed this request then re-fetch any changed
  1291. // data items.
  1292. //
  1293. if ( (status == ERROR_SUCCESS ||
  1294. (status == ERROR_RESOURCE_PROPERTIES_STORED)) &&
  1295. (ControlCode & CLCTL_MODIFY_MASK) ) {
  1296. FmpHandleResourceTypeControl( type,
  1297. ControlCode,
  1298. InBuffer,
  1299. InBufferSize,
  1300. OutBuffer,
  1301. OutBufferSize,
  1302. BytesReturned,
  1303. Required );
  1304. // ignore status
  1305. }
  1306. FnExit:
  1307. OmDereferenceObject(type);
  1308. return(status);
  1309. } // FmpRmResourceTypeControl
  1310. /****
  1311. @func BOOL | FmpPostProcessResourceControl| For core resource, if the control
  1312. code is handled successfully by the resource dll, the fm handles
  1313. any special handling in this function.
  1314. @parm PFM_RESOURCE | Resource | Supplies the resource to be controlled.
  1315. @parm DWORD| ControlCode | Supplies the control code that defines the
  1316. structure and action of the resource control.
  1317. Values of ControlCode between 0 and 0x10000000 are reserved
  1318. for future definition and use by Microsoft. All other values
  1319. are available for use by ISVs
  1320. @parm PUCHAR | InBuffer | Supplies a pointer to the input buffer to be passed
  1321. to the resource.
  1322. @parm DWORD | InBufferSize | Supplies the size, in bytes, of the data pointed
  1323. to by lpInBuffer..
  1324. @parm PUCHAR | OutBuffer | Supplies a pointer to the output buffer to be
  1325. filled in by the resource..
  1326. @parm DWORD | OutBufferSize | Supplies the size, in bytes, of the available
  1327. space pointed to by lpOutBuffer.
  1328. @parm LPDWORD | BytesReturned | Returns the number of bytes of lpOutBuffer
  1329. actually filled in by the resource..
  1330. @parm LPDWORD | Required | The number of bytes required if OutBuffer is not big enough.
  1331. @comm Called only for core resources.
  1332. @xref
  1333. ****/
  1334. DWORD
  1335. FmpPostProcessResourceControl(
  1336. IN PFM_RESOURCE Resource,
  1337. IN DWORD ControlCode,
  1338. IN PUCHAR InBuffer,
  1339. IN DWORD InBufferSize,
  1340. OUT PUCHAR OutBuffer,
  1341. IN DWORD OutBufferSize,
  1342. OUT LPDWORD BytesReturned,
  1343. OUT LPDWORD Required
  1344. )
  1345. {
  1346. DWORD dwStatus=ERROR_SUCCESS;
  1347. //handle cluster name change
  1348. switch(ControlCode)
  1349. {
  1350. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1351. {
  1352. LPWSTR pszClusterName=NULL;
  1353. PFM_RESTYPE pResType;
  1354. //need to check this only for core resources
  1355. if (Resource->ExFlags & CLUS_FLAG_CORE)
  1356. {
  1357. pResType = Resource->Type;
  1358. //SS: chk follow the name
  1359. if (!lstrcmpiW(OmObjectId(pResType), CLUS_RESTYPE_NAME_NETNAME))
  1360. {
  1361. dwStatus = FmNetNameParseProperties(InBuffer, InBufferSize,
  1362. &pszClusterName);
  1363. if (dwStatus == ERROR_SUCCESS && pszClusterName)
  1364. {
  1365. dwStatus = FmpRegUpdateClusterName(pszClusterName);
  1366. LocalFree(pszClusterName);
  1367. } else if ( dwStatus == ERROR_FILE_NOT_FOUND ) {
  1368. dwStatus = ERROR_SUCCESS;
  1369. }
  1370. }
  1371. }
  1372. break;
  1373. }
  1374. case CLUSCTL_RESOURCE_GET_CHARACTERISTICS:
  1375. {
  1376. LPDWORD pdwCharacteristics = ( LPDWORD ) OutBuffer;
  1377. //
  1378. // If the resource has dependencies, remove the quorum capable flag
  1379. //
  1380. if ( ( pdwCharacteristics != NULL ) &&
  1381. ( ( *BytesReturned ) == sizeof ( DWORD ) ) &&
  1382. ( ( *pdwCharacteristics ) & ( CLUS_CHAR_QUORUM ) ) )
  1383. {
  1384. FmpAcquireLocalResourceLock( Resource );
  1385. //
  1386. // The resource says it is quorum capable, however it has a dependency so it
  1387. // cant be a quorum.
  1388. //
  1389. if ( !IsListEmpty( &Resource->DependsOn ) )
  1390. {
  1391. //
  1392. // We will mask the quorum capable bit
  1393. //
  1394. *pdwCharacteristics = ( *pdwCharacteristics ) & ( ~CLUS_CHAR_QUORUM );
  1395. }
  1396. FmpReleaseLocalResourceLock( Resource );
  1397. }
  1398. break;
  1399. }
  1400. default:
  1401. break;
  1402. }
  1403. return(dwStatus);
  1404. }