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.

747 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. tree.c
  5. Abstract:
  6. Cluster resource tree management routines.
  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 TREE
  16. //
  17. // Global Data
  18. //
  19. //
  20. // Local function prototypes
  21. //
  22. BOOL
  23. FmpAddResourceToDependencyTree(
  24. IN PFM_RESOURCE Resource,
  25. IN PFM_DEPENDENCY_TREE Tree
  26. );
  27. BOOL
  28. FmpIsResourceInDependencyTree(
  29. IN PFM_RESOURCE Resource,
  30. IN PFM_DEPENDENCY_TREE Tree
  31. );
  32. DWORD
  33. FmpOfflineWaitingResourceTree(
  34. IN PFM_RESOURCE Resource,
  35. IN BOOL BringQuorumOffline
  36. );
  37. DWORD
  38. FmpRestartResourceTree(
  39. IN PFM_RESOURCE Resource
  40. )
  41. /*++
  42. Routine Description:
  43. This routine brings back part of a dependency tree, starting from the
  44. point of the last failure.
  45. Arguments:
  46. Resource - A pointer to the resource object that last failed and is
  47. restarting.
  48. Returns:
  49. ERROR_SUCCESS - if the request is successful.
  50. A Win32 error if the request fails.
  51. --*/
  52. {
  53. PLIST_ENTRY entry;
  54. PDEPENDENCY dependency;
  55. DWORD status;
  56. FmpAcquireLocalResourceLock( Resource );
  57. //
  58. // Tell the resource monitor to restart this resource if needed.
  59. //
  60. //
  61. // If the current state is not online and we want it to be online, then
  62. // bring it online.
  63. //
  64. if ( (Resource->State != ClusterResourceOnline) &&
  65. ((Resource->PersistentState == ClusterResourceOnline)) ) {
  66. ClRtlLogPrint(LOG_NOISE,
  67. "[FM] RestartResourceTree, Restart resource %1!ws!\n",
  68. OmObjectId(Resource));
  69. status = FmpOnlineResource(Resource, FALSE);
  70. }
  71. //
  72. // If this resource has any dependents, start them if needed.
  73. //
  74. for ( entry = Resource->ProvidesFor.Flink;
  75. entry != &(Resource->ProvidesFor);
  76. entry = entry->Flink
  77. )
  78. {
  79. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  80. //
  81. // Recursively restart the dependent resource.
  82. //
  83. ClRtlLogPrint(LOG_NOISE,
  84. "[FM] RestartResourceTree, %1!ws! depends on %2!ws!. Restart first\n",
  85. OmObjectId(dependency->DependentResource),
  86. OmObjectId(Resource));
  87. status = FmpRestartResourceTree(dependency->DependentResource);
  88. }
  89. FmpReleaseLocalResourceLock( Resource );
  90. return(ERROR_SUCCESS);
  91. } // FmpRestartResourceTree
  92. DWORD
  93. FmpOnlineWaitingTree(
  94. IN PFM_RESOURCE Resource
  95. )
  96. /*++
  97. Routine Description:
  98. This routine brings back part of a dependency tree, starting from the
  99. point of the last waiting resource.
  100. Arguments:
  101. Resource - A pointer to the resource object that is now online.
  102. Returns:
  103. ERROR_SUCCESS - if the request is successful.
  104. A Win32 error if the request fails.
  105. Notes:
  106. This routine is only called when the given resource is online.
  107. --*/
  108. {
  109. PLIST_ENTRY entry;
  110. PDEPENDENCY dependency;
  111. DWORD status;
  112. FmpAcquireLocalResourceLock( Resource );
  113. //if shutdown is in progress, dont bring resources online
  114. if (FmpShutdown)
  115. {
  116. //
  117. // If this resource has any dependents, and they are in online pending state
  118. // mark them as offline.
  119. //
  120. for ( entry = Resource->ProvidesFor.Flink;
  121. entry != &(Resource->ProvidesFor);
  122. entry = entry->Flink
  123. )
  124. {
  125. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  126. if ((dependency->DependentResource->State == ClusterResourceOnlinePending) &&
  127. (dependency->DependentResource->Flags & RESOURCE_WAITING))
  128. {
  129. //set the state of the all dependent resources to be offline again
  130. FmpPropagateResourceState(dependency->DependentResource, ClusterResourceOffline);
  131. //set the resource to be not waiting
  132. dependency->DependentResource->Flags &= ~RESOURCE_WAITING;
  133. //
  134. // Recursively set the state of all dependent resources to offline
  135. //
  136. ClRtlLogPrint(LOG_NOISE,
  137. "[FM] OnlineWaitingTree, %1!ws! (%2!u!) depends on %3!ws! (%4!u!). Shutdown others\n",
  138. OmObjectId(dependency->DependentResource),
  139. dependency->DependentResource->State,
  140. OmObjectId(Resource),
  141. Resource->State);
  142. status = FmpOnlineWaitingTree(dependency->DependentResource);
  143. }
  144. }
  145. //
  146. // Chittur Subbaraman (chitturs) - 11/5/1999
  147. //
  148. // Ensure that the resource state itself is made
  149. // ClusterResourceOffline if FM is asked to shutdown. Note that
  150. // this function is recursively called from below, not just from
  151. // the FM worker thread. So, if FM happened to be shutdown
  152. // while executing this function called from below, then we
  153. // offline all the dependent resources above, but not the
  154. // resource itself. This is done here.
  155. //
  156. if ( ( Resource->State == ClusterResourceOnlinePending ) &&
  157. ( Resource->Flags & RESOURCE_WAITING ) )
  158. {
  159. FmpPropagateResourceState( Resource, ClusterResourceOffline );
  160. Resource->Flags &= ~RESOURCE_WAITING;
  161. ClRtlLogPrint( LOG_NOISE,
  162. "[FM] OnlineWaitingTree, Resource <%1!ws!> forcibly brought offline...\n",
  163. OmObjectId( Resource ) );
  164. }
  165. FmpReleaseLocalResourceLock( Resource );
  166. return(ERROR_SUCCESS);
  167. }
  168. //for normal-non shutdown case
  169. //
  170. // Tell the resource monitor to restart this resource if needed.
  171. //
  172. //
  173. // If the current state is not online and it is waiting, then it probably
  174. // needs to be brought online now.
  175. //
  176. if ( (Resource->State == ClusterResourceOnlinePending) &&
  177. (Resource->Flags & RESOURCE_WAITING) ) {
  178. ClRtlLogPrint(LOG_NOISE,
  179. "[FM] FmpOnlineWaitingTree, Start resource %1!ws!\n",
  180. OmObjectId(Resource));
  181. Resource->State = ClusterResourceOffline;
  182. status = FmpOnlineResource(Resource, FALSE);
  183. if ( status == ERROR_SUCCESS ) {
  184. ClRtlLogPrint(LOG_NOISE,
  185. "[FM] FmpOnlineWaitingTree, online for resource %1!ws! succeeded, online the dependents\r\n",
  186. OmObjectId(Resource));
  187. }
  188. else if (status == ERROR_QUORUM_RESOURCE_ONLINE_FAILED)
  189. {
  190. PRESOURCE_ENUM pResourceEnum;
  191. LPWSTR pszNewId;
  192. ClRtlLogPrint(LOG_NOISE,
  193. "[FM] FmpOnlineWaitingTree, online for resource %1!ws!, status = %2!u!.\n",
  194. OmObjectId(Resource),
  195. status);
  196. pResourceEnum = (PRESOURCE_ENUM)LocalAlloc(LMEM_FIXED,
  197. sizeof(RESOURCE_ENUM));
  198. if (!pResourceEnum)
  199. {
  200. CL_UNEXPECTED_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  201. CsInconsistencyHalt(ERROR_NOT_ENOUGH_MEMORY);
  202. }
  203. pResourceEnum->EntryCount = 1;
  204. pResourceEnum->ContainsQuorum = (Resource == gpQuoResource);
  205. pszNewId = LocalAlloc(LMEM_FIXED, (lstrlenW(OmObjectId(Resource))+1) * sizeof(WCHAR));
  206. if ( pszNewId == NULL )
  207. {
  208. CsInconsistencyHalt(ERROR_NOT_ENOUGH_MEMORY);
  209. }
  210. lstrcpyW(pszNewId, OmObjectId(Resource));
  211. pResourceEnum->Entry[0].Id = pszNewId;
  212. pResourceEnum->Entry[0].State = Resource->PersistentState;
  213. FmpSubmitRetryOnline(pResourceEnum, NULL);
  214. FmpReleaseLocalResourceLock(Resource);
  215. LocalFree(pszNewId);
  216. LocalFree(pResourceEnum);
  217. return(status);
  218. }
  219. else
  220. {
  221. FmpReleaseLocalResourceLock( Resource );
  222. ClRtlLogPrint(LOG_NOISE,
  223. "[FM] FmpOnlineWaitingTree, online for resource %1!ws! returned = %2!u!.\n",
  224. OmObjectId(Resource),
  225. status);
  226. return(status);
  227. }
  228. }
  229. //
  230. // If this resource has any dependents, start them if needed.
  231. //
  232. for ( entry = Resource->ProvidesFor.Flink;
  233. entry != &(Resource->ProvidesFor);
  234. entry = entry->Flink
  235. )
  236. {
  237. dependency = CONTAINING_RECORD(entry, DEPENDENCY, ProviderLinkage);
  238. //
  239. // Recursively restart the dependent resource.
  240. //
  241. ClRtlLogPrint(LOG_NOISE,
  242. "[FM] OnlineWaitingTree, %1!ws! (%2!u!) depends on %3!ws! (%4!u!). Start now\n",
  243. OmObjectId(dependency->DependentResource),
  244. dependency->DependentResource->State,
  245. OmObjectId(Resource),
  246. Resource->State);
  247. status = FmpOnlineWaitingTree(dependency->DependentResource);
  248. }
  249. FmpReleaseLocalResourceLock( Resource );
  250. return(ERROR_SUCCESS);
  251. } // FmpOnlineWaitingTree
  252. DWORD
  253. FmpOfflineWaitingTree(
  254. IN PFM_RESOURCE Resource
  255. )
  256. {
  257. PLIST_ENTRY entry;
  258. PDEPENDENCY dependency;
  259. DWORD status;
  260. FmpAcquireLocalResourceLock( Resource );
  261. ClRtlLogPrint(LOG_NOISE,
  262. "[FM] FmpOfflineWaitingTree: Entry for <%1!ws!>.\n",
  263. OmObjectName( Resource ) );
  264. //
  265. // Tell the resource monitor to stop this resource if needed.
  266. // Make sure that the quorum resource is the last one brought offline
  267. //
  268. status = FmpOfflineWaitingResourceTree(Resource, FALSE);
  269. //the quorum resource might still need to come offline, if it is in this group
  270. if ((status == ERROR_SUCCESS) && (Resource->Group == gpQuoResource->Group))
  271. {
  272. ClRtlLogPrint(LOG_NOISE,
  273. "[FM] FmpOfflineWaitingTree: Quorum resource is in the same group,Moving list=0x%1!08lx!\n",
  274. Resource->Group->MovingList);
  275. //if a move is pending bring the quorum resource offline if all resources
  276. // in the group are offline
  277. // else dont bring the quorum resource offline
  278. // this is because we dont bring the quorum resource offline on group offlines
  279. if (Resource->Group->MovingList)
  280. {
  281. PLIST_ENTRY listEntry;
  282. DWORD BringQuorumOffline = TRUE;
  283. PFM_RESOURCE pGroupResource;
  284. for ( listEntry = Resource->Group->Contains.Flink;
  285. listEntry != &(Resource->Group->Contains);
  286. listEntry = listEntry->Flink )
  287. {
  288. pGroupResource = CONTAINING_RECORD(listEntry,
  289. FM_RESOURCE,
  290. ContainsLinkage );
  291. // if this is the quorum resource continue
  292. if (pGroupResource->QuorumResource)
  293. continue;
  294. //if the state is not offline or failed, dont try
  295. //and bring the quorum resource offline
  296. if ((pGroupResource->State != ClusterResourceOffline) &&
  297. (pGroupResource->State != ClusterResourceFailed))
  298. {
  299. ClRtlLogPrint(LOG_NOISE,
  300. "[FM] FmpOfflineWaitingTree: Quorum cannot be brought offline now for <%1!ws!>, state=%2!u!\n",
  301. OmObjectName(pGroupResource), pGroupResource->State);
  302. BringQuorumOffline = FALSE;
  303. break;
  304. }
  305. }
  306. if (BringQuorumOffline)
  307. {
  308. ClRtlLogPrint(LOG_NOISE,
  309. "[FM] FmpOfflineWaitingTree: bring quorum resource offline\n");
  310. status = FmpOfflineResource(gpQuoResource, FALSE);
  311. }
  312. }
  313. }
  314. FmpReleaseLocalResourceLock( Resource );
  315. ClRtlLogPrint(LOG_NOISE,
  316. "[FM] FmpOfflineWaitingTree: returned status %1!u! for <%2!ws!>.\n",
  317. status, OmObjectName( Resource ) );
  318. return(status);
  319. }
  320. DWORD
  321. FmpOfflineWaitingResourceTree(
  322. IN PFM_RESOURCE Resource,
  323. IN BOOL BringQuorumOffline
  324. )
  325. /*++
  326. Routine Description:
  327. This routine offlines a dependency tree, starting from the
  328. point of the last waiting resource.
  329. Arguments:
  330. Resource - A pointer to the resource object that is now offline.
  331. Returns:
  332. ERROR_SUCCESS - if the request is successful.
  333. A Win32 error if the request fails.
  334. Notes:
  335. This routine is only called when the given resource is offline.
  336. --*/
  337. {
  338. PLIST_ENTRY entry;
  339. PDEPENDENCY dependency;
  340. DWORD status = ERROR_SUCCESS;
  341. FmpAcquireLocalResourceLock( Resource );
  342. //
  343. // Tell the resource monitor to stop this resource if needed.
  344. //
  345. //
  346. // If the current state is not offline and it is waiting, then it probably
  347. // needs to be brought offline now.
  348. //
  349. if ((Resource->State == ClusterResourceOfflinePending) &&
  350. (Resource->Flags & RESOURCE_WAITING)) {
  351. ClRtlLogPrint(LOG_NOISE,
  352. "[FM] OfflineWaitingResourceTree, Offline resource %1!ws!\n",
  353. OmObjectId(Resource));
  354. Resource->State = ClusterResourceOnline;
  355. status = FmpOfflineResource(Resource, FALSE);
  356. if ( status == ERROR_IO_PENDING ) {
  357. FmpReleaseLocalResourceLock( Resource );
  358. ClRtlLogPrint(LOG_NOISE,
  359. "[FM] OfflineWaitingResourceTree, offline for resource %1!ws! returned pending.\n",
  360. OmObjectId(Resource));
  361. return(status);
  362. } else {
  363. ClRtlLogPrint(LOG_NOISE,
  364. "[FM] OfflineWaitingResourceTree, offline for resource %1!ws!, status = %2!u!.\n",
  365. OmObjectId(Resource),
  366. status);
  367. }
  368. }
  369. //
  370. // If this resource has any providers, stop them if needed.
  371. //
  372. for ( entry = Resource->DependsOn.Flink;
  373. entry != &(Resource->DependsOn);
  374. entry = entry->Flink
  375. )
  376. {
  377. dependency = CONTAINING_RECORD(entry, DEPENDENCY, DependentLinkage);
  378. if (dependency->ProviderResource->QuorumResource && !BringQuorumOffline)
  379. {
  380. continue;
  381. }
  382. //
  383. // Recursively offline the provider resource.
  384. //
  385. ClRtlLogPrint(LOG_NOISE,
  386. "[FM] OfflineWaitingResourceTree, %1!ws! provides for %2!ws!. Offline next.\n",
  387. OmObjectId(dependency->ProviderResource),
  388. OmObjectId(Resource));
  389. //dependency->ProviderResource->Flags |= RESOURCE_WAITING;
  390. status = FmpOfflineWaitingResourceTree(dependency->ProviderResource, BringQuorumOffline);
  391. }
  392. FmpReleaseLocalResourceLock( Resource );
  393. ClRtlLogPrint(LOG_NOISE,
  394. "[FM] OfflineWaitingResourceTree: Exit, status=%1!u! for <%2!ws!>.\n",
  395. status, OmObjectName( Resource ) );
  396. return(status);
  397. } // FmpOfflineWaitingResourceTree
  398. PFM_DEPENDENCY_TREE
  399. FmCreateFullDependencyTree(
  400. IN PFM_RESOURCE Resource
  401. )
  402. /*++
  403. Routine Description:
  404. Creates a full dependency tree containing all the resources
  405. that either depend on or provide for the supplied resource.
  406. Arguments:
  407. Resource - Supplies the resource
  408. Return Value:
  409. Pointer to the dependency tree.
  410. NULL if out of memory.
  411. --*/
  412. {
  413. PFM_DEPENDENCY_TREE Tree;
  414. BOOL Success;
  415. Tree = LocalAlloc(LMEM_FIXED, sizeof(FM_DEPENDENCY_TREE));
  416. if (Tree == NULL) {
  417. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  418. return(NULL);
  419. }
  420. InitializeListHead(&Tree->ListHead);
  421. //
  422. // Add the resources that the specified resource depends on.
  423. //
  424. Success = FmpAddResourceToDependencyTree(Resource, Tree);
  425. if (!Success) {
  426. LocalFree(Tree);
  427. return(NULL);
  428. } else {
  429. return(Tree);
  430. }
  431. }
  432. BOOL
  433. FmpIsResourceInDependencyTree(
  434. IN PFM_RESOURCE Resource,
  435. IN PFM_DEPENDENCY_TREE Tree
  436. )
  437. /*++
  438. Routine Description:
  439. Determines whether the specified resource is already in the
  440. dependency tree.
  441. Arguments:
  442. Resource - Supplies the resource to check for
  443. Tree - Supplies the dependency tree.
  444. Return Value:
  445. TRUE if the resource is in the dependency tree
  446. FALSE if the resource is not in the dependency tree
  447. --*/
  448. {
  449. PLIST_ENTRY ListEntry;
  450. PFM_DEPENDTREE_ENTRY Node;
  451. ListEntry = Tree->ListHead.Flink;
  452. while (ListEntry != &Tree->ListHead) {
  453. Node = CONTAINING_RECORD(ListEntry,
  454. FM_DEPENDTREE_ENTRY,
  455. ListEntry);
  456. if (Node->Resource == Resource) {
  457. return(TRUE);
  458. }
  459. ListEntry = ListEntry->Flink;
  460. }
  461. return(FALSE);
  462. }
  463. BOOL
  464. FmpAddResourceToDependencyTree(
  465. IN PFM_RESOURCE Resource,
  466. IN PFM_DEPENDENCY_TREE Tree
  467. )
  468. /*++
  469. Routine Description:
  470. Recursive worker for adding a resource and all resources that
  471. it depends on or provides for into the dependency tree.
  472. Arguments:
  473. Resource - Supplies the resource to add.
  474. Tree - Supplies the tree the resource should be added to.
  475. Return Value:
  476. TRUE - Successfully completed
  477. FALSE - out of memory
  478. --*/
  479. {
  480. PLIST_ENTRY ListEntry;
  481. PDEPENDENCY Dependency;
  482. PFM_DEPENDTREE_ENTRY Node;
  483. //
  484. // First check to see if we are already in the tree.
  485. // If so, we are done.
  486. //
  487. if (FmpIsResourceInDependencyTree(Resource, Tree)) {
  488. return(TRUE);
  489. }
  490. //
  491. // Recursively call ourselves for each entry we depend on.
  492. //
  493. ListEntry = Resource->DependsOn.Flink;
  494. while (ListEntry != &Resource->DependsOn) {
  495. Dependency = CONTAINING_RECORD(ListEntry,
  496. DEPENDENCY,
  497. DependentLinkage);
  498. ListEntry = ListEntry->Flink;
  499. //
  500. // Recursively add this resource to the tree
  501. //
  502. if (!FmpAddResourceToDependencyTree(Dependency->ProviderResource, Tree)) {
  503. return(FALSE);
  504. }
  505. }
  506. //
  507. // Add ourselves to the list now if we are not already in it.
  508. //
  509. if (!FmpIsResourceInDependencyTree(Resource, Tree)) {
  510. //
  511. // Add ourselves to the end of the list.
  512. //
  513. Node = LocalAlloc(LMEM_FIXED, sizeof(FM_DEPENDTREE_ENTRY));
  514. if (Node == NULL) {
  515. return(FALSE);
  516. }
  517. OmReferenceObject(Resource);
  518. Node->Resource = Resource;
  519. InsertTailList(&Tree->ListHead, &Node->ListEntry);
  520. }
  521. //
  522. // Now add the resources that this resource provides for to the list.
  523. //
  524. ListEntry = Resource->ProvidesFor.Flink;
  525. while (ListEntry != &Resource->ProvidesFor) {
  526. Dependency = CONTAINING_RECORD(ListEntry,
  527. DEPENDENCY,
  528. ProviderLinkage);
  529. ListEntry = ListEntry->Flink;
  530. //
  531. // Recursively add this resource to the tree
  532. //
  533. if (!FmpAddResourceToDependencyTree(Dependency->DependentResource, Tree)) {
  534. return(FALSE);
  535. }
  536. }
  537. return(TRUE);
  538. }
  539. VOID
  540. FmDestroyFullDependencyTree(
  541. IN PFM_DEPENDENCY_TREE Tree
  542. )
  543. /*++
  544. Routine Description:
  545. Destroys a dependency tree
  546. Arguments:
  547. Tree - Supplies the dependency tree
  548. Return Value:
  549. None
  550. --*/
  551. {
  552. PFM_DEPENDTREE_ENTRY Entry;
  553. PLIST_ENTRY ListEntry;
  554. while (!IsListEmpty(&Tree->ListHead)) {
  555. ListEntry = RemoveHeadList(&Tree->ListHead);
  556. Entry = CONTAINING_RECORD(ListEntry,
  557. FM_DEPENDTREE_ENTRY,
  558. ListEntry);
  559. OmDereferenceObject(Entry->Resource);
  560. LocalFree(Entry);
  561. }
  562. LocalFree(Tree);
  563. }