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.

1529 lines
34 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. Node->CommState = ClusnetNodeCommStateOffline;
  192. //
  193. // Delete all the node's interfaces.
  194. //
  195. IF_CNDBG( CN_DEBUG_NODEOBJ )
  196. CNPRINT((
  197. "[CNP] Deleting all interfaces on node %u\n",
  198. Node->Id
  199. ));
  200. while (!IsListEmpty(&(Node->InterfaceList))) {
  201. interface = CONTAINING_RECORD(
  202. Node->InterfaceList.Flink,
  203. CNP_INTERFACE,
  204. NodeLinkage
  205. );
  206. network = interface->Network;
  207. CnAcquireLockAtDpc(&(network->Lock));
  208. network->Irql = DISPATCH_LEVEL;
  209. CnpDeleteInterface(interface);
  210. //
  211. // The network object lock was released.
  212. //
  213. }
  214. //
  215. // Remove initial reference on node object. When the reference
  216. // count goes to zero, the node will be deleted. This releases
  217. // the node lock.
  218. //
  219. CnpDereferenceNode(Node);
  220. CnVerifyCpuLockMask(
  221. 0, // Required
  222. 0xFFFFFFFF, // Forbidden
  223. 0 // Maximum
  224. );
  225. return(FALSE);
  226. }
  227. //
  228. // CNP Internal Routines
  229. //
  230. VOID
  231. CnpWalkNodeTable(
  232. PCNP_NODE_UPDATE_ROUTINE UpdateRoutine,
  233. PVOID UpdateContext
  234. )
  235. {
  236. ULONG i;
  237. CN_IRQL tableIrql;
  238. PCNP_NODE node;
  239. BOOLEAN isNodeTableLockHeld;
  240. CnVerifyCpuLockMask(
  241. 0, // Required
  242. 0xFFFFFFFF, // Forbidden
  243. 0 // Maximum
  244. );
  245. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  246. CnAssert(CnMinValidNodeId != ClusterInvalidNodeId);
  247. CnAssert(CnMaxValidNodeId != ClusterInvalidNodeId);
  248. for (i=CnMinValidNodeId; i <= CnMaxValidNodeId; i++) {
  249. node = CnpNodeTable[i];
  250. if (node != NULL) {
  251. CnAcquireLockAtDpc(&(node->Lock));
  252. node->Irql = DISPATCH_LEVEL;
  253. isNodeTableLockHeld = (*UpdateRoutine)(
  254. node,
  255. UpdateContext,
  256. tableIrql
  257. );
  258. //
  259. // The node object lock was released.
  260. // The node table lock may also have been released.
  261. //
  262. if (!isNodeTableLockHeld) {
  263. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  264. }
  265. }
  266. }
  267. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  268. CnVerifyCpuLockMask(
  269. 0, // Required
  270. 0xFFFFFFFF, // Forbidden
  271. 0 // Maximum
  272. );
  273. return;
  274. } // CnpWalkNodeTable
  275. NTSTATUS
  276. CnpValidateAndFindNode(
  277. IN CL_NODE_ID NodeId,
  278. OUT PCNP_NODE * Node
  279. )
  280. {
  281. NTSTATUS status;
  282. CN_IRQL tableIrql;
  283. PCNP_NODE node = NULL;
  284. CnVerifyCpuLockMask(
  285. 0, // Required
  286. CNP_LOCK_RANGE, // Forbidden
  287. CNP_PRECEEDING_LOCK_RANGE // Maximum
  288. );
  289. if (CnIsValidNodeId(NodeId)) {
  290. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  291. node = CnpNodeTable[NodeId];
  292. if (node != NULL) {
  293. CnAcquireLockAtDpc(&(node->Lock));
  294. CnReleaseLockFromDpc(&CnpNodeTableLock);
  295. node->Irql = tableIrql;
  296. *Node = node;
  297. CnVerifyCpuLockMask(
  298. CNP_NODE_OBJECT_LOCK, // Required
  299. CNP_NODE_TABLE_LOCK, // Forbidden
  300. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  301. );
  302. return(STATUS_SUCCESS);
  303. }
  304. else {
  305. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  306. }
  307. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  308. }
  309. else {
  310. status = STATUS_CLUSTER_INVALID_NODE;
  311. }
  312. CnVerifyCpuLockMask(
  313. 0, // Required
  314. CNP_LOCK_RANGE, // Forbidden
  315. CNP_PRECEEDING_LOCK_RANGE // Maximum
  316. );
  317. return(status);
  318. } // CnpValidateAndFindNode
  319. PCNP_NODE
  320. CnpLockedFindNode(
  321. IN CL_NODE_ID NodeId,
  322. IN CN_IRQL NodeTableIrql
  323. )
  324. /*++
  325. Routine Description:
  326. Searches the node table for a specified node object.
  327. Arguments:
  328. NodeId - The ID of the node object to locate.
  329. NodeTableIrql - The IRQL level at which the node table lock was
  330. acquired before calling this routine.
  331. Return Value:
  332. A pointer to the requested node object, if it exists.
  333. NULL otherwise.
  334. Notes:
  335. Called with CnpNodeTableLock held.
  336. Returns with CnpNodeTableLock released.
  337. If return value is non-NULL, returns with node object lock held.
  338. --*/
  339. {
  340. NTSTATUS status;
  341. CN_IRQL tableIrql;
  342. PCNP_NODE node;
  343. CnVerifyCpuLockMask(
  344. CNP_NODE_TABLE_LOCK, // Required
  345. 0, // Forbidden
  346. CNP_NODE_TABLE_LOCK_MAX // Maximum
  347. );
  348. node = CnpNodeTable[NodeId];
  349. if (node != NULL) {
  350. CnAcquireLockAtDpc(&(node->Lock));
  351. CnReleaseLockFromDpc(&CnpNodeTableLock);
  352. node->Irql = NodeTableIrql;
  353. CnVerifyCpuLockMask(
  354. CNP_NODE_OBJECT_LOCK, // Required
  355. CNP_NODE_TABLE_LOCK, // Forbidden
  356. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  357. );
  358. return(node);
  359. }
  360. CnReleaseLock(&CnpNodeTableLock, NodeTableIrql);
  361. CnVerifyCpuLockMask(
  362. 0, // Required
  363. (CNP_NODE_TABLE_LOCK | CNP_NODE_OBJECT_LOCK), // Forbidden
  364. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  365. );
  366. return(NULL);
  367. } // CnpLockedFindNode
  368. PCNP_NODE
  369. CnpFindNode(
  370. IN CL_NODE_ID NodeId
  371. )
  372. {
  373. CN_IRQL tableIrql;
  374. CnVerifyCpuLockMask(
  375. 0, // Required
  376. CNP_LOCK_RANGE, // Forbidden
  377. CNP_PRECEEDING_LOCK_RANGE // Maximum
  378. );
  379. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  380. return(CnpLockedFindNode(NodeId, tableIrql));
  381. } // CnpFindNode
  382. VOID
  383. CnpDeclareNodeUnreachable(
  384. PCNP_NODE Node
  385. )
  386. /*++
  387. Notes:
  388. Called with node object lock held.
  389. --*/
  390. {
  391. CnVerifyCpuLockMask(
  392. CNP_NODE_OBJECT_LOCK, // Required
  393. 0, // Forbidden
  394. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  395. );
  396. if ( (Node->CommState == ClusnetNodeCommStateOnline) &&
  397. !CnpIsNodeUnreachable(Node)
  398. )
  399. {
  400. IF_CNDBG( CN_DEBUG_NODEOBJ )
  401. CNPRINT(("[CNP] Declaring node %u unreachable\n", Node->Id));
  402. Node->Flags |= CNP_NODE_FLAG_UNREACHABLE;
  403. }
  404. return;
  405. } // CnpDeclareNodeUnreachable
  406. VOID
  407. CnpDeclareNodeReachable(
  408. PCNP_NODE Node
  409. )
  410. /*++
  411. Notes:
  412. Called with node object lock held.
  413. --*/
  414. {
  415. CnVerifyCpuLockMask(
  416. CNP_NODE_OBJECT_LOCK, // Required
  417. 0, // Forbidden
  418. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  419. );
  420. if ( (Node->CommState == ClusnetNodeCommStateOnline) &&
  421. CnpIsNodeUnreachable(Node)
  422. )
  423. {
  424. IF_CNDBG( CN_DEBUG_NODEOBJ )
  425. CNPRINT(("[CNP] Declaring node %u reachable again\n", Node->Id));
  426. Node->Flags &= ~(CNP_NODE_FLAG_UNREACHABLE);
  427. }
  428. return;
  429. } // CnpDeclareNodeUnreachable
  430. VOID
  431. CnpReferenceNode(
  432. PCNP_NODE Node
  433. )
  434. /*++
  435. Notes:
  436. Called with node object lock held.
  437. --*/
  438. {
  439. CnVerifyCpuLockMask(
  440. CNP_NODE_OBJECT_LOCK, // Required
  441. 0, // Forbidden
  442. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  443. );
  444. CnAssert(Node->RefCount != 0xFFFFFFFF);
  445. Node->RefCount++;
  446. IF_CNDBG( CN_DEBUG_CNPREF )
  447. CNPRINT((
  448. "[CNP] Referencing node %u, new refcount %u\n",
  449. Node->Id,
  450. Node->RefCount
  451. ));
  452. return;
  453. } // CnpReferenceNode
  454. VOID
  455. CnpDereferenceNode(
  456. PCNP_NODE Node
  457. )
  458. /*++
  459. Notes:
  460. Called with node object lock held.
  461. Returns with node object lock released.
  462. --*/
  463. {
  464. BOOLEAN isDeleting = FALSE;
  465. ULONG newRefCount;
  466. CnVerifyCpuLockMask(
  467. CNP_NODE_OBJECT_LOCK, // Required
  468. 0, // Forbidden
  469. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  470. );
  471. CnAssert(Node->RefCount != 0);
  472. newRefCount = --(Node->RefCount);
  473. IF_CNDBG( CN_DEBUG_CNPREF )
  474. CNPRINT((
  475. "[CNP] Dereferencing node %u, new refcount %u\n",
  476. Node->Id,
  477. newRefCount
  478. ));
  479. CnReleaseLock(&(Node->Lock), Node->Irql);
  480. if (newRefCount > 0) {
  481. CnVerifyCpuLockMask(
  482. 0, // Required
  483. CNP_NODE_OBJECT_LOCK, // Forbidden
  484. CNP_NODE_TABLE_LOCK_MAX // Maximum
  485. );
  486. return;
  487. }
  488. CnpDestroyNode(Node);
  489. CnVerifyCpuLockMask(
  490. 0, // Required
  491. CNP_NODE_OBJECT_LOCK, // Forbidden
  492. CNP_NODE_TABLE_LOCK_MAX // Maximum
  493. );
  494. return;
  495. } // CnpDereferenceNode
  496. //
  497. // Cluster Transport Public Routines
  498. //
  499. NTSTATUS
  500. CnpLoadNodes(
  501. VOID
  502. )
  503. /*++
  504. Routine Description:
  505. Called when the Cluster Network driver is loading. Initializes
  506. static node-related data structures.
  507. Arguments:
  508. None.
  509. Return Value:
  510. None.
  511. --*/
  512. {
  513. NTSTATUS status;
  514. ULONG i;
  515. CnInitializeLock(&CnpNodeTableLock, CNP_NODE_TABLE_LOCK);
  516. InitializeListHead(&CnpDeletingNodeList);
  517. return(STATUS_SUCCESS);
  518. } // CnpLoadNodes
  519. NTSTATUS
  520. CnpInitializeNodes(
  521. VOID
  522. )
  523. /*++
  524. Routine Description:
  525. Called when the Cluster Network driver is being (re)initialized.
  526. Initializes dynamic node-related data structures.
  527. Arguments:
  528. None.
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. NTSTATUS status;
  534. ULONG i;
  535. PAGED_CODE();
  536. CnAssert(CnLocalNodeId != ClusterInvalidNodeId);
  537. CnAssert(CnMinValidNodeId != ClusterInvalidNodeId);
  538. CnAssert(CnMaxValidNodeId != ClusterInvalidNodeId);
  539. CnAssert(CnpNodeTable == NULL);
  540. CnAssert(CnpNodeShutdownEvent == NULL);
  541. CnAssert(IsListEmpty(&CnpDeletingNodeList));
  542. CnpNodeShutdownEvent = CnAllocatePool(sizeof(KEVENT));
  543. if (CnpNodeShutdownEvent == NULL) {
  544. return(STATUS_INSUFFICIENT_RESOURCES);
  545. }
  546. KeInitializeEvent(CnpNodeShutdownEvent, NotificationEvent, FALSE);
  547. CnpIsNodeShutdownPending = FALSE;
  548. CnpNodeTable = CnAllocatePool(
  549. (sizeof(PCNP_NODE) * (CnMaxValidNodeId + 1))
  550. );
  551. if (CnpNodeTable == NULL) {
  552. return(STATUS_INSUFFICIENT_RESOURCES);
  553. }
  554. RtlZeroMemory(CnpNodeTable, (sizeof(PCNP_NODE) * (CnMaxValidNodeId + 1)) );
  555. //
  556. // Register the local node.
  557. //
  558. status = CxRegisterNode(CnLocalNodeId);
  559. if (!NT_SUCCESS(status)) {
  560. return(status);
  561. }
  562. CnVerifyCpuLockMask(
  563. 0, // Required
  564. 0xFFFFFFFF, // Forbidden
  565. 0 // Maximum
  566. );
  567. return(STATUS_SUCCESS);
  568. } // CnpInitializeNodes
  569. VOID
  570. CnpShutdownNodes(
  571. VOID
  572. )
  573. /*++
  574. Routine Description:
  575. Called when a shutdown request is issued to the Cluster Network
  576. Driver. Deletes all node objects.
  577. Arguments:
  578. None.
  579. Return Value:
  580. None.
  581. --*/
  582. {
  583. ULONG i;
  584. CN_IRQL tableIrql;
  585. PCNP_NODE node;
  586. PCNP_NODE * table;
  587. BOOLEAN waitEvent = FALSE;
  588. NTSTATUS status;
  589. CnVerifyCpuLockMask(
  590. 0, // Required
  591. 0xFFFFFFFF, // Forbidden
  592. 0 // Maximum
  593. );
  594. if (CnpNodeShutdownEvent != NULL) {
  595. CnAssert(CnpIsNodeShutdownPending == FALSE);
  596. IF_CNDBG(CN_DEBUG_CLEANUP) {
  597. CNPRINT(("[CNP] Cleaning up nodes...\n"));
  598. }
  599. if (CnpNodeTable != NULL) {
  600. CnpWalkNodeTable(CnpDeleteNode, NULL);
  601. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  602. if (!IsListEmpty(&CnpDeletingNodeList)) {
  603. CnpIsNodeShutdownPending = TRUE;
  604. waitEvent = TRUE;
  605. }
  606. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  607. if (waitEvent) {
  608. IF_CNDBG(CN_DEBUG_CLEANUP) {
  609. CNPRINT(("[CNP] Node deletes are pending...\n"));
  610. }
  611. status = KeWaitForSingleObject(
  612. CnpNodeShutdownEvent,
  613. Executive,
  614. KernelMode,
  615. FALSE, // not alertable
  616. NULL // no timeout
  617. );
  618. CnAssert(status == STATUS_SUCCESS);
  619. }
  620. CnAssert(IsListEmpty(&CnpDeletingNodeList));
  621. IF_CNDBG(CN_DEBUG_CLEANUP) {
  622. CNPRINT(("[CNP] All nodes deleted.\n"));
  623. }
  624. CnFreePool(CnpNodeTable); CnpNodeTable = NULL;
  625. }
  626. CnFreePool(CnpNodeShutdownEvent); CnpNodeShutdownEvent = NULL;
  627. IF_CNDBG(CN_DEBUG_CLEANUP) {
  628. CNPRINT(("[CNP] Nodes cleaned up.\n"));
  629. }
  630. }
  631. CnVerifyCpuLockMask(
  632. 0, // Required
  633. 0xFFFFFFFF, // Forbidden
  634. 0 // Maximum
  635. );
  636. return;
  637. } // CnpShutdownNodes
  638. NTSTATUS
  639. CxRegisterNode(
  640. CL_NODE_ID NodeId
  641. )
  642. {
  643. NTSTATUS status = STATUS_SUCCESS;
  644. CN_IRQL tableIrql;
  645. PCNP_NODE node = NULL;
  646. CnVerifyCpuLockMask(
  647. 0, // Required
  648. 0xFFFFFFFF, // Forbidden
  649. 0 // Maximum
  650. );
  651. if (CnIsValidNodeId(NodeId)) {
  652. //
  653. // Allocate and initialize a node object.
  654. //
  655. node = CnAllocatePool(sizeof(CNP_NODE));
  656. if (node == NULL) {
  657. return(STATUS_INSUFFICIENT_RESOURCES);
  658. }
  659. RtlZeroMemory(node, sizeof(CNP_NODE));
  660. CN_INIT_SIGNATURE(node, CNP_NODE_SIG);
  661. node->Id = NodeId;
  662. node->CommState = ClusnetNodeCommStateOffline;
  663. node->MMState = ClusnetNodeStateDead;
  664. node->RefCount = 1;
  665. //
  666. // NodeDownIssued is init'ed to true so that the first recv'd
  667. // heart beat msg will cause a node up event to be triggered
  668. //
  669. node->NodeDownIssued = TRUE;
  670. InitializeListHead(&(node->InterfaceList));
  671. CnInitializeLock(&(node->Lock), CNP_NODE_OBJECT_LOCK);
  672. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  673. //
  674. // Make sure this isn't a duplicate registration
  675. //
  676. if (CnpNodeTable[NodeId] == NULL) {
  677. if (NodeId == CnLocalNodeId) {
  678. node->Flags |= CNP_NODE_FLAG_LOCAL;
  679. CnpLocalNode = node;
  680. }
  681. CnpNodeTable[NodeId] = node;
  682. status = STATUS_SUCCESS;
  683. }
  684. else {
  685. status = STATUS_CLUSTER_NODE_EXISTS;
  686. }
  687. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  688. if (!NT_SUCCESS(status)) {
  689. CnFreePool(node);
  690. }
  691. else {
  692. IF_CNDBG( CN_DEBUG_NODEOBJ )
  693. CNPRINT(("[CNP] Registered node %u\n", NodeId));
  694. }
  695. }
  696. else {
  697. status = STATUS_CLUSTER_INVALID_NODE;
  698. }
  699. CnVerifyCpuLockMask(
  700. 0, // Required
  701. 0xFFFFFFFF, // Forbidden
  702. 0 // Maximum
  703. );
  704. return(status);
  705. } // CxRegisterNode
  706. VOID
  707. CxCancelDeregisterNode(
  708. PDEVICE_OBJECT DeviceObject,
  709. PIRP Irp
  710. )
  711. /*++
  712. Routine Description:
  713. Cancellation handler for DeregisterNode requests.
  714. Return Value:
  715. None.
  716. Notes:
  717. Called with cancel spinlock held.
  718. Returns with cancel spinlock released.
  719. --*/
  720. {
  721. PFILE_OBJECT fileObject;
  722. CN_IRQL cancelIrql = Irp->CancelIrql;
  723. PLIST_ENTRY entry;
  724. PCNP_NODE node;
  725. CnVerifyCpuLockMask(
  726. 0, // Required
  727. 0xFFFFFFFF, // Forbidden
  728. 0 // Maximum
  729. );
  730. CnMarkIoCancelLockAcquired();
  731. IF_CNDBG( CN_DEBUG_IRP )
  732. CNPRINT((
  733. "[CNP] Attempting to cancel DeregisterNode irp %p\n",
  734. Irp
  735. ));
  736. CnAssert(DeviceObject == CnDeviceObject);
  737. fileObject = CnBeginCancelRoutine(Irp);
  738. CnAcquireLockAtDpc(&CnpNodeTableLock);
  739. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  740. //
  741. // We can only complete the irp if we can find it stashed in a
  742. // deleting node object. The deleting node object could have
  743. // been destroyed and the IRP completed before we acquired the
  744. // CnpNetworkListLock.
  745. //
  746. for (entry = CnpDeletingNodeList.Flink;
  747. entry != &CnpDeletingNodeList;
  748. entry = entry->Flink
  749. )
  750. {
  751. node = CONTAINING_RECORD(entry, CNP_NODE, Linkage);
  752. if (node->PendingDeleteIrp == Irp) {
  753. IF_CNDBG( CN_DEBUG_IRP )
  754. CNPRINT((
  755. "[CNP] Found dereg irp on node %u\n",
  756. node->Id
  757. ));
  758. //
  759. // Found the Irp. Now take it away and complete it.
  760. //
  761. node->PendingDeleteIrp = NULL;
  762. CnReleaseLock(&CnpNodeTableLock, cancelIrql);
  763. CnAcquireCancelSpinLock(&(Irp->CancelIrql));
  764. CnEndCancelRoutine(fileObject);
  765. CnCompletePendingRequest(Irp, STATUS_CANCELLED, 0);
  766. //
  767. // IoCancelSpinLock was released by CnCompletePendingRequest().
  768. //
  769. CnVerifyCpuLockMask(
  770. 0, // Required
  771. 0xFFFFFFFF, // Forbidden
  772. 0 // Maximum
  773. );
  774. return;
  775. }
  776. }
  777. CnReleaseLock(&CnpNodeTableLock, cancelIrql);
  778. CnAcquireCancelSpinLock(&cancelIrql);
  779. CnEndCancelRoutine(fileObject);
  780. CnReleaseCancelSpinLock(cancelIrql);
  781. CnVerifyCpuLockMask(
  782. 0, // Required
  783. 0xFFFFFFFF, // Forbidden
  784. 0 // Maximum
  785. );
  786. return;
  787. } // CnpCancelApiDeregisterNode
  788. NTSTATUS
  789. CxDeregisterNode(
  790. CL_NODE_ID NodeId,
  791. PIRP Irp,
  792. PIO_STACK_LOCATION IrpSp
  793. )
  794. {
  795. NTSTATUS status;
  796. CN_IRQL cancelIrql;
  797. PCNP_NODE node = NULL;
  798. BOOLEAN isNodeTableLockHeld;
  799. CnVerifyCpuLockMask(
  800. 0, // Required
  801. 0xFFFFFFFF, // Forbidden
  802. 0 // Maximum
  803. );
  804. if (CnIsValidNodeId(NodeId)) {
  805. if (NodeId != CnLocalNodeId) {
  806. CnAcquireCancelSpinLock(&cancelIrql);
  807. CnAcquireLockAtDpc(&CnpNodeTableLock);
  808. node = CnpNodeTable[NodeId];
  809. if (node != NULL) {
  810. status = CnMarkRequestPending(
  811. Irp,
  812. IrpSp,
  813. CxCancelDeregisterNode
  814. );
  815. if (status != STATUS_CANCELLED) {
  816. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  817. CnAssert(status == STATUS_SUCCESS);
  818. CnAcquireLockAtDpc(&(node->Lock));
  819. IF_CNDBG( CN_DEBUG_NODEOBJ )
  820. CNPRINT(("[CNP] Deregistering node %u\n", NodeId));
  821. //
  822. // Save a pointer to pending irp. Note this is protected
  823. // by the table lock, not the object lock.
  824. //
  825. node->PendingDeleteIrp = Irp;
  826. isNodeTableLockHeld = CnpDeleteNode(node, NULL, cancelIrql);
  827. if (isNodeTableLockHeld) {
  828. CnReleaseLock(&CnpNodeTableLock, cancelIrql);
  829. }
  830. CnVerifyCpuLockMask(
  831. 0, // Required
  832. 0xFFFFFFFF, // Forbidden
  833. 0 // Maximum
  834. );
  835. return(STATUS_PENDING);
  836. }
  837. }
  838. else {
  839. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  840. }
  841. CnReleaseLockFromDpc(&CnpNodeTableLock);
  842. CnReleaseCancelSpinLock(cancelIrql);
  843. }
  844. else {
  845. status = STATUS_CLUSTER_INVALID_REQUEST;
  846. }
  847. }
  848. else {
  849. status = STATUS_CLUSTER_INVALID_NODE;
  850. }
  851. CnVerifyCpuLockMask(
  852. 0, // Required
  853. 0xFFFFFFFF, // Forbidden
  854. 0 // Maximum
  855. );
  856. return(status);
  857. } // CxDeregisterNode
  858. NTSTATUS
  859. CxOnlineNodeComm(
  860. CL_NODE_ID NodeId
  861. )
  862. {
  863. NTSTATUS status;
  864. PCNP_NODE node;
  865. CnVerifyCpuLockMask(
  866. 0, // Required
  867. 0xFFFFFFFF, // Forbidden
  868. 0 // Maximum
  869. );
  870. status = CnpValidateAndFindNode(NodeId, &node);
  871. if (status == STATUS_SUCCESS) {
  872. if (node->CommState == ClusnetNodeCommStateOffline) {
  873. IF_CNDBG( CN_DEBUG_NODEOBJ )
  874. CNPRINT((
  875. "[CNP] Moving node %u comm state to online.\n",
  876. NodeId
  877. ));
  878. CnTrace(
  879. CNP_NODE_DETAIL,
  880. CnpTraceOnlineNodeComm,
  881. "[CNP] Moving node %u comm state to online.\n",
  882. NodeId
  883. );
  884. node->CommState = ClusnetNodeCommStateOnline;
  885. CnpWalkInterfacesOnNode(node, CnpResetAndOnlinePendingInterface);
  886. }
  887. else {
  888. status = STATUS_CLUSTER_NODE_ALREADY_UP;
  889. }
  890. CnReleaseLock(&(node->Lock), node->Irql);
  891. }
  892. CnVerifyCpuLockMask(
  893. 0, // Required
  894. 0xFFFFFFFF, // Forbidden
  895. 0 // Maximum
  896. );
  897. return(status);
  898. } // CxOnlineNodeComm
  899. NTSTATUS
  900. CxOfflineNodeComm(
  901. IN CL_NODE_ID NodeId,
  902. IN PIRP Irp,
  903. IN PIO_STACK_LOCATION IrpSp
  904. )
  905. /*++
  906. Notes:
  907. --*/
  908. {
  909. PCNP_NODE node;
  910. NTSTATUS status;
  911. CnVerifyCpuLockMask(
  912. 0, // Required
  913. 0xFFFFFFFF, // Forbidden
  914. 0 // Maximum
  915. );
  916. status = CnpValidateAndFindNode(NodeId, &node);
  917. if (status == STATUS_SUCCESS) {
  918. if (node->CommState == ClusnetNodeCommStateOnline) {
  919. IF_CNDBG( CN_DEBUG_NODEOBJ )
  920. CNPRINT((
  921. "[CNP] Moving node %u comm state to offline.\n",
  922. NodeId
  923. ));
  924. CnTrace(
  925. CNP_NODE_DETAIL,
  926. CnpTraceOfflineNodeComm,
  927. "[CNP] Moving node %u comm state to offline.\n",
  928. NodeId
  929. );
  930. node->CommState = ClusnetNodeCommStateOffline;
  931. CnpWalkInterfacesOnNode(node, CnpOfflineInterfaceWrapper);
  932. }
  933. else {
  934. status = STATUS_CLUSTER_NODE_ALREADY_DOWN;
  935. }
  936. CnReleaseLock(&(node->Lock), node->Irql);
  937. }
  938. else {
  939. status = STATUS_CLUSTER_NODE_NOT_FOUND;
  940. }
  941. CnVerifyCpuLockMask(
  942. 0, // Required
  943. 0xFFFFFFFF, // Forbidden
  944. 0 // Maximum
  945. );
  946. return(status);
  947. } // CxOfflineNodeComm
  948. NTSTATUS
  949. CxGetNodeCommState(
  950. IN CL_NODE_ID NodeId,
  951. OUT PCLUSNET_NODE_COMM_STATE CommState
  952. )
  953. {
  954. NTSTATUS status;
  955. PCNP_NODE node;
  956. CnVerifyCpuLockMask(
  957. 0, // Required
  958. 0xFFFFFFFF, // Forbidden
  959. 0 // Maximum
  960. );
  961. status = CnpValidateAndFindNode(NodeId, &node);
  962. if (status == STATUS_SUCCESS) {
  963. if (CnpIsNodeUnreachable(node)) {
  964. *CommState = ClusnetNodeCommStateUnreachable;
  965. }
  966. else {
  967. *CommState = node->CommState;
  968. }
  969. CnReleaseLock(&(node->Lock), node->Irql);
  970. }
  971. CnVerifyCpuLockMask(
  972. 0, // Required
  973. 0xFFFFFFFF, // Forbidden
  974. 0 // Maximum
  975. );
  976. return(status);
  977. } // CxGetNodeCommState
  978. NTSTATUS
  979. CxGetNodeMembershipState(
  980. IN CL_NODE_ID NodeId,
  981. OUT PCLUSNET_NODE_STATE State
  982. )
  983. {
  984. NTSTATUS status;
  985. PCNP_NODE node;
  986. CnVerifyCpuLockMask(
  987. 0, // Required
  988. 0xFFFFFFFF, // Forbidden
  989. 0 // Maximum
  990. );
  991. status = CnpValidateAndFindNode(NodeId, &node);
  992. if (status == STATUS_SUCCESS) {
  993. *State = node->MMState;
  994. CnReleaseLock(&(node->Lock), node->Irql);
  995. }
  996. CnVerifyCpuLockMask(
  997. 0, // Required
  998. 0xFFFFFFFF, // Forbidden
  999. 0 // Maximum
  1000. );
  1001. return(status);
  1002. } // CxGetNodeMembershipState
  1003. NTSTATUS
  1004. CxSetNodeMembershipState(
  1005. IN CL_NODE_ID NodeId,
  1006. IN CLUSNET_NODE_STATE State
  1007. )
  1008. {
  1009. NTSTATUS status;
  1010. PCNP_NODE node;
  1011. MM_ACTION MMAction;
  1012. BOOLEAN nodeLockAcquired = FALSE;
  1013. CnVerifyCpuLockMask(
  1014. 0, // Required
  1015. 0xFFFFFFFF, // Forbidden
  1016. 0 // Maximum
  1017. );
  1018. status = CnpValidateAndFindNode(NodeId, &node);
  1019. if (status == STATUS_SUCCESS) {
  1020. nodeLockAcquired = TRUE;
  1021. IF_CNDBG( CN_DEBUG_MMSTATE ) {
  1022. CNPRINT(("[Clusnet] Changing Node %u (%08X) MMState from %u to %u\n",
  1023. node->Id, node, node->MMState, State));
  1024. }
  1025. //
  1026. // look up the routine to call (if any) based on the old and new
  1027. // state
  1028. //
  1029. switch ( MembershipStateTable[ node->MMState ][ State ] ) {
  1030. case MMActionIllegal:
  1031. status = STATUS_CLUSTER_INVALID_REQUEST;
  1032. break;
  1033. case MMActionWarning:
  1034. //
  1035. // warning about null transitions
  1036. //
  1037. if ( node->MMState == ClusnetNodeStateAlive &&
  1038. State == ClusnetNodeStateAlive ) {
  1039. status = STATUS_CLUSTER_NODE_ALREADY_UP;
  1040. } else if ( node->MMState == ClusnetNodeStateDead &&
  1041. State == ClusnetNodeStateDead ) {
  1042. status = STATUS_CLUSTER_NODE_ALREADY_DOWN;
  1043. }
  1044. break;
  1045. case MMActionNodeAlive:
  1046. node->MMState = State;
  1047. //
  1048. // if we're transitioning our own node from Dead to
  1049. // Joining or Alive then start heartbeat code
  1050. //
  1051. if (( node->MMState != ClusnetNodeStateJoining ||
  1052. State != ClusnetNodeStateAlive )
  1053. &&
  1054. CnpIsNodeLocal( node )) {
  1055. node->MissedHBs = 0;
  1056. node->HBWasMissed = FALSE;
  1057. //
  1058. // Release the node lock before starting heartbeats. Note
  1059. // that we are holding the global resource here, which will
  1060. // synchronize this code with shutdown.
  1061. //
  1062. CnReleaseLock(&(node->Lock), node->Irql);
  1063. nodeLockAcquired = FALSE;
  1064. CnpStartHeartBeats();
  1065. }
  1066. break;
  1067. case MMActionNodeDead:
  1068. //
  1069. // reset this flag so when node is being brought
  1070. // online again, we'll issue a Node Up event on
  1071. // first HB received from this node.
  1072. //
  1073. node->NodeDownIssued = TRUE;
  1074. node->MMState = State;
  1075. if ( CnpIsNodeLocal( node )) {
  1076. //
  1077. // Release the node lock before stopping heartbeats. Note
  1078. // that we are holding the global resource here, which will
  1079. // synchronize this code with shutdown.
  1080. //
  1081. CnReleaseLock(&(node->Lock), node->Irql);
  1082. nodeLockAcquired = FALSE;
  1083. CnpStopHeartBeats();
  1084. }
  1085. break;
  1086. case MMActionConfigured:
  1087. node->MMState = State;
  1088. break;
  1089. }
  1090. if ( NT_ERROR( status )) {
  1091. CN_DBGCHECK;
  1092. }
  1093. if (nodeLockAcquired) {
  1094. CnReleaseLock(&(node->Lock), node->Irql);
  1095. }
  1096. }
  1097. CnVerifyCpuLockMask(
  1098. 0, // Required
  1099. 0xFFFFFFFF, // Forbidden
  1100. 0 // Maximum
  1101. );
  1102. return(status);
  1103. } // CxSetNodeMembershipState