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.

1122 lines
30 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. event.c
  5. Abstract:
  6. general kernel to user event facility. Maintains a list of events that have
  7. occurred and delivers them to Umode via the completion of an IOCTL IRP.
  8. How this works:
  9. The consumer opens a handle to clusnet and issues an
  10. IOCTL_CLUSNET_SET_EVENT_MASK IRP indicating a mask of the events in which it
  11. is interested. A kernel consumer must also supply a callback routine through
  12. which it is notified about the event, i.e, they don't need to drop an
  13. IOCTL_CLUSNET_GET_NEXT_EVENT IRP to receive notifications. The consumer is
  14. linked onto the EventFileHandles list through the Linkage field in the
  15. CN_FSCONTEXT structure. All synchronization is provided through one lock
  16. called EventLock.
  17. Umode consumers issue an IOCTL_CLUSNET_GET_NEXT_EVENT IRP to reap the next
  18. interesting event. If no events are queued, the IRP is marked pending and a
  19. pointer to it is stored in the FS context. CnEventIrpCancel is set as the
  20. cancel routine. Note that only one IRP can be pending at a time; if an IRP
  21. is already queued, this one is completed with STATUS_UNSUCCESSFUL.
  22. If an event is waiting, it is removed from the FS context's list, the data
  23. copied to the IRP's buffer and completed with success.
  24. Posters call CnIssueEvent to post the event of interest. This obtains the
  25. event lock, walks the file object list, and for consumers that are
  26. interested in this event, allocates an Event context block (maintained as a
  27. nonpaged lookaside list) and queues it to that file object's list of
  28. events. It then posts a work queue item to run CnpDeliverEvents. We can't do
  29. IRP processing directly since that would violate lock ordering within
  30. clusnet.
  31. CnDeliverEvents obtains the IO cancel and event locks, then runs the file
  32. context list to see if there are events queued for any pending IRPs. If so,
  33. the event data is copied to the systembuffer and the IRP is completed.
  34. Author:
  35. Charlie Wickham (charlwi) 17-Feb-1997
  36. Environment:
  37. Kernel Mode
  38. Revision History:
  39. Charlie Wickham (charlwi) 25-Oct-1999
  40. Split CnIssueEvent into two routines: CnIssueEvent which strictly looks
  41. up the apporpriate consumers of the event and CnpDeliverEvents which
  42. runs at IRQL 0 to complete any IRPs that are waiting for new
  43. events. This was done to prevent out of order event delivery; since the
  44. event lock was near the top of locks to acquire first, the net IF down
  45. events had to be queued to a worker thread which was bad. Now the event
  46. lock is lowest which doesn't require a worker thread to post. The worker
  47. thread still runs when it detects that there is an IRP waiting for an
  48. event.
  49. David Dion (daviddio) 29-Nov-2000
  50. Disallow modification of the EventFileHandles list while event
  51. deliveries are in process. Because CnpDeliverEvents and CnIssueEvent
  52. drop their locks to deliver (via IRP completion and kmode callback,
  53. respectively), a race condition can occur where an FS context event
  54. mask is cleared and the FS context linkage fields are reset.
  55. Modification of the EventFileHandles list is prevented using a count
  56. of currently delivering threads that is protected by the EventLock.
  57. --*/
  58. #include "precomp.h"
  59. #pragma hdrstop
  60. #include "event.tmh"
  61. /* Forward */
  62. NTSTATUS
  63. CnSetEventMask(
  64. IN PCN_FSCONTEXT FsContext,
  65. IN PCLUSNET_SET_EVENT_MASK_REQUEST EventRequest
  66. );
  67. NTSTATUS
  68. CnGetNextEvent(
  69. IN PIRP Irp,
  70. IN PIO_STACK_LOCATION IrpSp
  71. );
  72. NTSTATUS
  73. CnIssueEvent(
  74. CLUSNET_EVENT_TYPE Event,
  75. CL_NODE_ID NodeId OPTIONAL,
  76. CL_NETWORK_ID NetworkId OPTIONAL
  77. );
  78. VOID
  79. CnEventIrpCancel(
  80. PDEVICE_OBJECT DeviceObject,
  81. PIRP Irp
  82. );
  83. /* End Forward */
  84. VOID
  85. CnStartEventDelivery(
  86. VOID
  87. )
  88. /*++
  89. Routine Description:
  90. Synchronizes iteration through EventFileHandles list with respect
  91. to the EventDeliveryInProgress counter and the EventDeliveryComplete
  92. KEVENT.
  93. Arguments:
  94. None.
  95. Return value:
  96. None.
  97. Notes:
  98. Called with and returns with EventLock held.
  99. --*/
  100. {
  101. CnVerifyCpuLockMask(
  102. CNP_EVENT_LOCK, // Required
  103. 0, // Forbidden
  104. CNP_EVENT_LOCK_MAX // Maximum
  105. );
  106. CnAssert(EventDeliveryInProgress >= 0);
  107. if (++EventDeliveryInProgress == 1) {
  108. #if DBG
  109. if (KeResetEvent(&EventDeliveryComplete) == 0) {
  110. CnAssert(FALSE);
  111. }
  112. #else // DBG
  113. KeClearEvent(&EventDeliveryComplete);
  114. #endif // DBG
  115. }
  116. EventRevisitRequired = FALSE;
  117. CnVerifyCpuLockMask(
  118. CNP_EVENT_LOCK, // Required
  119. 0, // Forbidden
  120. CNP_EVENT_LOCK_MAX // Maximum
  121. );
  122. } // CnStartEventDelivery
  123. BOOLEAN
  124. CnStopEventDelivery(
  125. VOID
  126. )
  127. /**
  128. Routine Description:
  129. Synchronizes iteration through EventFileHandles list with respect
  130. to the EventDeliveryInProgress counter and the EventDeliveryComplete
  131. KEVENT. Checks the EventRevisitRequired flag to determine if an
  132. event IRP arrived during the preceding delivery.
  133. When signalling EventDeliveryComplete, IO_NETWORK_INCREMENT is used
  134. to try to avoid starvation of waiters versus other event-delivering
  135. threads.
  136. Arguments:
  137. None.
  138. Return value:
  139. TRUE if a new event or event IRP may have been added to the
  140. EventFileHandles list, and it is necessary to rescan.
  141. Notes:
  142. Called with and returns with EventLock held.
  143. --*/
  144. {
  145. BOOLEAN eventRevisitRequired = EventRevisitRequired;
  146. CnVerifyCpuLockMask(
  147. CNP_EVENT_LOCK, // Required
  148. 0, // Forbidden
  149. CNP_EVENT_LOCK_MAX // Maximum
  150. );
  151. EventRevisitRequired = FALSE;
  152. CnAssert(EventDeliveryInProgress >= 1);
  153. if (--EventDeliveryInProgress == 0) {
  154. if (KeSetEvent(
  155. &EventDeliveryComplete,
  156. IO_NETWORK_INCREMENT,
  157. FALSE
  158. ) != 0) {
  159. CnAssert(FALSE);
  160. }
  161. }
  162. if (eventRevisitRequired) {
  163. CnTrace(
  164. EVENT_DETAIL, StopDeliveryRevisitRequired,
  165. "[CN] CnStopEventDelivery: revisit required."
  166. );
  167. }
  168. CnVerifyCpuLockMask(
  169. CNP_EVENT_LOCK, // Required
  170. 0, // Forbidden
  171. CNP_EVENT_LOCK_MAX // Maximum
  172. );
  173. return(eventRevisitRequired);
  174. } // CnStopEventDelivery
  175. BOOLEAN
  176. CnIsEventDeliveryInProgress(
  177. VOID
  178. )
  179. /*++
  180. Routine Description:
  181. Checks the EventDeliveryInProgress counter to determine if
  182. an event delivery is in progress. If so, sets the
  183. EventRevisitRequired flag.
  184. Arguments:
  185. None.
  186. Return value:
  187. TRUE if event delivery in progress.
  188. Notes:
  189. Called with and returns with EventLock held.
  190. --*/
  191. {
  192. CnVerifyCpuLockMask(
  193. CNP_EVENT_LOCK, // Required
  194. 0, // Forbidden
  195. CNP_EVENT_LOCK_MAX // Maximum
  196. );
  197. if (EventDeliveryInProgress > 0) {
  198. return(EventRevisitRequired = TRUE);
  199. } else {
  200. return(FALSE);
  201. }
  202. CnVerifyCpuLockMask(
  203. CNP_EVENT_LOCK, // Required
  204. 0, // Forbidden
  205. CNP_EVENT_LOCK_MAX // Maximum
  206. );
  207. } // CnIsEventDeliveryInProgress
  208. BOOLEAN
  209. CnWaitForEventDelivery(
  210. IN PKIRQL EventLockIrql
  211. )
  212. /*++
  213. Routine Description:
  214. Waits for EventDeliveryComplete event to be signalled as long
  215. as EventDeliveryInProgress counter is greater than zero.
  216. Maintains a starvation counter to avoid looping forever.
  217. Starvation threshold of 100 was chosen arbitrarily.
  218. Arguments:
  219. EventLockIrql - irql at which EventLock was acquired
  220. Return value:
  221. TRUE if returning with no deliveries in progress
  222. FALSE if starvation threshold is exceeded and returning with
  223. deliveries in progress
  224. Notes:
  225. Called with and returns with EventLock held; however, EventLock
  226. may be dropped and reacquired during execution.
  227. This call blocks, so no other spinlocks may be held at
  228. invocation.
  229. --*/
  230. {
  231. NTSTATUS status;
  232. ULONG starvationCounter;
  233. CnVerifyCpuLockMask(
  234. CNP_EVENT_LOCK, // Required
  235. (ULONG) ~(CNP_EVENT_LOCK), // Forbidden
  236. CNP_EVENT_LOCK_MAX // Maximum
  237. );
  238. starvationCounter = 100;
  239. while (starvationCounter-- > 0) {
  240. if (EventDeliveryInProgress == 0) {
  241. return(TRUE);
  242. }
  243. CnReleaseLock(&EventLock, *EventLockIrql);
  244. status = KeWaitForSingleObject(
  245. &EventDeliveryComplete,
  246. Executive,
  247. KernelMode,
  248. FALSE,
  249. NULL
  250. );
  251. CnAssert(status == STATUS_SUCCESS);
  252. CnAcquireLock(&EventLock, EventLockIrql);
  253. }
  254. CnTrace(
  255. EVENT_DETAIL, EventWaitStarvation,
  256. "[CN] CnWaitForEventDelivery: starvation threshold %u "
  257. "exceeded.",
  258. starvationCounter
  259. );
  260. IF_CNDBG( CN_DEBUG_EVENT ) {
  261. CNPRINT(("[CN] CnWaitForEventDelivery: starvation threshold "
  262. "expired.\n"));
  263. }
  264. CnVerifyCpuLockMask(
  265. CNP_EVENT_LOCK, // Required
  266. (ULONG) ~(CNP_EVENT_LOCK), // Forbidden
  267. CNP_EVENT_LOCK // Maximum
  268. );
  269. return(FALSE);
  270. } // CnWaitForEventDelivery
  271. NTSTATUS
  272. CnSetEventMask(
  273. IN PCN_FSCONTEXT FsContext,
  274. IN PCLUSNET_SET_EVENT_MASK_REQUEST EventRequest
  275. )
  276. /*++
  277. Routine Description:
  278. For a given file handle context, set the event mask associated
  279. with it
  280. Arguments:
  281. FsContext - pointer to the clusnet file handle context block
  282. EventMask - mask of interested events
  283. Return Value:
  284. STATUS_TIMEOUT if unable to modify EventFileHandles list.
  285. STATUS_INVALID_PARAMETER_MIX if providing NULL event mask on
  286. first call
  287. STATUS_SUCCESS on success.
  288. Notes:
  289. This call may block.
  290. --*/
  291. {
  292. CN_IRQL OldIrql;
  293. NTSTATUS Status = STATUS_SUCCESS;
  294. PLIST_ENTRY NextEntry;
  295. CnVerifyCpuLockMask(
  296. 0, // Required
  297. 0xFFFFFFFF, // Forbidden
  298. 0 // Maximum
  299. );
  300. CnAcquireLock( &EventLock, &OldIrql );
  301. #if 0
  302. PCN_FSCONTEXT ListFsContext;
  303. NextEntry = EventFileHandles.Flink;
  304. while ( NextEntry != &EventFileHandles ) {
  305. ListFsContext = CONTAINING_RECORD( NextEntry, CN_FSCONTEXT, Linkage );
  306. if ( ListFsContext == FsContext ) {
  307. break;
  308. }
  309. NextEntry = ListFsContext->Linkage.Flink;
  310. }
  311. #endif
  312. if ( EventRequest->EventMask != 0 ) {
  313. //
  314. // adding or updating a handle. If not in the list then add them.
  315. // Remember the events and, if appropriate, the callback func to use
  316. // when an event occurs.
  317. //
  318. if ( IsListEmpty( &FsContext->Linkage )) {
  319. //
  320. // Do not modify the EventFileHandles list if an event
  321. // delivery is in progress.
  322. //
  323. if (CnWaitForEventDelivery(&OldIrql)) {
  324. InsertHeadList( &EventFileHandles, &FsContext->Linkage );
  325. } else {
  326. Status = STATUS_TIMEOUT;
  327. }
  328. }
  329. if (NT_SUCCESS(Status)) {
  330. FsContext->EventMask = EventRequest->EventMask;
  331. FsContext->KmodeEventCallback = EventRequest->KmodeEventCallback;
  332. }
  333. } else if ( !IsListEmpty( &FsContext->Linkage )) {
  334. //
  335. // Null event mask and the fileobj on the event file obj list means
  336. // remove this guy from the list. Zap any events that may been queued
  337. // waiting for an IRP. Re-init the linkage to empty so we'll add them
  338. // back on if they re-init the mask.
  339. //
  340. FsContext->EventMask = 0;
  341. //
  342. // Do not modify the EventFileHandles list if an event
  343. // delivery is in progress. It is okay to modify this
  344. // FsContext structure since the EventLock is held.
  345. //
  346. if (CnWaitForEventDelivery(&OldIrql)) {
  347. RemoveEntryList( &FsContext->Linkage );
  348. InitializeListHead( &FsContext->Linkage );
  349. } else {
  350. Status = STATUS_TIMEOUT;
  351. }
  352. while ( !IsListEmpty( &FsContext->EventList )) {
  353. NextEntry = RemoveHeadList( &FsContext->EventList );
  354. ExFreeToNPagedLookasideList( EventLookasideList, NextEntry );
  355. }
  356. } else {
  357. //
  358. // can't provide NULL event mask first time in
  359. //
  360. Status = STATUS_INVALID_PARAMETER_MIX;
  361. }
  362. CnReleaseLock( &EventLock, OldIrql );
  363. if (Status != STATUS_SUCCESS) {
  364. CnTrace(
  365. EVENT_DETAIL, SetEventMaskFailed,
  366. "[CN] CnSetEventMask failed, status %!status!.",
  367. Status
  368. );
  369. }
  370. CnVerifyCpuLockMask(
  371. 0, // Required
  372. 0xFFFFFFFF, // Forbidden
  373. 0 // Maximum
  374. );
  375. return Status;
  376. } // CnSetEventMask
  377. VOID
  378. CnpDeliverEvents(
  379. IN PDEVICE_OBJECT DeviceObject,
  380. IN PVOID Parameter
  381. )
  382. /*++
  383. Routine Description:
  384. Deliver any queued events to those who are waiting. If an IRP is already
  385. queued, complete it with the info supplied.
  386. Arguments:
  387. DeviceObject - clusnet device object, not used
  388. Parameter - PIO_WORKITEM that must be freed
  389. Return Value:
  390. None
  391. --*/
  392. {
  393. CN_IRQL OldIrql;
  394. PCLUSNET_EVENT_ENTRY Event;
  395. PCLUSNET_EVENT_RESPONSE UserEventData;
  396. PCN_FSCONTEXT FsContext;
  397. PLIST_ENTRY NextFsHandleEntry;
  398. PIRP EventIrp;
  399. PLIST_ENTRY Entry;
  400. ULONG eventsDelivered = 0;
  401. BOOLEAN revisitRequired;
  402. CnVerifyCpuLockMask(
  403. 0, // Required
  404. 0xFFFFFFFF, // Forbidden
  405. 0 // Maximum
  406. );
  407. //
  408. // free the workitem
  409. //
  410. IoFreeWorkItem( (PIO_WORKITEM) Parameter );
  411. //
  412. // grab the cancel and event locks and loop through the file handles,
  413. // looking to see which file objs have events queued and IRPs pending.
  414. //
  415. CnAcquireCancelSpinLock ( &OldIrql );
  416. CnAcquireLockAtDpc( &EventLock );
  417. do {
  418. //
  419. // Indicate that a thread is iterating through the EventFileHandles
  420. // list to deliver events.
  421. //
  422. CnTrace(
  423. EVENT_DETAIL, DeliverEventsStartIteration,
  424. "[CN] CnpDeliverEvents: starting file handles list iteration."
  425. );
  426. CnStartEventDelivery();
  427. NextFsHandleEntry = EventFileHandles.Flink;
  428. while ( NextFsHandleEntry != &EventFileHandles ) {
  429. FsContext = CONTAINING_RECORD( NextFsHandleEntry, CN_FSCONTEXT, Linkage );
  430. EventIrp = FsContext->EventIrp;
  431. if ( !IsListEmpty( &FsContext->EventList ) && EventIrp != NULL ) {
  432. //
  433. // clear the pointer to the pended IRP and remove the entry from the
  434. // event list while synchronized.
  435. //
  436. FsContext->EventIrp = NULL;
  437. Entry = RemoveHeadList( &FsContext->EventList );
  438. CnReleaseLockFromDpc( &EventLock );
  439. Event = CONTAINING_RECORD( Entry, CLUSNET_EVENT_ENTRY, Linkage );
  440. IF_CNDBG( CN_DEBUG_EVENT ) {
  441. CNPRINT(("[CN] CnDeliverEvents: completing IRP %p with event %d\n",
  442. EventIrp, Event->EventData.EventType));
  443. }
  444. EventIrp->CancelIrql = OldIrql;
  445. UserEventData = (PCLUSNET_EVENT_RESPONSE)EventIrp->AssociatedIrp.SystemBuffer;
  446. UserEventData->Epoch = Event->EventData.Epoch;
  447. UserEventData->EventType = Event->EventData.EventType;
  448. UserEventData->NodeId = Event->EventData.NodeId;
  449. UserEventData->NetworkId = Event->EventData.NetworkId;
  450. ExFreeToNPagedLookasideList( EventLookasideList, Entry );
  451. CnTrace(
  452. EVENT_DETAIL, DeliverEventsCompletingIrp,
  453. "[CN] Completing IRP to deliver event: "
  454. "Epoch %u, Type %u, NodeId %u, NetworkId %u.",
  455. UserEventData->Epoch,
  456. UserEventData->EventType,
  457. UserEventData->NodeId,
  458. UserEventData->NetworkId
  459. );
  460. //
  461. // IO Cancel lock is released in this routine
  462. //
  463. CnCompletePendingRequest(EventIrp,
  464. STATUS_SUCCESS,
  465. sizeof( CLUSNET_EVENT_RESPONSE ));
  466. CnAcquireCancelSpinLock ( &OldIrql );
  467. CnAcquireLockAtDpc( &EventLock );
  468. ++eventsDelivered;
  469. }
  470. NextFsHandleEntry = FsContext->Linkage.Flink;
  471. }
  472. CnTrace(
  473. EVENT_DETAIL, DeliverEventsStopIteration,
  474. "[CN] CnpDeliverEvents: file handle list iteration complete."
  475. );
  476. } while ( CnStopEventDelivery() );
  477. CnReleaseLockFromDpc( &EventLock );
  478. CnReleaseCancelSpinLock( OldIrql );
  479. CnTrace(
  480. EVENT_DETAIL, DeliverEventsSummary,
  481. "[CN] CnpDeliverEvents: delivered %u events.",
  482. eventsDelivered
  483. );
  484. IF_CNDBG( CN_DEBUG_EVENT ) {
  485. CNPRINT(("[CN] CnDeliverEvents: events delivered %d\n", eventsDelivered ));
  486. }
  487. CnVerifyCpuLockMask(
  488. 0, // Required
  489. 0xFFFFFFFF, // Forbidden
  490. 0 // Maximum
  491. );
  492. } // CnDeliverEvents
  493. NTSTATUS
  494. CnIssueEvent(
  495. CLUSNET_EVENT_TYPE EventType,
  496. CL_NODE_ID NodeId OPTIONAL,
  497. CL_NETWORK_ID NetworkId OPTIONAL
  498. )
  499. /*++
  500. Routine Description:
  501. Post an event to each file object's event queue that is interested in this
  502. type of event. Schedule a work queue item to run down the file objs to
  503. deliver the events. We can't complete the IRPs directly since we might
  504. violate the locking order inside clusnet.
  505. Arguments:
  506. EventType - type of event
  507. NodeId - optional node Id associated with event
  508. NetworkId - optional network Id associated with event
  509. Return Value:
  510. STATUS_SUCCESS
  511. STATUS_INSUFFICIENT_RESOUCES
  512. --*/
  513. {
  514. CN_IRQL OldIrql;
  515. PCLUSNET_EVENT_ENTRY Event;
  516. PCLUSNET_EVENT_RESPONSE UserData;
  517. PCN_FSCONTEXT FsContext;
  518. PLIST_ENTRY NextFsHandleEntry;
  519. PIRP EventIrp;
  520. PIO_WORKITEM EventWorkItem;
  521. BOOLEAN startupWorkerThread = FALSE;
  522. BOOLEAN eventHandled = FALSE;
  523. CnVerifyCpuLockMask(
  524. 0, // Required
  525. CNP_EVENT_LOCK, // Forbidden
  526. CNP_EVENT_LOCK_PRECEEDING // Maximum
  527. );
  528. CnTrace(
  529. EVENT_DETAIL, CnIssueEvent,
  530. "[CN] CnIssueEvent: Event Type %u, NodeId %u, NetworkId %u.",
  531. EventType, NodeId, NetworkId
  532. );
  533. IF_CNDBG( CN_DEBUG_EVENT ) {
  534. CNPRINT(( "[CN] CnIssueEvent: Event type 0x%lx Node: %d Network: %d\n",
  535. EventType, NodeId, NetworkId ));
  536. }
  537. //
  538. // grab the event lock and loop through the file handles, looking to see
  539. // which ones are interested in this event
  540. //
  541. CnAcquireLock( &EventLock, &OldIrql );
  542. //
  543. // Indicate that a thread is iterating through the EventFileHandles
  544. // list to deliver events (kernel-mode callback counts as a delivery).
  545. //
  546. CnTrace(
  547. EVENT_DETAIL, IssueEventStartIteration,
  548. "[CN] CnIssueEvent: starting file handles list iteration."
  549. );
  550. CnStartEventDelivery();
  551. NextFsHandleEntry = EventFileHandles.Flink;
  552. if ( NextFsHandleEntry == &EventFileHandles ) {
  553. IF_CNDBG( CN_DEBUG_EVENT ) {
  554. CNPRINT(( "[CN] CnIssueEvent: No file objs on event file handle list\n"));
  555. }
  556. }
  557. while ( NextFsHandleEntry != &EventFileHandles ) {
  558. FsContext = CONTAINING_RECORD( NextFsHandleEntry, CN_FSCONTEXT, Linkage );
  559. if ( FsContext->EventMask & EventType ) {
  560. //
  561. // if kernel mode, then issue the callback
  562. //
  563. if ( FsContext->KmodeEventCallback ) {
  564. //
  565. // up the ref count so have a valid Flink when we return any
  566. // potential call out
  567. //
  568. CnReferenceFsContext( FsContext );
  569. CnReleaseLock( &EventLock, OldIrql );
  570. CnTrace(
  571. EVENT_DETAIL, IssueEventKmodeCallback,
  572. "[CN] CnIssueEvent: invoking kernel-mode callback %p "
  573. "for Event Type %u NodeId %u NetworkId %u.",
  574. FsContext->KmodeEventCallback,
  575. EventType,
  576. NodeId,
  577. NetworkId
  578. );
  579. (*FsContext->KmodeEventCallback)( EventType, NodeId, NetworkId );
  580. CnAcquireLock( &EventLock, &OldIrql );
  581. CnDereferenceFsContext( FsContext );
  582. } else {
  583. //
  584. // post a copy of this event on the handle's list.
  585. //
  586. Event = ExAllocateFromNPagedLookasideList( EventLookasideList );
  587. if ( Event == NULL ) {
  588. IF_CNDBG( CN_DEBUG_EVENT ) {
  589. CNPRINT(( "[CN] CnIssueEvent: No more Event buffers!\n"));
  590. }
  591. CnReleaseLock( &EventLock, OldIrql );
  592. return STATUS_INSUFFICIENT_RESOURCES;
  593. }
  594. Event->EventData.Epoch = InterlockedExchange( &EventEpoch, EventEpoch );
  595. Event->EventData.EventType = EventType;
  596. Event->EventData.NodeId = NodeId;
  597. Event->EventData.NetworkId = NetworkId;
  598. InsertTailList( &FsContext->EventList, &Event->Linkage );
  599. //
  600. // run the worker thread only if there is an IRP already queued
  601. //
  602. if ( FsContext->EventIrp ) {
  603. startupWorkerThread = TRUE;
  604. }
  605. }
  606. eventHandled = TRUE;
  607. }
  608. NextFsHandleEntry = FsContext->Linkage.Flink;
  609. }
  610. //
  611. // Indicate that iteration through the EventFileHandles list
  612. // is complete.
  613. //
  614. CnTrace(
  615. EVENT_DETAIL, IssueEventStartIteration,
  616. "[CN] CnIssueEvent: file handles list iteration complete."
  617. );
  618. startupWorkerThread |= CnStopEventDelivery();
  619. CnReleaseLock( &EventLock, OldIrql );
  620. if ( startupWorkerThread ) {
  621. //
  622. // schedule deliver event routine to run
  623. //
  624. CnTrace(
  625. EVENT_DETAIL, IssueEventScheduleWorker,
  626. "[CN] CnIssueEvent: scheduling worker thread."
  627. );
  628. EventWorkItem = IoAllocateWorkItem( CnDeviceObject );
  629. if ( EventWorkItem != NULL ) {
  630. IoQueueWorkItem(
  631. EventWorkItem,
  632. CnpDeliverEvents,
  633. DelayedWorkQueue,
  634. EventWorkItem
  635. );
  636. }
  637. }
  638. if ( !eventHandled ) {
  639. CnTrace(
  640. EVENT_DETAIL, IssueEventNoConsumers,
  641. "[CN] CnIssueEvent: No consumers for Event Type %u Node %u Network %u.",
  642. EventType, NodeId, NetworkId
  643. );
  644. IF_CNDBG( CN_DEBUG_EVENT ) {
  645. CNPRINT(( "[CN] CnIssueEvent: No consumers for Event type 0x%lx Node: %d Network: %d\n",
  646. EventType, NodeId, NetworkId ));
  647. }
  648. }
  649. CnVerifyCpuLockMask(
  650. 0, // Required
  651. CNP_EVENT_LOCK, // Forbidden
  652. CNP_EVENT_LOCK_PRECEEDING // Maximum
  653. );
  654. return STATUS_SUCCESS;
  655. } // CnIssueEvent
  656. VOID
  657. CnEventIrpCancel(
  658. PDEVICE_OBJECT DeviceObject,
  659. PIRP Irp
  660. )
  661. /*++
  662. Routine Description:
  663. Cancellation handler for CnGetNextEvent requests.
  664. Return Value:
  665. None
  666. Notes:
  667. Called with cancel spinlock held.
  668. Returns with cancel spinlock released.
  669. --*/
  670. {
  671. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  672. PFILE_OBJECT fileObject;
  673. CN_IRQL cancelIrql = Irp->CancelIrql;
  674. PCN_FSCONTEXT FsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  675. CnMarkIoCancelLockAcquired();
  676. fileObject = CnBeginCancelRoutine(Irp);
  677. CnAcquireLockAtDpc( &EventLock );
  678. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  679. CnTrace(
  680. EVENT_DETAIL, EventIrpCancel,
  681. "[CN] Cancelling event IRP %p.",
  682. Irp
  683. );
  684. IF_CNDBG( CN_DEBUG_EVENT ) {
  685. CNPRINT(("[CN] CnEventIrpCancel: canceling %p\n", Irp ));
  686. }
  687. CnAssert(DeviceObject == CnDeviceObject);
  688. //
  689. // We can only complete the irp if it really belongs to the Event code. The
  690. // IRP could have been completed before we acquired the Event lock.
  691. //
  692. if ( FsContext->EventIrp == Irp ) {
  693. FsContext->EventIrp = NULL;
  694. CnReleaseLock( &EventLock, cancelIrql );
  695. CnAcquireCancelSpinLock(&(Irp->CancelIrql));
  696. CnEndCancelRoutine(fileObject);
  697. CnCompletePendingRequest(Irp, STATUS_CANCELLED, 0);
  698. return;
  699. }
  700. CnReleaseLock( &EventLock, cancelIrql );
  701. CnAcquireCancelSpinLock( &cancelIrql );
  702. CnEndCancelRoutine(fileObject);
  703. CnReleaseCancelSpinLock(cancelIrql);
  704. CnVerifyCpuLockMask(
  705. 0, // Required
  706. 0xFFFFFFFF, // Forbidden
  707. 0 // Maximum
  708. );
  709. return;
  710. } // CnEventIrpCancel
  711. NTSTATUS
  712. CnGetNextEvent(
  713. IN PIRP Irp,
  714. IN PIO_STACK_LOCATION IrpSp
  715. )
  716. /*++
  717. Routine Description:
  718. This routine obtains the next event from the event list for
  719. this file handle. If an event is queued, it completes this IRP
  720. with the event data. Otherwise, the IRP is pended, waiting for
  721. an event to be posted.
  722. Return Value:
  723. STATUS_PENDING if IRP successfully captured
  724. STATUS_UNSUCCESSFUL if no more room in the list or IRP couldn't be
  725. Notes:
  726. Returns with cancel spinlock released.
  727. --*/
  728. {
  729. NTSTATUS Status;
  730. KIRQL OldIrql;
  731. PLIST_ENTRY Entry;
  732. PCLUSNET_EVENT_ENTRY Event;
  733. PCN_FSCONTEXT FsContext = IrpSp->FileObject->FsContext;
  734. PCLUSNET_EVENT_RESPONSE UserEventData = (PCLUSNET_EVENT_RESPONSE)
  735. Irp->AssociatedIrp.SystemBuffer;
  736. BOOLEAN DeliveryInProgress = FALSE;
  737. CnVerifyCpuLockMask(
  738. 0, // Required
  739. 0xFFFFFFFF, // Forbidden
  740. 0 // Maximum
  741. );
  742. //
  743. // acquire the IO cancel lock, then our event lock so we're synch'ed
  744. // with regards to the state of the IRP and the event list
  745. //
  746. CnAcquireCancelSpinLock( &OldIrql );
  747. CnAcquireLockAtDpc( &EventLock );
  748. //
  749. // check first if we have an event queued. if we have an event queued
  750. // and there is no delivery in progress we can complete the IRP now.
  751. // otherwise, we need to pend the IRP to avoid out-of-order delivery.
  752. //
  753. if ( !IsListEmpty( &FsContext->EventList )
  754. && !(DeliveryInProgress = CnIsEventDeliveryInProgress())
  755. ) {
  756. //
  757. // complete the IRP now
  758. //
  759. CnReleaseCancelSpinLock(DISPATCH_LEVEL);
  760. Entry = RemoveHeadList( &FsContext->EventList );
  761. CnReleaseLock( &EventLock, OldIrql );
  762. Event = CONTAINING_RECORD( Entry, CLUSNET_EVENT_ENTRY, Linkage );
  763. *UserEventData = Event->EventData;
  764. CnTrace(
  765. EVENT_DETAIL, GetNextEventCompletingIrp,
  766. "[CN] Completing IRP to deliver event: "
  767. "Epoch %u, Type %u, NodeId %u, NetworkId %u.",
  768. UserEventData->Epoch,
  769. UserEventData->EventType,
  770. UserEventData->NodeId,
  771. UserEventData->NetworkId
  772. );
  773. IF_CNDBG( CN_DEBUG_EVENT ) {
  774. CNPRINT(("[CN] CnGetNextEvent: completing IRP %p with event %d\n",
  775. Irp, Event->EventData.EventType));
  776. }
  777. ExFreeToNPagedLookasideList( EventLookasideList, Entry );
  778. Irp->IoStatus.Information = sizeof(CLUSNET_EVENT_RESPONSE);
  779. Status = STATUS_SUCCESS;
  780. } else {
  781. //
  782. // make sure we have room for the new IRP
  783. //
  784. if ( FsContext->EventIrp ) {
  785. CnReleaseCancelSpinLock( DISPATCH_LEVEL );
  786. CnTrace(
  787. EVENT_DETAIL, GetNextIrpAlreadyPending,
  788. "[CN] CnGetNextEvent: IRP %p is already pending.",
  789. FsContext->EventIrp
  790. );
  791. IF_CNDBG( CN_DEBUG_EVENT ) {
  792. CNPRINT(("[CN] CnGetNextEvent: IRP %p is already pending\n",
  793. FsContext->EventIrp));
  794. }
  795. Status = STATUS_UNSUCCESSFUL;
  796. } else {
  797. Status = CnMarkRequestPending( Irp, IrpSp, CnEventIrpCancel );
  798. CnAssert( NT_SUCCESS( Status ));
  799. CnReleaseCancelSpinLock( DISPATCH_LEVEL );
  800. if ( NT_SUCCESS( Status )) {
  801. //
  802. // remember this IRP in our open file context block
  803. //
  804. FsContext->EventIrp = Irp;
  805. CnTrace(
  806. EVENT_DETAIL, GetNextEventDeliveryInProgress,
  807. "[CN] CnGetNextEvent: pending IRP %p, "
  808. "delivery in progress: %!bool!",
  809. Irp, DeliveryInProgress
  810. );
  811. IF_CNDBG( CN_DEBUG_EVENT ) {
  812. CNPRINT(("[CN] CnGetNextEvent: pending IRP %p\n", Irp));
  813. }
  814. Status = STATUS_PENDING;
  815. }
  816. }
  817. CnReleaseLock(&EventLock, OldIrql);
  818. }
  819. CnVerifyCpuLockMask(
  820. 0, // Required
  821. 0xFFFFFFFF, // Forbidden
  822. 0 // Maximum
  823. );
  824. return Status;
  825. } // CnGetNextEvent
  826. /* end event.c */