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.

1596 lines
38 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. cnpnode.c
  5. Abstract:
  6. Node management routines for the Cluster Network Protocol.
  7. Author:
  8. Mike Massa (mikemas) July 29, 1996
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 07-29-96 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cnpnode.tmh"
  18. //
  19. // Global Node Data
  20. //
  21. PCNP_NODE * CnpNodeTable = NULL;
  22. LIST_ENTRY CnpDeletingNodeList = {NULL, NULL};
  23. #if DBG
  24. CN_LOCK CnpNodeTableLock = {0, 0};
  25. #else // DBG
  26. CN_LOCK CnpNodeTableLock = 0;
  27. #endif // DBG
  28. PCNP_NODE CnpLocalNode = NULL;
  29. BOOLEAN CnpIsNodeShutdownPending = FALSE;
  30. PKEVENT CnpNodeShutdownEvent = NULL;
  31. //
  32. // static data
  33. //
  34. //
  35. // Membership state table. This table is used to determine the validity
  36. // of membership state transitions. Row is current state; col is the state
  37. // to which a transition is made. Dead to Unconfigured is currently illegal,
  38. // but someday, if we support dynamically shrinking the size of the
  39. // cluster, we'd need to allow this transition.
  40. //
  41. typedef enum _MM_ACTION {
  42. MMActionIllegal = 0,
  43. MMActionWarning,
  44. MMActionNodeAlive,
  45. MMActionNodeDead,
  46. MMActionConfigured,
  47. MMActionUnconfigured
  48. } MM_ACTION;
  49. MM_ACTION MembershipStateTable[ClusnetNodeStateLastEntry][ClusnetNodeStateLastEntry] = {
  50. // Alive Joining Dead NC'ed
  51. /* Alive */ { MMActionWarning, MMActionIllegal, MMActionNodeDead, MMActionIllegal },
  52. /* Join */ { MMActionNodeAlive, MMActionIllegal, MMActionNodeDead, MMActionIllegal },
  53. /* Dead */ { MMActionNodeAlive, MMActionNodeAlive, MMActionWarning, MMActionIllegal },
  54. /* NC'ed */ { MMActionIllegal, MMActionIllegal, MMActionConfigured, MMActionIllegal }
  55. };
  56. #ifdef ALLOC_PRAGMA
  57. #pragma alloc_text(INIT, CnpLoadNodes)
  58. #pragma alloc_text(PAGE, CnpInitializeNodes)
  59. #endif // ALLOC_PRAGMA
  60. //
  61. // Private utility routines
  62. //
  63. VOID
  64. CnpDestroyNode(
  65. PCNP_NODE Node
  66. )
  67. /*++
  68. Notes:
  69. Called with no locks held. There should be no outstanding references
  70. to the target node.
  71. Synchronization with CnpCancelDeregisterNode() is achieved via
  72. CnpNodeTableLock.
  73. --*/
  74. {
  75. PLIST_ENTRY entry;
  76. CN_IRQL tableIrql;
  77. BOOLEAN setCleanupEvent = FALSE;
  78. CnVerifyCpuLockMask(
  79. 0, // Required
  80. 0xFFFFFFFF, // Forbidden
  81. 0 // Maximum
  82. );
  83. IF_CNDBG( CN_DEBUG_NODEOBJ )
  84. CNPRINT(("[CNP] Destroying node %u\n", Node->Id));
  85. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  86. //
  87. // Remove the node from the deleting list.
  88. //
  89. #if DBG
  90. {
  91. PCNP_NODE node = NULL;
  92. //
  93. // Verify that the node object is on the deleting list.
  94. //
  95. for (entry = CnpDeletingNodeList.Flink;
  96. entry != &CnpDeletingNodeList;
  97. entry = entry->Flink
  98. )
  99. {
  100. node = CONTAINING_RECORD(entry, CNP_NODE, Linkage);
  101. if (node == Node) {
  102. break;
  103. }
  104. }
  105. CnAssert(node == Node);
  106. }
  107. #endif // DBG
  108. RemoveEntryList(&(Node->Linkage));
  109. if (CnpIsNodeShutdownPending) {
  110. if (IsListEmpty(&CnpDeletingNodeList)) {
  111. setCleanupEvent = TRUE;
  112. }
  113. }
  114. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  115. if (Node->PendingDeleteIrp != NULL) {
  116. CnAcquireCancelSpinLock(&(Node->PendingDeleteIrp->CancelIrql));
  117. CnCompletePendingRequest(Node->PendingDeleteIrp, STATUS_SUCCESS, 0);
  118. //
  119. // The IoCancelSpinLock was released by CnCompletePendingRequest()
  120. //
  121. }
  122. CnFreePool(Node);
  123. if (setCleanupEvent) {
  124. IF_CNDBG(CN_DEBUG_CLEANUP) {
  125. CNPRINT(("[CNP] Setting node cleanup event.\n"));
  126. }
  127. KeSetEvent(CnpNodeShutdownEvent, 0, FALSE);
  128. }
  129. CnVerifyCpuLockMask(
  130. 0, // Required
  131. 0xFFFFFFFF, // Forbidden
  132. 0 // Maximum
  133. );
  134. return;
  135. } // CnpDestroyNode
  136. BOOLEAN
  137. CnpDeleteNode(
  138. IN PCNP_NODE Node,
  139. IN PVOID Unused,
  140. IN CN_IRQL NodeTableIrql
  141. )
  142. /*++
  143. Routine Description:
  144. Deletes a node object.
  145. Arguments:
  146. Node - A pointer to the node object to be deleted.
  147. Unused - An umused parameter.
  148. NodeTableIrql - The IRQL value at which the CnpNodeTable lock was
  149. acquired,
  150. Return Value:
  151. Returns TRUE if the CnpNodeTable lock is still held.
  152. Returns FALSE if the CnpNodeTable lock is released.
  153. Notes:
  154. Called with CnpNodeTable and node object locks held.
  155. Releases both locks.
  156. Conforms to the calling convention for PCNP_NODE_UPDATE_ROUTINE
  157. --*/
  158. {
  159. PLIST_ENTRY entry;
  160. PCNP_INTERFACE interface;
  161. PCNP_NETWORK network;
  162. CL_NODE_ID nodeId = Node->Id;
  163. CnVerifyCpuLockMask(
  164. (CNP_NODE_TABLE_LOCK | CNP_NODE_OBJECT_LOCK), // Required
  165. 0, // Forbidden
  166. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  167. );
  168. IF_CNDBG( CN_DEBUG_NODEOBJ )
  169. CNPRINT(("[CNP] Deleting node %u\n", nodeId));
  170. if (CnpLocalNode == Node) {
  171. CnAssert(CnLocalNodeId == Node->Id);
  172. CnpLocalNode = NULL;
  173. }
  174. //
  175. // Move the node to the deleting list.
  176. //
  177. CnpNodeTable[nodeId] = NULL;
  178. InsertTailList(&CnpDeletingNodeList, &(Node->Linkage));
  179. IF_CNDBG( CN_DEBUG_NODEOBJ )
  180. CNPRINT((
  181. "[CNP] Moved node %u to deleting list\n",
  182. nodeId
  183. ));
  184. CnReleaseLockFromDpc(&CnpNodeTableLock);
  185. Node->Irql = NodeTableIrql;
  186. //
  187. // From this point on, the cancel routine may run and
  188. // complete the irp.
  189. //
  190. Node->Flags |= CNP_NODE_FLAG_DELETING;
  191. CnTrace(
  192. CNP_NODE_DETAIL,
  193. CnpTraceDeleteNodeOfflineComm,
  194. "[CNP] Moving node %u comm state to offline.\n",
  195. Node->Id
  196. );
  197. Node->CommState = ClusnetNodeCommStateOffline;
  198. //
  199. // Delete all the node's interfaces.
  200. //
  201. IF_CNDBG( CN_DEBUG_NODEOBJ )
  202. CNPRINT((
  203. "[CNP] Deleting all interfaces on node %u\n",
  204. Node->Id
  205. ));
  206. while (!IsListEmpty(&(Node->InterfaceList))) {
  207. interface = CONTAINING_RECORD(
  208. Node->InterfaceList.Flink,
  209. CNP_INTERFACE,
  210. NodeLinkage
  211. );
  212. network = interface->Network;
  213. CnAcquireLockAtDpc(&(network->Lock));
  214. network->Irql = DISPATCH_LEVEL;
  215. CnpDeleteInterface(interface);
  216. //
  217. // The network object lock was released.
  218. //
  219. }
  220. //
  221. // Remove initial reference on node object. When the reference
  222. // count goes to zero, the node will be deleted. This releases
  223. // the node lock.
  224. //
  225. CnpDereferenceNode(Node);
  226. CnVerifyCpuLockMask(
  227. 0, // Required
  228. 0xFFFFFFFF, // Forbidden
  229. 0 // Maximum
  230. );
  231. return(FALSE);
  232. }
  233. //
  234. // CNP Internal Routines
  235. //
  236. VOID
  237. CnpWalkNodeTable(
  238. PCNP_NODE_UPDATE_ROUTINE UpdateRoutine,
  239. PVOID UpdateContext
  240. )
  241. {
  242. ULONG i;
  243. CN_IRQL tableIrql;
  244. PCNP_NODE node;
  245. BOOLEAN isNodeTableLockHeld;
  246. CnVerifyCpuLockMask(
  247. 0, // Required
  248. 0xFFFFFFFF, // Forbidden
  249. 0 // Maximum
  250. );
  251. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  252. CnAssert(CnMinValidNodeId != ClusterInvalidNodeId);
  253. CnAssert(CnMaxValidNodeId != ClusterInvalidNodeId);
  254. for (i=CnMinValidNodeId; i <= CnMaxValidNodeId; i++) {
  255. if (CnpNodeTable == NULL) {
  256. //
  257. // The node table has been freed since we
  258. // last held the node table lock.
  259. //
  260. break;
  261. }
  262. node = CnpNodeTable[i];
  263. if (node != NULL) {
  264. CnAcquireLockAtDpc(&(node->Lock));
  265. node->Irql = DISPATCH_LEVEL;
  266. isNodeTableLockHeld = (*UpdateRoutine)(
  267. node,
  268. UpdateContext,
  269. tableIrql
  270. );
  271. //
  272. // The node object lock was released.
  273. // The node table lock may also have been released.
  274. //
  275. if (!isNodeTableLockHeld) {
  276. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  277. }
  278. }
  279. }
  280. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  281. CnVerifyCpuLockMask(
  282. 0, // Required
  283. 0xFFFFFFFF, // Forbidden
  284. 0 // Maximum
  285. );
  286. return;
  287. } // CnpWalkNodeTable
  288. NTSTATUS
  289. CnpValidateAndFindNode(
  290. IN CL_NODE_ID NodeId,
  291. OUT PCNP_NODE * Node
  292. )
  293. {
  294. NTSTATUS status;
  295. CN_IRQL tableIrql;
  296. PCNP_NODE node = NULL;
  297. CnVerifyCpuLockMask(
  298. 0, // Required
  299. CNP_LOCK_RANGE, // Forbidden
  300. CNP_PRECEEDING_LOCK_RANGE // Maximum
  301. );
  302. if (CnIsValidNodeId(NodeId)) {
  303. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  304. if (CnpNodeTable != NULL &&
  305. CnpNodeTable[NodeId] != NULL) {
  306. node = CnpNodeTable[NodeId];
  307. CnAcquireLockAtDpc(&(node->Lock));
  308. CnReleaseLockFromDpc(&CnpNodeTableLock);
  309. node->Irql = tableIrql;
  310. *Node = node;
  311. CnVerifyCpuLockMask(
  312. CNP_NODE_OBJECT_LOCK, // Required
  313. CNP_NODE_TABLE_LOCK, // Forbidden
  314. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  315. );
  316. return(STATUS_SUCCESS);
  317. }
  318. else {
  319. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  320. }
  321. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  322. }
  323. else {
  324. status = STATUS_CLUSTER_INVALID_NODE;
  325. }
  326. CnVerifyCpuLockMask(
  327. 0, // Required
  328. CNP_LOCK_RANGE, // Forbidden
  329. CNP_PRECEEDING_LOCK_RANGE // Maximum
  330. );
  331. return(status);
  332. } // CnpValidateAndFindNode
  333. PCNP_NODE
  334. CnpLockedFindNode(
  335. IN CL_NODE_ID NodeId,
  336. IN CN_IRQL NodeTableIrql
  337. )
  338. /*++
  339. Routine Description:
  340. Searches the node table for a specified node object.
  341. Arguments:
  342. NodeId - The ID of the node object to locate.
  343. NodeTableIrql - The IRQL level at which the node table lock was
  344. acquired before calling this routine.
  345. Return Value:
  346. A pointer to the requested node object, if it exists.
  347. NULL otherwise.
  348. Notes:
  349. Called with CnpNodeTableLock held.
  350. Returns with CnpNodeTableLock released.
  351. If return value is non-NULL, returns with node object lock held.
  352. --*/
  353. {
  354. NTSTATUS status;
  355. CN_IRQL tableIrql;
  356. PCNP_NODE node;
  357. CnVerifyCpuLockMask(
  358. CNP_NODE_TABLE_LOCK, // Required
  359. 0, // Forbidden
  360. CNP_NODE_TABLE_LOCK_MAX // Maximum
  361. );
  362. node = CnpNodeTable[NodeId];
  363. if (node != NULL) {
  364. CnAcquireLockAtDpc(&(node->Lock));
  365. CnReleaseLockFromDpc(&CnpNodeTableLock);
  366. node->Irql = NodeTableIrql;
  367. CnVerifyCpuLockMask(
  368. CNP_NODE_OBJECT_LOCK, // Required
  369. CNP_NODE_TABLE_LOCK, // Forbidden
  370. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  371. );
  372. return(node);
  373. }
  374. CnReleaseLock(&CnpNodeTableLock, NodeTableIrql);
  375. CnVerifyCpuLockMask(
  376. 0, // Required
  377. (CNP_NODE_TABLE_LOCK | CNP_NODE_OBJECT_LOCK), // Forbidden
  378. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  379. );
  380. return(NULL);
  381. } // CnpLockedFindNode
  382. PCNP_NODE
  383. CnpFindNode(
  384. IN CL_NODE_ID NodeId
  385. )
  386. {
  387. CN_IRQL tableIrql;
  388. CnVerifyCpuLockMask(
  389. 0, // Required
  390. CNP_LOCK_RANGE, // Forbidden
  391. CNP_PRECEEDING_LOCK_RANGE // Maximum
  392. );
  393. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  394. if (CnpNodeTable == NULL) {
  395. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  396. return(NULL);
  397. }
  398. return(CnpLockedFindNode(NodeId, tableIrql));
  399. } // CnpFindNode
  400. VOID
  401. CnpDeclareNodeUnreachable(
  402. PCNP_NODE Node
  403. )
  404. /*++
  405. Notes:
  406. Called with node object lock held.
  407. --*/
  408. {
  409. CnVerifyCpuLockMask(
  410. CNP_NODE_OBJECT_LOCK, // Required
  411. 0, // Forbidden
  412. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  413. );
  414. if ( (Node->CommState == ClusnetNodeCommStateOnline) &&
  415. !CnpIsNodeUnreachable(Node)
  416. )
  417. {
  418. IF_CNDBG( CN_DEBUG_NODEOBJ )
  419. CNPRINT(("[CNP] Declaring node %u unreachable\n", Node->Id));
  420. Node->Flags |= CNP_NODE_FLAG_UNREACHABLE;
  421. }
  422. return;
  423. } // CnpDeclareNodeUnreachable
  424. VOID
  425. CnpDeclareNodeReachable(
  426. PCNP_NODE Node
  427. )
  428. /*++
  429. Notes:
  430. Called with node object lock held.
  431. --*/
  432. {
  433. CnVerifyCpuLockMask(
  434. CNP_NODE_OBJECT_LOCK, // Required
  435. 0, // Forbidden
  436. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  437. );
  438. if ( (Node->CommState == ClusnetNodeCommStateOnline) &&
  439. CnpIsNodeUnreachable(Node)
  440. )
  441. {
  442. IF_CNDBG( CN_DEBUG_NODEOBJ )
  443. CNPRINT(("[CNP] Declaring node %u reachable again\n", Node->Id));
  444. Node->Flags &= ~(CNP_NODE_FLAG_UNREACHABLE);
  445. }
  446. return;
  447. } // CnpDeclareNodeUnreachable
  448. VOID
  449. CnpReferenceNode(
  450. PCNP_NODE Node
  451. )
  452. /*++
  453. Notes:
  454. Called with node object lock held.
  455. --*/
  456. {
  457. CnVerifyCpuLockMask(
  458. CNP_NODE_OBJECT_LOCK, // Required
  459. 0, // Forbidden
  460. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  461. );
  462. CnAssert(Node->RefCount != 0xFFFFFFFF);
  463. Node->RefCount++;
  464. IF_CNDBG( CN_DEBUG_CNPREF )
  465. CNPRINT((
  466. "[CNP] Referencing node %u, new refcount %u\n",
  467. Node->Id,
  468. Node->RefCount
  469. ));
  470. return;
  471. } // CnpReferenceNode
  472. VOID
  473. CnpDereferenceNode(
  474. PCNP_NODE Node
  475. )
  476. /*++
  477. Notes:
  478. Called with node object lock held.
  479. Returns with node object lock released.
  480. --*/
  481. {
  482. BOOLEAN isDeleting = FALSE;
  483. ULONG newRefCount;
  484. CnVerifyCpuLockMask(
  485. CNP_NODE_OBJECT_LOCK, // Required
  486. 0, // Forbidden
  487. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  488. );
  489. CnAssert(Node->RefCount != 0);
  490. newRefCount = --(Node->RefCount);
  491. IF_CNDBG( CN_DEBUG_CNPREF )
  492. CNPRINT((
  493. "[CNP] Dereferencing node %u, new refcount %u\n",
  494. Node->Id,
  495. newRefCount
  496. ));
  497. CnReleaseLock(&(Node->Lock), Node->Irql);
  498. if (newRefCount > 0) {
  499. CnVerifyCpuLockMask(
  500. 0, // Required
  501. CNP_NODE_OBJECT_LOCK, // Forbidden
  502. CNP_NODE_TABLE_LOCK_MAX // Maximum
  503. );
  504. return;
  505. }
  506. CnpDestroyNode(Node);
  507. CnVerifyCpuLockMask(
  508. 0, // Required
  509. CNP_NODE_OBJECT_LOCK, // Forbidden
  510. CNP_NODE_TABLE_LOCK_MAX // Maximum
  511. );
  512. return;
  513. } // CnpDereferenceNode
  514. //
  515. // Cluster Transport Public Routines
  516. //
  517. NTSTATUS
  518. CnpLoadNodes(
  519. VOID
  520. )
  521. /*++
  522. Routine Description:
  523. Called when the Cluster Network driver is loading. Initializes
  524. static node-related data structures.
  525. Arguments:
  526. None.
  527. Return Value:
  528. None.
  529. --*/
  530. {
  531. NTSTATUS status;
  532. ULONG i;
  533. CnInitializeLock(&CnpNodeTableLock, CNP_NODE_TABLE_LOCK);
  534. InitializeListHead(&CnpDeletingNodeList);
  535. return(STATUS_SUCCESS);
  536. } // CnpLoadNodes
  537. NTSTATUS
  538. CnpInitializeNodes(
  539. VOID
  540. )
  541. /*++
  542. Routine Description:
  543. Called when the Cluster Network driver is being (re)initialized.
  544. Initializes dynamic node-related data structures.
  545. Arguments:
  546. None.
  547. Return Value:
  548. None.
  549. --*/
  550. {
  551. NTSTATUS status;
  552. ULONG i;
  553. PAGED_CODE();
  554. CnAssert(CnLocalNodeId != ClusterInvalidNodeId);
  555. CnAssert(CnMinValidNodeId != ClusterInvalidNodeId);
  556. CnAssert(CnMaxValidNodeId != ClusterInvalidNodeId);
  557. CnAssert(CnpNodeTable == NULL);
  558. CnAssert(CnpNodeShutdownEvent == NULL);
  559. CnAssert(IsListEmpty(&CnpDeletingNodeList));
  560. CnpNodeShutdownEvent = CnAllocatePool(sizeof(KEVENT));
  561. if (CnpNodeShutdownEvent == NULL) {
  562. return(STATUS_INSUFFICIENT_RESOURCES);
  563. }
  564. KeInitializeEvent(CnpNodeShutdownEvent, NotificationEvent, FALSE);
  565. CnpIsNodeShutdownPending = FALSE;
  566. CnpNodeTable = CnAllocatePool(
  567. (sizeof(PCNP_NODE) * (CnMaxValidNodeId + 1))
  568. );
  569. if (CnpNodeTable == NULL) {
  570. return(STATUS_INSUFFICIENT_RESOURCES);
  571. }
  572. RtlZeroMemory(CnpNodeTable, (sizeof(PCNP_NODE) * (CnMaxValidNodeId + 1)) );
  573. //
  574. // Register the local node.
  575. //
  576. status = CxRegisterNode(CnLocalNodeId);
  577. if (!NT_SUCCESS(status)) {
  578. return(status);
  579. }
  580. CnVerifyCpuLockMask(
  581. 0, // Required
  582. 0xFFFFFFFF, // Forbidden
  583. 0 // Maximum
  584. );
  585. return(STATUS_SUCCESS);
  586. } // CnpInitializeNodes
  587. VOID
  588. CnpShutdownNodes(
  589. VOID
  590. )
  591. /*++
  592. Routine Description:
  593. Called when a shutdown request is issued to the Cluster Network
  594. Driver. Deletes all node objects.
  595. Arguments:
  596. None.
  597. Return Value:
  598. None.
  599. --*/
  600. {
  601. ULONG i;
  602. CN_IRQL tableIrql;
  603. PCNP_NODE node;
  604. PCNP_NODE * table;
  605. BOOLEAN waitEvent = FALSE;
  606. NTSTATUS status;
  607. CnVerifyCpuLockMask(
  608. 0, // Required
  609. 0xFFFFFFFF, // Forbidden
  610. 0 // Maximum
  611. );
  612. if (CnpNodeShutdownEvent != NULL) {
  613. CnAssert(CnpIsNodeShutdownPending == FALSE);
  614. IF_CNDBG(CN_DEBUG_CLEANUP) {
  615. CNPRINT(("[CNP] Cleaning up nodes...\n"));
  616. }
  617. if (CnpNodeTable != NULL) {
  618. CnpWalkNodeTable(CnpDeleteNode, NULL);
  619. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  620. if (!IsListEmpty(&CnpDeletingNodeList)) {
  621. CnpIsNodeShutdownPending = TRUE;
  622. waitEvent = TRUE;
  623. }
  624. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  625. if (waitEvent) {
  626. IF_CNDBG(CN_DEBUG_CLEANUP) {
  627. CNPRINT(("[CNP] Node deletes are pending...\n"));
  628. }
  629. status = KeWaitForSingleObject(
  630. CnpNodeShutdownEvent,
  631. Executive,
  632. KernelMode,
  633. FALSE, // not alertable
  634. NULL // no timeout
  635. );
  636. CnAssert(status == STATUS_SUCCESS);
  637. }
  638. CnAssert(IsListEmpty(&CnpDeletingNodeList));
  639. IF_CNDBG(CN_DEBUG_CLEANUP) {
  640. CNPRINT(("[CNP] All nodes deleted.\n"));
  641. }
  642. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  643. if (CnpNodeTable != NULL) {
  644. CnFreePool(CnpNodeTable);
  645. CnpNodeTable = NULL;
  646. }
  647. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  648. }
  649. CnFreePool(CnpNodeShutdownEvent); CnpNodeShutdownEvent = NULL;
  650. IF_CNDBG(CN_DEBUG_CLEANUP) {
  651. CNPRINT(("[CNP] Nodes cleaned up.\n"));
  652. }
  653. }
  654. CnVerifyCpuLockMask(
  655. 0, // Required
  656. 0xFFFFFFFF, // Forbidden
  657. 0 // Maximum
  658. );
  659. return;
  660. } // CnpShutdownNodes
  661. NTSTATUS
  662. CxRegisterNode(
  663. CL_NODE_ID NodeId
  664. )
  665. {
  666. NTSTATUS status = STATUS_SUCCESS;
  667. CN_IRQL tableIrql;
  668. PCNP_NODE node = NULL;
  669. CnVerifyCpuLockMask(
  670. 0, // Required
  671. 0xFFFFFFFF, // Forbidden
  672. 0 // Maximum
  673. );
  674. if (CnIsValidNodeId(NodeId)) {
  675. //
  676. // Allocate and initialize a node object.
  677. //
  678. node = CnAllocatePool(sizeof(CNP_NODE));
  679. if (node == NULL) {
  680. return(STATUS_INSUFFICIENT_RESOURCES);
  681. }
  682. RtlZeroMemory(node, sizeof(CNP_NODE));
  683. CN_INIT_SIGNATURE(node, CNP_NODE_SIG);
  684. node->Id = NodeId;
  685. node->CommState = ClusnetNodeCommStateOffline;
  686. node->MMState = ClusnetNodeStateDead;
  687. node->RefCount = 1;
  688. //
  689. // NodeDownIssued is init'ed to true so that the first recv'd
  690. // heart beat msg will cause a node up event to be triggered
  691. //
  692. node->NodeDownIssued = TRUE;
  693. InitializeListHead(&(node->InterfaceList));
  694. CnInitializeLock(&(node->Lock), CNP_NODE_OBJECT_LOCK);
  695. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  696. //
  697. // Make sure the node table is present. If the node table
  698. // were not present (e.g. because of clusnet shutdown) the
  699. // clusnet state check should have failed in the dispatch
  700. // code, but this check is inexpensive and extra-thorough.
  701. //
  702. if (CnpNodeTable != NULL) {
  703. //
  704. // Make sure this isn't a duplicate registration
  705. //
  706. if (CnpNodeTable[NodeId] == NULL) {
  707. if (NodeId == CnLocalNodeId) {
  708. node->Flags |= CNP_NODE_FLAG_LOCAL;
  709. CnpLocalNode = node;
  710. }
  711. CnpNodeTable[NodeId] = node;
  712. status = STATUS_SUCCESS;
  713. }
  714. else {
  715. status = STATUS_CLUSTER_NODE_EXISTS;
  716. }
  717. }
  718. else {
  719. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  720. }
  721. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  722. if (!NT_SUCCESS(status)) {
  723. CnFreePool(node);
  724. }
  725. else {
  726. IF_CNDBG( CN_DEBUG_NODEOBJ )
  727. CNPRINT(("[CNP] Registered node %u\n", NodeId));
  728. CnTrace(
  729. CNP_NODE_DETAIL,
  730. CnpTraceRegisteredNode,
  731. "[CNP] Registered node %u.\n",
  732. NodeId
  733. );
  734. }
  735. }
  736. else {
  737. status = STATUS_CLUSTER_INVALID_NODE;
  738. }
  739. CnVerifyCpuLockMask(
  740. 0, // Required
  741. 0xFFFFFFFF, // Forbidden
  742. 0 // Maximum
  743. );
  744. return(status);
  745. } // CxRegisterNode
  746. VOID
  747. CxCancelDeregisterNode(
  748. PDEVICE_OBJECT DeviceObject,
  749. PIRP Irp
  750. )
  751. /*++
  752. Routine Description:
  753. Cancellation handler for DeregisterNode requests.
  754. Return Value:
  755. None.
  756. Notes:
  757. Called with cancel spinlock held.
  758. Returns with cancel spinlock released.
  759. --*/
  760. {
  761. PFILE_OBJECT fileObject;
  762. CN_IRQL cancelIrql = Irp->CancelIrql;
  763. PLIST_ENTRY entry;
  764. PCNP_NODE node;
  765. CnVerifyCpuLockMask(
  766. 0, // Required
  767. 0xFFFFFFFF, // Forbidden
  768. 0 // Maximum
  769. );
  770. CnMarkIoCancelLockAcquired();
  771. IF_CNDBG( CN_DEBUG_IRP )
  772. CNPRINT((
  773. "[CNP] Attempting to cancel DeregisterNode irp %p\n",
  774. Irp
  775. ));
  776. CnAssert(DeviceObject == CnDeviceObject);
  777. fileObject = CnBeginCancelRoutine(Irp);
  778. CnAcquireLockAtDpc(&CnpNodeTableLock);
  779. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  780. //
  781. // We can only complete the irp if we can find it stashed in a
  782. // deleting node object. The deleting node object could have
  783. // been destroyed and the IRP completed before we acquired the
  784. // CnpNetworkListLock.
  785. //
  786. for (entry = CnpDeletingNodeList.Flink;
  787. entry != &CnpDeletingNodeList;
  788. entry = entry->Flink
  789. )
  790. {
  791. node = CONTAINING_RECORD(entry, CNP_NODE, Linkage);
  792. if (node->PendingDeleteIrp == Irp) {
  793. IF_CNDBG( CN_DEBUG_IRP )
  794. CNPRINT((
  795. "[CNP] Found dereg irp on node %u\n",
  796. node->Id
  797. ));
  798. //
  799. // Found the Irp. Now take it away and complete it.
  800. //
  801. node->PendingDeleteIrp = NULL;
  802. CnReleaseLock(&CnpNodeTableLock, cancelIrql);
  803. CnAcquireCancelSpinLock(&(Irp->CancelIrql));
  804. CnEndCancelRoutine(fileObject);
  805. CnCompletePendingRequest(Irp, STATUS_CANCELLED, 0);
  806. //
  807. // IoCancelSpinLock was released by CnCompletePendingRequest().
  808. //
  809. CnVerifyCpuLockMask(
  810. 0, // Required
  811. 0xFFFFFFFF, // Forbidden
  812. 0 // Maximum
  813. );
  814. return;
  815. }
  816. }
  817. CnReleaseLock(&CnpNodeTableLock, cancelIrql);
  818. CnAcquireCancelSpinLock(&cancelIrql);
  819. CnEndCancelRoutine(fileObject);
  820. CnReleaseCancelSpinLock(cancelIrql);
  821. CnVerifyCpuLockMask(
  822. 0, // Required
  823. 0xFFFFFFFF, // Forbidden
  824. 0 // Maximum
  825. );
  826. return;
  827. } // CnpCancelApiDeregisterNode
  828. NTSTATUS
  829. CxDeregisterNode(
  830. CL_NODE_ID NodeId,
  831. PIRP Irp,
  832. PIO_STACK_LOCATION IrpSp
  833. )
  834. {
  835. NTSTATUS status;
  836. CN_IRQL cancelIrql;
  837. PCNP_NODE node = NULL;
  838. BOOLEAN isNodeTableLockHeld;
  839. CnVerifyCpuLockMask(
  840. 0, // Required
  841. 0xFFFFFFFF, // Forbidden
  842. 0 // Maximum
  843. );
  844. if (CnIsValidNodeId(NodeId)) {
  845. if (NodeId != CnLocalNodeId) {
  846. CnAcquireCancelSpinLock(&cancelIrql);
  847. CnAcquireLockAtDpc(&CnpNodeTableLock);
  848. if (CnpNodeTable != NULL &&
  849. CnpNodeTable[NodeId] != NULL) {
  850. node = CnpNodeTable[NodeId];
  851. status = CnMarkRequestPending(
  852. Irp,
  853. IrpSp,
  854. CxCancelDeregisterNode
  855. );
  856. if (status != STATUS_CANCELLED) {
  857. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  858. CnAssert(status == STATUS_SUCCESS);
  859. CnAcquireLockAtDpc(&(node->Lock));
  860. IF_CNDBG( CN_DEBUG_NODEOBJ )
  861. CNPRINT(("[CNP] Deregistering node %u\n", NodeId));
  862. //
  863. // Save a pointer to pending irp. Note this is protected
  864. // by the table lock, not the object lock.
  865. //
  866. node->PendingDeleteIrp = Irp;
  867. isNodeTableLockHeld = CnpDeleteNode(
  868. node,
  869. NULL,
  870. cancelIrql
  871. );
  872. if (isNodeTableLockHeld) {
  873. CnReleaseLock(&CnpNodeTableLock, cancelIrql);
  874. }
  875. CnVerifyCpuLockMask(
  876. 0, // Required
  877. 0xFFFFFFFF, // Forbidden
  878. 0 // Maximum
  879. );
  880. return(STATUS_PENDING);
  881. }
  882. }
  883. else {
  884. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  885. }
  886. CnReleaseLockFromDpc(&CnpNodeTableLock);
  887. CnReleaseCancelSpinLock(cancelIrql);
  888. }
  889. else {
  890. status = STATUS_CLUSTER_INVALID_REQUEST;
  891. }
  892. }
  893. else {
  894. status = STATUS_CLUSTER_INVALID_NODE;
  895. }
  896. CnVerifyCpuLockMask(
  897. 0, // Required
  898. 0xFFFFFFFF, // Forbidden
  899. 0 // Maximum
  900. );
  901. return(status);
  902. } // CxDeregisterNode
  903. NTSTATUS
  904. CxOnlineNodeComm(
  905. CL_NODE_ID NodeId
  906. )
  907. {
  908. NTSTATUS status;
  909. PCNP_NODE node;
  910. CnVerifyCpuLockMask(
  911. 0, // Required
  912. 0xFFFFFFFF, // Forbidden
  913. 0 // Maximum
  914. );
  915. status = CnpValidateAndFindNode(NodeId, &node);
  916. if (status == STATUS_SUCCESS) {
  917. if (node->CommState == ClusnetNodeCommStateOffline) {
  918. IF_CNDBG( CN_DEBUG_NODEOBJ )
  919. CNPRINT((
  920. "[CNP] Moving node %u comm state to online.\n",
  921. NodeId
  922. ));
  923. CnTrace(
  924. CNP_NODE_DETAIL,
  925. CnpTraceOnlineNodeComm,
  926. "[CNP] Moving node %u comm state to online.\n",
  927. NodeId
  928. );
  929. node->CommState = ClusnetNodeCommStateOnline;
  930. CnpWalkInterfacesOnNode(node, CnpResetAndOnlinePendingInterface);
  931. }
  932. else {
  933. status = STATUS_CLUSTER_NODE_ALREADY_UP;
  934. }
  935. CnReleaseLock(&(node->Lock), node->Irql);
  936. }
  937. CnVerifyCpuLockMask(
  938. 0, // Required
  939. 0xFFFFFFFF, // Forbidden
  940. 0 // Maximum
  941. );
  942. return(status);
  943. } // CxOnlineNodeComm
  944. NTSTATUS
  945. CxOfflineNodeComm(
  946. IN CL_NODE_ID NodeId,
  947. IN PIRP Irp,
  948. IN PIO_STACK_LOCATION IrpSp
  949. )
  950. /*++
  951. Notes:
  952. --*/
  953. {
  954. PCNP_NODE node;
  955. NTSTATUS status;
  956. CnVerifyCpuLockMask(
  957. 0, // Required
  958. 0xFFFFFFFF, // Forbidden
  959. 0 // Maximum
  960. );
  961. status = CnpValidateAndFindNode(NodeId, &node);
  962. if (status == STATUS_SUCCESS) {
  963. if (node->CommState == ClusnetNodeCommStateOnline) {
  964. IF_CNDBG( CN_DEBUG_NODEOBJ )
  965. CNPRINT((
  966. "[CNP] Moving node %u comm state to offline.\n",
  967. NodeId
  968. ));
  969. CnTrace(
  970. CNP_NODE_DETAIL,
  971. CnpTraceOfflineNodeComm,
  972. "[CNP] Moving node %u comm state to offline.\n",
  973. NodeId
  974. );
  975. node->CommState = ClusnetNodeCommStateOffline;
  976. CnpWalkInterfacesOnNode(node, CnpOfflineInterfaceWrapper);
  977. }
  978. else {
  979. status = STATUS_CLUSTER_NODE_ALREADY_DOWN;
  980. }
  981. CnReleaseLock(&(node->Lock), node->Irql);
  982. }
  983. else {
  984. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  985. }
  986. CnVerifyCpuLockMask(
  987. 0, // Required
  988. 0xFFFFFFFF, // Forbidden
  989. 0 // Maximum
  990. );
  991. return(status);
  992. } // CxOfflineNodeComm
  993. NTSTATUS
  994. CxGetNodeCommState(
  995. IN CL_NODE_ID NodeId,
  996. OUT PCLUSNET_NODE_COMM_STATE CommState
  997. )
  998. {
  999. NTSTATUS status;
  1000. PCNP_NODE node;
  1001. CnVerifyCpuLockMask(
  1002. 0, // Required
  1003. 0xFFFFFFFF, // Forbidden
  1004. 0 // Maximum
  1005. );
  1006. status = CnpValidateAndFindNode(NodeId, &node);
  1007. if (status == STATUS_SUCCESS) {
  1008. if (CnpIsNodeUnreachable(node)) {
  1009. CnTrace(
  1010. CNP_NODE_DETAIL,
  1011. CnpTraceGetNodeCommStateUnreach,
  1012. "[CNP] Returning node %u comm state offline "
  1013. "because node is unreachable.",
  1014. NodeId
  1015. );
  1016. *CommState = ClusnetNodeCommStateUnreachable;
  1017. }
  1018. else {
  1019. CnTrace(
  1020. CNP_NODE_DETAIL,
  1021. CnpTraceGetNodeCommState,
  1022. "[CNP] Returning node %u comm state %u.",
  1023. NodeId, node->CommState
  1024. );
  1025. *CommState = node->CommState;
  1026. }
  1027. CnReleaseLock(&(node->Lock), node->Irql);
  1028. }
  1029. CnVerifyCpuLockMask(
  1030. 0, // Required
  1031. 0xFFFFFFFF, // Forbidden
  1032. 0 // Maximum
  1033. );
  1034. return(status);
  1035. } // CxGetNodeCommState
  1036. NTSTATUS
  1037. CxGetNodeMembershipState(
  1038. IN CL_NODE_ID NodeId,
  1039. OUT PCLUSNET_NODE_STATE State
  1040. )
  1041. {
  1042. NTSTATUS status;
  1043. PCNP_NODE node;
  1044. CnVerifyCpuLockMask(
  1045. 0, // Required
  1046. 0xFFFFFFFF, // Forbidden
  1047. 0 // Maximum
  1048. );
  1049. status = CnpValidateAndFindNode(NodeId, &node);
  1050. if (status == STATUS_SUCCESS) {
  1051. *State = node->MMState;
  1052. CnReleaseLock(&(node->Lock), node->Irql);
  1053. }
  1054. CnVerifyCpuLockMask(
  1055. 0, // Required
  1056. 0xFFFFFFFF, // Forbidden
  1057. 0 // Maximum
  1058. );
  1059. return(status);
  1060. } // CxGetNodeMembershipState
  1061. NTSTATUS
  1062. CxSetNodeMembershipState(
  1063. IN CL_NODE_ID NodeId,
  1064. IN CLUSNET_NODE_STATE State
  1065. )
  1066. {
  1067. NTSTATUS status;
  1068. PCNP_NODE node;
  1069. MM_ACTION MMAction;
  1070. BOOLEAN nodeLockAcquired = FALSE;
  1071. CnVerifyCpuLockMask(
  1072. 0, // Required
  1073. 0xFFFFFFFF, // Forbidden
  1074. 0 // Maximum
  1075. );
  1076. status = CnpValidateAndFindNode(NodeId, &node);
  1077. if (status == STATUS_SUCCESS) {
  1078. nodeLockAcquired = TRUE;
  1079. IF_CNDBG( CN_DEBUG_MMSTATE ) {
  1080. CNPRINT(("[Clusnet] Changing Node %u (%08X) MMState from %u to %u\n",
  1081. node->Id, node, node->MMState, State));
  1082. }
  1083. //
  1084. // look up the routine to call (if any) based on the old and new
  1085. // state
  1086. //
  1087. switch ( MembershipStateTable[ node->MMState ][ State ] ) {
  1088. case MMActionIllegal:
  1089. status = STATUS_CLUSTER_INVALID_REQUEST;
  1090. break;
  1091. case MMActionWarning:
  1092. //
  1093. // warning about null transitions
  1094. //
  1095. if ( node->MMState == ClusnetNodeStateAlive &&
  1096. State == ClusnetNodeStateAlive ) {
  1097. status = STATUS_CLUSTER_NODE_ALREADY_UP;
  1098. } else if ( node->MMState == ClusnetNodeStateDead &&
  1099. State == ClusnetNodeStateDead ) {
  1100. status = STATUS_CLUSTER_NODE_ALREADY_DOWN;
  1101. }
  1102. break;
  1103. case MMActionNodeAlive:
  1104. node->MMState = State;
  1105. //
  1106. // if we're transitioning our own node from Dead to
  1107. // Joining or Alive then start heartbeat code
  1108. //
  1109. if (( node->MMState != ClusnetNodeStateJoining ||
  1110. State != ClusnetNodeStateAlive )
  1111. &&
  1112. CnpIsNodeLocal( node )) {
  1113. node->MissedHBs = 0;
  1114. node->HBWasMissed = FALSE;
  1115. //
  1116. // Release the node lock before starting heartbeats. Note
  1117. // that we are holding the global resource here, which will
  1118. // synchronize this code with shutdown.
  1119. //
  1120. CnReleaseLock(&(node->Lock), node->Irql);
  1121. nodeLockAcquired = FALSE;
  1122. status = CnpStartHeartBeats();
  1123. }
  1124. break;
  1125. case MMActionNodeDead:
  1126. //
  1127. // reset this flag so when node is being brought
  1128. // online again, we'll issue a Node Up event on
  1129. // first HB received from this node.
  1130. //
  1131. node->NodeDownIssued = TRUE;
  1132. node->MMState = State;
  1133. if ( CnpIsNodeLocal( node )) {
  1134. //
  1135. // Release the node lock before stopping heartbeats. Note
  1136. // that we are holding the global resource here, which will
  1137. // synchronize this code with shutdown.
  1138. //
  1139. CnReleaseLock(&(node->Lock), node->Irql);
  1140. nodeLockAcquired = FALSE;
  1141. CnpStopHeartBeats();
  1142. }
  1143. break;
  1144. case MMActionConfigured:
  1145. node->MMState = State;
  1146. break;
  1147. }
  1148. if ( NT_ERROR( status )) {
  1149. CN_DBGCHECK;
  1150. }
  1151. if (nodeLockAcquired) {
  1152. CnReleaseLock(&(node->Lock), node->Irql);
  1153. }
  1154. }
  1155. CnVerifyCpuLockMask(
  1156. 0, // Required
  1157. 0xFFFFFFFF, // Forbidden
  1158. 0 // Maximum
  1159. );
  1160. return(status);
  1161. } // CxSetNodeMembershipState