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.

757 lines
24 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. worker.c
  5. Abstract:
  6. Failover Manager worker thread.
  7. Author:
  8. Mike Massa (mikemas) 12-Mar-1996
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "fmp.h"
  13. #define LOG_MODULE WORKER
  14. CL_QUEUE FmpWorkQueue;
  15. //
  16. // Local Data
  17. //
  18. HANDLE FmpWorkerThreadHandle = NULL;
  19. //
  20. // Forward routines
  21. //
  22. BOOL
  23. FmpAddNodeGroupCallback(
  24. IN PVOID Context1,
  25. IN PVOID Context2,
  26. IN PVOID Object,
  27. IN LPCWSTR Name
  28. );
  29. //
  30. // Local routines
  31. //
  32. DWORD
  33. FmpWorkerThread(
  34. IN LPVOID Ignored
  35. )
  36. {
  37. DWORD status;
  38. PLIST_ENTRY entry;
  39. PWORK_ITEM workItem;
  40. DWORD running = TRUE;
  41. PFM_RESOURCE resource;
  42. PFMP_POSSIBLE_NODE possibleNode;
  43. DWORD i;
  44. ClRtlLogPrint(LOG_NOISE,"[FM] Worker thread running\n");
  45. while ( running ) {
  46. //
  47. // Check the FM work queue for work items
  48. //
  49. entry = ClRtlRemoveHeadQueue(&FmpWorkQueue);
  50. if ( entry == NULL ) {
  51. return(ERROR_SUCCESS);
  52. }
  53. workItem = CONTAINING_RECORD(entry,
  54. WORK_ITEM,
  55. ListEntry);
  56. //
  57. // FM no longer cares about node up events, make sure
  58. // we aren't getting any queued.
  59. //
  60. switch ( workItem->Event ) {
  61. case FM_EVENT_SHUTDOWN:
  62. ClRtlLogPrint(LOG_NOISE,"[FM] WorkerThread terminating...\n");
  63. running = FALSE;
  64. break;
  65. case FM_EVENT_RESOURCE_ADDED:
  66. resource = workItem->Context1;
  67. if ( resource->Monitor == NULL ) {
  68. FmpAcquireLocalResourceLock( resource );
  69. //
  70. // Chittur Subbaraman (chitturs) - 8/12/99
  71. //
  72. // Make sure the resource is not marked for delete.
  73. //
  74. if ( IS_VALID_FM_RESOURCE( resource ) )
  75. {
  76. FmpInitializeResource( resource, TRUE );
  77. }
  78. FmpReleaseLocalResourceLock( resource );
  79. }
  80. OmDereferenceObject( resource );
  81. break;
  82. case FM_EVENT_RESOURCE_DELETED:
  83. //
  84. // Tell the resource monitor to cleanup the resource.
  85. //
  86. resource = workItem->Context1;
  87. FmpAcquireLocalResourceLock( resource );
  88. // Now that no remaining resource depends on this resource and
  89. // this resource does not depend on any other resources, we can
  90. // terminate it in the resource monitor if the resource is not
  91. // already offline or failed
  92. //
  93. if ( (resource->Group->OwnerNode == NmLocalNode) &&
  94. ((resource->State != ClusterResourceOffline) &&
  95. (resource->State != ClusterResourceFailed))) {
  96. FmpRmTerminateResource(resource);
  97. }
  98. status = FmpRmCloseResource(resource);
  99. ClRtlLogPrint( LOG_NOISE,
  100. "[FM] WorkItem, delete resource <%1!ws!> status %2!u!\n",
  101. OmObjectName(resource),
  102. status );
  103. FmpReleaseLocalResourceLock( resource );
  104. OmDereferenceObject(resource);
  105. break;
  106. case FM_EVENT_GROUP_FAILED:
  107. FmpHandleGroupFailure( workItem->Context1 );
  108. break;
  109. case FM_EVENT_NODE_ADDED:
  110. //
  111. // We need to add this node to every resource's possible owners
  112. // list and to each group's preferred owners list.
  113. //
  114. OmEnumObjects( ObjectTypeGroup,
  115. FmpAddNodeGroupCallback,
  116. workItem->Context1,
  117. NULL );
  118. break;
  119. case FM_EVENT_NODE_EVICTED:
  120. //
  121. // Enumerate all the resources types to remove any PossibleNode references.
  122. //
  123. OmEnumObjects(ObjectTypeResType,
  124. FmpEnumResTypeNodeEvict,
  125. workItem->Context1,
  126. NULL);
  127. //
  128. // Enumerate all the resources to remove any PossibleNode references.
  129. //
  130. OmEnumObjects(ObjectTypeResource,
  131. FmpEnumResourceNodeEvict,
  132. workItem->Context1,
  133. NULL);
  134. //
  135. // Enumerate all the groups to remove any PreferredNode references
  136. //
  137. OmEnumObjects(ObjectTypeGroup,
  138. FmpEnumGroupNodeEvict,
  139. workItem->Context1,
  140. NULL);
  141. //Now dereference the object
  142. OmDereferenceObject( workItem->Context1 );
  143. break;
  144. case FM_EVENT_CLUSTER_PROPERTY_CHANGE:
  145. //this is for the cluster name change
  146. FmpClusterEventPropHandler((PFM_RESOURCE)workItem->Context1);
  147. //Now dereference the object
  148. OmDereferenceObject( workItem->Context1 );
  149. break;
  150. case FM_EVENT_RESOURCE_CHANGE:
  151. // this is for a Add/Remove possible node request
  152. possibleNode = workItem->Context1;
  153. if ( possibleNode == NULL ) {
  154. break;
  155. }
  156. FmpRmResourceControl( possibleNode->Resource,
  157. possibleNode->ControlCode,
  158. (PUCHAR)OmObjectName(possibleNode->Node),
  159. ((lstrlenW(OmObjectName(possibleNode->Node)) + 1) * sizeof(WCHAR)),
  160. NULL,
  161. 0,
  162. NULL,
  163. NULL );
  164. // ignore status
  165. OmDereferenceObject( possibleNode->Resource );
  166. OmDereferenceObject( possibleNode->Node );
  167. LocalFree( possibleNode );
  168. break;
  169. case FM_EVENT_RESOURCE_PROPERTY_CHANGE:
  170. //
  171. // Generate a cluster wide event notification for this event.
  172. //
  173. ClusterWideEvent(
  174. CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE,
  175. workItem->Context1 // Resource
  176. );
  177. OmDereferenceObject( workItem->Context1 );
  178. break;
  179. case FM_EVENT_RES_RESOURCE_TRANSITION:
  180. FmpHandleResourceTransition(workItem->Context1, workItem->Context2);
  181. OmDereferenceObject(workItem->Context1);
  182. break;
  183. case FM_EVENT_RES_RESOURCE_FAILED:
  184. FmpProcessResourceEvents(workItem->Context1, ClusterResourceFailed,
  185. workItem->Context2);
  186. OmDereferenceObject( workItem->Context1 );
  187. break;
  188. case FM_EVENT_RES_RETRY_TIMER:
  189. resource= (PFM_RESOURCE)workItem->Context1;
  190. //Remove any pending watchdog timer
  191. if (resource->hTimer)
  192. {
  193. RemoveTimerActivity(resource->hTimer);
  194. resource->hTimer = NULL;
  195. }
  196. FmpAcquireLocalResourceLock(resource);
  197. // Check if this resource was deleted in the meanwhile,
  198. // or is not in failed state
  199. if( ( IS_VALID_FM_RESOURCE( resource ) ) &&
  200. ( resource->State == ClusterResourceFailed ) &&
  201. ( resource->PersistentState == ClusterResourceOnline ) )
  202. {
  203. // Check if we are the owner, if not ignore it
  204. if ( resource->Group->OwnerNode == NmLocalNode )
  205. {
  206. FmpProcessResourceEvents(resource,
  207. ClusterResourceFailed,
  208. ClusterResourceOnline);
  209. }
  210. }
  211. FmpReleaseLocalResourceLock(resource);
  212. OmDereferenceObject( workItem->Context1 );
  213. break;
  214. case FM_EVENT_INTERNAL_PROP_GROUP_STATE:
  215. FmpPropagateGroupState(workItem->Context1);
  216. OmDereferenceObject( workItem->Context1 );
  217. break;
  218. case FM_EVENT_INTERNAL_RETRY_ONLINE:
  219. {
  220. PFM_RESLIST_ONLINE_RETRY_INFO pFmOnlineRetryInfo;
  221. RemoveTimerActivity((HANDLE)workItem->Context2);
  222. pFmOnlineRetryInfo= workItem->Context1;
  223. CL_ASSERT(pFmOnlineRetryInfo);
  224. ClRtlLogPrint(LOG_NOISE,
  225. "[FM] FmpWorkerThread, retrying to online resourcelist\r\n");
  226. FmpOnlineResourceFromList(&(pFmOnlineRetryInfo->ResourceEnum));
  227. //Free memory
  228. for (i =0; i< pFmOnlineRetryInfo->ResourceEnum.EntryCount; i++)
  229. LocalFree( pFmOnlineRetryInfo->ResourceEnum.Entry[i].Id );
  230. LocalFree(pFmOnlineRetryInfo);
  231. break;
  232. }
  233. case FM_EVENT_INTERNAL_RESOURCE_CHANGE_PARAMS:
  234. {
  235. BOOL bIsValidRes = TRUE;
  236. //
  237. // Now tell the resource monitor about the changes.
  238. //
  239. status = ERROR_SUCCESS;
  240. resource = (PFM_RESOURCE)workItem->Context1;
  241. FmpAcquireLocalResourceLock( resource );
  242. //
  243. // Chittur Subbaraman (chitturs) - 8/12/99
  244. //
  245. // Check whether the resource is marked for delete.
  246. //
  247. if ( !IS_VALID_FM_RESOURCE( resource ) )
  248. {
  249. bIsValidRes = FALSE;
  250. }
  251. FmpReleaseLocalResourceLock( resource );
  252. if( bIsValidRes )
  253. {
  254. status = FmpRmChangeResourceParams( resource );
  255. }
  256. if ( status != ERROR_SUCCESS )
  257. {
  258. ClRtlLogPrint(LOG_UNUSUAL,
  259. "[FM] FmpWorkerThread, failed to change resource "
  260. "parameters for %1!ws!, error %2!u!.\n",
  261. OmObjectId(resource),
  262. status );
  263. }
  264. OmDereferenceObject(resource);
  265. break;
  266. }
  267. case FM_EVENT_INTERNAL_ONLINE_GROUPLIST:
  268. {
  269. PGROUP_ENUM pGroupList = NULL;
  270. ClRtlLogPrint(LOG_NOISE,
  271. "[FM] FmpWorkerThread : Processing Node Down Group List\n");
  272. pGroupList = workItem->Context1;
  273. FmpOnlineGroupList(pGroupList, TRUE);
  274. FmpDeleteEnum(pGroupList);
  275. break;
  276. }
  277. case FM_EVENT_RESOURCE_NAME_CHANGE:
  278. {
  279. //
  280. // Chittur Subbaraman (chitturs) - 6/29/99
  281. //
  282. // Added this new event to handle resource name change
  283. // notifications to resource DLLs.
  284. //
  285. PFM_RES_CHANGE_NAME pResChangeName = NULL;
  286. DWORD dwStatus = ERROR_SUCCESS;
  287. pResChangeName = ( PFM_RES_CHANGE_NAME ) workItem->Context1;
  288. dwStatus = FmpRmResourceControl( pResChangeName->pResource,
  289. CLUSCTL_RESOURCE_SET_NAME,
  290. (PUCHAR) pResChangeName->szNewResourceName,
  291. ((lstrlenW(pResChangeName->szNewResourceName) + 1) * sizeof(WCHAR)),
  292. NULL,
  293. 0,
  294. NULL,
  295. NULL );
  296. ClRtlLogPrint(LOG_NOISE,
  297. "[FM] Worker thread handling FM_EVENT_RESOURCE_NAME_CHANGE event - FmpRmResourceControl returns %1!u! for resource %2!ws!\n",
  298. dwStatus,
  299. OmObjectId(pResChangeName->pResource));
  300. OmDereferenceObject( pResChangeName->pResource );
  301. LocalFree( pResChangeName );
  302. break;
  303. }
  304. default:
  305. ClRtlLogPrint(LOG_NOISE,
  306. "[FM] WorkerThread, unrecognized event %1!u!\n",
  307. workItem->Event);
  308. }
  309. //
  310. // Free the work item.
  311. //
  312. LocalFree( workItem );
  313. }
  314. return(ERROR_SUCCESS);
  315. } // FmpWorkerThread
  316. VOID
  317. FmpProcessResourceEvents(
  318. IN PFM_RESOURCE pResource,
  319. IN CLUSTER_RESOURCE_STATE NewState,
  320. IN CLUSTER_RESOURCE_STATE OldState
  321. )
  322. /*++
  323. Routine Description:
  324. Arguments:
  325. Return Value:
  326. Comments: This should not call PropagateResourceState(). FmpProcessResourceEvents
  327. acquires the group lock. The quorum resource state must be propagated without holding
  328. the group lock. FmpPropagateResourceState() must be called by FmpHandleResourceTransition.
  329. There is a slight window between when the event is received in FmpHandleResourceTransition()
  330. and when the actions corresponding to those are carried out in FmpProcessResourceEvents().
  331. In this window, another opposing action like offline/online might occur. But we dont
  332. worry about it since if there are waiting resources on this resource, those actions
  333. are not carried out.
  334. --*/
  335. {
  336. DWORD Status;
  337. BOOL bQuoChangeLockHeld = FALSE;
  338. CL_ASSERT(pResource != NULL);
  339. ChkFMState:
  340. if (!FmpFMGroupsInited)
  341. {
  342. DWORD dwRetryCount = 50;
  343. ACQUIRE_SHARED_LOCK(gQuoChangeLock);
  344. //FmFormNewClusterPhaseProcessing is in progress
  345. if (FmpFMFormPhaseProcessing)
  346. {
  347. ClRtlLogPrint(LOG_CRITICAL,
  348. "[FM] FmpProcessResourceEvents, resource notification from quorum resource during phase processing,sleep and retry\n");
  349. RELEASE_LOCK(gQuoChangeLock);
  350. Sleep(500);
  351. if (dwRetryCount--)
  352. goto ChkFMState;
  353. else
  354. {
  355. ClRtlLogPrint(LOG_CRITICAL,
  356. "[FM] FmpProcessResourceEvents, waited for too long\n");
  357. //terminate the process
  358. CL_ASSERT(FALSE);
  359. }
  360. }
  361. else
  362. {
  363. bQuoChangeLockHeld = TRUE;
  364. }
  365. //this can only come from the quorum resource
  366. CL_ASSERT(pResource->QuorumResource);
  367. }
  368. FmpAcquireLocalResourceLock( pResource );
  369. //
  370. // Chittur Subbaraman (chitturs) - 8/12/99
  371. //
  372. // First check whether the resource has been marked for deletion. If
  373. // so, don't do anything. Note that this function is called from
  374. // the worker thread AFTER FmpHandleResourceTransition has propagated
  375. // the failed state of the resource. Now, after the propagation has
  376. // occurred, a client is free to delete the resource. So, when the
  377. // worker thread makes this function call, we need to check whether
  378. // the resource is deleted and reject the call. Note that this function
  379. // holds the resource lock on the owner node of the resource and so
  380. // is serialized with the FmDeleteResource call which is also executed
  381. // on the owner node of the resource with the lock held. So, the
  382. // following check will give us a consistent result.
  383. //
  384. if ( !IS_VALID_FM_RESOURCE( pResource ) )
  385. {
  386. ClRtlLogPrint(LOG_NOISE,
  387. "[FM] FmpProcessResourceEvents: Resource %1!ws! has already been deleted, returning...\n",
  388. OmObjectId(pResource));
  389. goto FnExit;
  390. }
  391. switch(NewState){
  392. case ClusterResourceFailed:
  393. //check the old resource state
  394. if (OldState == ClusterResourceOnline)
  395. {
  396. FmpHandleResourceFailure(pResource);
  397. }
  398. else if ((OldState == ClusterResourceOffline) ||
  399. (OldState == ClusterResourceOfflinePending))
  400. {
  401. FmpTerminateResource(pResource);
  402. if ( pResource->Group->OwnerNode == NmLocalNode )
  403. {
  404. Status = FmpOfflineWaitingTree(pResource);
  405. if ( Status != ERROR_IO_PENDING)
  406. {
  407. FmpSignalGroupWaiters( pResource->Group );
  408. }
  409. }
  410. }
  411. else if (OldState == ClusterResourceOnlinePending)
  412. {
  413. FmpHandleResourceFailure(pResource);
  414. FmpSignalGroupWaiters( pResource->Group );
  415. }
  416. break;
  417. case ClusterResourceOnline:
  418. if (OldState == ClusterResourceOnlinePending)
  419. {
  420. Status = FmpOnlineWaitingTree( pResource );
  421. if (Status != ERROR_IO_PENDING) {
  422. FmpSignalGroupWaiters( pResource->Group );
  423. }
  424. }
  425. break;
  426. case ClusterResourceOffline:
  427. if ((OldState == ClusterResourceOfflinePending) ||
  428. (OldState == ClusterResourceOffline))
  429. {
  430. Status = FmpOfflineWaitingTree(pResource);
  431. if ( Status != ERROR_IO_PENDING)
  432. {
  433. FmpSignalGroupWaiters( pResource->Group );
  434. }
  435. }
  436. break;
  437. }
  438. FnExit:
  439. FmpReleaseLocalResourceLock( pResource );
  440. if (bQuoChangeLockHeld) RELEASE_LOCK(gQuoChangeLock);
  441. return;
  442. }
  443. VOID
  444. FmpPostWorkItem(
  445. IN CLUSTER_EVENT Event,
  446. IN PVOID Context1,
  447. IN ULONG_PTR Context2
  448. )
  449. /*++
  450. Routine Description:
  451. Posts a work item event to the FM work queue.
  452. Arguments:
  453. Event - The event to post.
  454. Context1 - A pointer to some context. This context should be permanent
  455. in memory - i.e. it should not be deallocated when this call
  456. returns.
  457. Context2 - A pointer to additional context. This context should be
  458. permanent in memory - i.e. it should not be deallocated when this
  459. call returns.
  460. Returns:
  461. None.
  462. --*/
  463. {
  464. PWORK_ITEM workItem;
  465. workItem = LocalAlloc(LMEM_FIXED, sizeof(WORK_ITEM));
  466. if ( workItem == NULL ) {
  467. CsInconsistencyHalt(ERROR_NOT_ENOUGH_MEMORY);
  468. } else {
  469. workItem->Event = Event;
  470. workItem->Context1 = Context1;
  471. workItem->Context2 = Context2;
  472. //
  473. // Insert work item on queue and wake up the worker thread.
  474. //
  475. ClRtlInsertTailQueue(&FmpWorkQueue, &workItem->ListEntry);
  476. }
  477. } // FmpPostEvent
  478. DWORD
  479. FmpStartWorkerThread(
  480. VOID
  481. )
  482. {
  483. DWORD threadId;
  484. DWORD Status;
  485. //
  486. // Start up our worker thread
  487. //
  488. ClRtlLogPrint(LOG_NOISE,"[FM] Starting worker thread...\n");
  489. FmpWorkerThreadHandle = CreateThread(
  490. NULL,
  491. 0,
  492. FmpWorkerThread,
  493. NULL,
  494. 0,
  495. &threadId
  496. );
  497. if (FmpWorkerThreadHandle == NULL) {
  498. ClRtlLogPrint(LOG_NOISE,
  499. "[FM] Failed to start worker thread %1!u!\n",
  500. GetLastError()
  501. );
  502. return(GetLastError());
  503. }
  504. return(ERROR_SUCCESS);
  505. } // FmpStartWorkerThread
  506. BOOL
  507. FmpAddNodeGroupCallback(
  508. IN PVOID Context1,
  509. IN PVOID Context2,
  510. IN PVOID Object,
  511. IN LPCWSTR Name
  512. )
  513. /*++
  514. Routine Description:
  515. Enumeration callback for each group in the system when a new
  516. node is added to the cluster.
  517. The algorithm used here is to enumerate all the resources in
  518. this group. For each resource in the group that does not
  519. have an explicit "PreferredOwners" setting in the registry,
  520. the node is added as a PossibleNode. Finally, if the node
  521. was added as a possiblenode for each resource in the group,
  522. the node is added to the end of the preferredowners list for
  523. the group.
  524. Arguments:
  525. Context1 - Supplies the PNM_NODE of the new node.
  526. Context2 - Not used.
  527. Object - Supplies the group object.
  528. Name - Supplies the name of the group object.
  529. Return Value:
  530. TRUE
  531. --*/
  532. {
  533. PFM_RESOURCE Resource;
  534. PFM_GROUP Group;
  535. PNM_NODE Node;
  536. HDMKEY hKey;
  537. DWORD Status;
  538. PPREFERRED_ENTRY preferredEntry;
  539. PRESOURCE_ENUM ResourceEnum;
  540. DWORD i;
  541. Group = (PFM_GROUP)Object;
  542. Node = (PNM_NODE)Context1;
  543. FmpAcquireLocalGroupLock( Group );
  544. Status = FmpGetResourceList( &ResourceEnum,
  545. Group );
  546. FmpReleaseLocalGroupLock( Group );
  547. if ( Status != ERROR_SUCCESS ) {
  548. ClRtlLogPrint(LOG_NOISE,
  549. "[FM] AddNodeGroup, failed to get resource list for group %1!ws!, status %2!u!.\n",
  550. Name,
  551. Status );
  552. return(TRUE);
  553. }
  554. //
  555. // First fix up the resource info.
  556. //
  557. for ( i = 0; i < ResourceEnum->EntryCount; i++ ) {
  558. Resource = OmReferenceObjectById( ObjectTypeResource,
  559. ResourceEnum->Entry[i].Id );
  560. if ( Resource != NULL ) {
  561. FmpAcquireLocalResourceLock( Resource );
  562. //ss: we need to hold the resource lock as well
  563. //since that is the one that the update (FmpUpdateChangeResourceNode)
  564. // to remove and add nodes obtains and we must synchronize with it
  565. FmpAcquireResourceLock();
  566. Status = FmpFixupResourceInfo( Resource );
  567. FmpReleaseResourceLock();
  568. FmpReleaseLocalResourceLock( Resource );
  569. if ( Status == ERROR_SUCCESS ) {
  570. FmpRmResourceControl( Resource,
  571. CLUSCTL_RESOURCE_INSTALL_NODE,
  572. (PUCHAR)OmObjectName(Node),
  573. ((lstrlenW(OmObjectName(Node)) + 1) * sizeof(WCHAR)),
  574. NULL,
  575. 0,
  576. NULL,
  577. NULL );
  578. // Ignore status return
  579. ClusterEvent( CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE,
  580. Resource );
  581. } else {
  582. ClRtlLogPrint(LOG_UNUSUAL,
  583. "[FM] AddNodeGroup, failed to fixup info for resource %1!ws! when node was added!\n",
  584. OmObjectName( Resource ) );
  585. }
  586. OmDereferenceObject( Resource );
  587. } else {
  588. ClRtlLogPrint(LOG_NOISE,
  589. "[FM] AddNodeGroup, failed to find resource %1!ws! in group %2!ws!.\n",
  590. ResourceEnum->Entry[i].Id,
  591. Name );
  592. }
  593. }
  594. FmpDeleteResourceEnum( ResourceEnum );
  595. //
  596. // Now fix up the group information.
  597. //
  598. FmpAcquireLocalGroupLock( Group );
  599. Status = FmpFixupGroupInfo( Group );
  600. FmpReleaseLocalGroupLock( Group );
  601. if ( Status == ERROR_SUCCESS ) {
  602. ClusterEvent( CLUSTER_EVENT_GROUP_PROPERTY_CHANGE, Group );
  603. } else {
  604. ClRtlLogPrint(LOG_UNUSUAL,
  605. "[FM] AddNodeGroup, failed to fixup info for group %1!ws! when node was added, status %2!u!.\n",
  606. OmObjectName( Group ),
  607. Status );
  608. }
  609. return(TRUE);
  610. } // FmpAddNodeGroupCallback