2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
28 #define OVS_DBG_MOD OVS_DBG_EVENT
31 LIST_ENTRY ovsEventQueue
;
32 static NDIS_SPIN_LOCK eventQueueLock
;
33 UINT32 ovsNumEventQueue
;
39 InitializeListHead(&ovsEventQueue
);
40 NdisAllocateSpinLock(&eventQueueLock
);
41 return STATUS_SUCCESS
;
45 OvsCleanupEventQueue()
47 ASSERT(IsListEmpty(&ovsEventQueue
));
48 ASSERT(ovsNumEventQueue
== 0);
49 NdisFreeSpinLock(&eventQueueLock
);
53 OvsAcquireEventQueueLock()
55 NdisAcquireSpinLock(&eventQueueLock
);
59 OvsReleaseEventQueueLock()
61 NdisReleaseSpinLock(&eventQueueLock
);
65 * --------------------------------------------------------------------------
66 * Cleanup the event queue of the OpenInstance.
67 * --------------------------------------------------------------------------
70 OvsCleanupEvent(POVS_OPEN_INSTANCE instance
)
72 POVS_EVENT_QUEUE queue
;
74 queue
= (POVS_EVENT_QUEUE
)instance
->eventQueue
;
76 POVS_EVENT_QUEUE_ELEM elem
;
77 PLIST_ENTRY link
, next
;
79 OvsAcquireEventQueueLock();
80 RemoveEntryList(&queue
->queueLink
);
82 if (queue
->pendingIrp
) {
83 PDRIVER_CANCEL cancelRoutine
;
84 irp
= queue
->pendingIrp
;
85 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
86 queue
->pendingIrp
= NULL
;
87 if (cancelRoutine
== NULL
) {
91 instance
->eventQueue
= NULL
;
92 OvsReleaseEventQueueLock();
94 OvsCompleteIrpRequest(irp
, 0, STATUS_SUCCESS
);
97 LIST_FORALL_SAFE(&queue
->elemList
, link
, next
) {
98 elem
= CONTAINING_RECORD(link
, OVS_EVENT_QUEUE_ELEM
, link
);
99 OvsFreeMemoryWithTag(elem
, OVS_EVENT_POOL_TAG
);
101 OvsFreeMemoryWithTag(queue
, OVS_EVENT_POOL_TAG
);
106 * --------------------------------------------------------------------------
107 * When event is generated, we need to post the event to all
108 * the event queues. If there is pending Irp waiting for event
109 * complete the Irp to wakeup the user thread.
111 * Side effects: User thread may be woken up.
112 * --------------------------------------------------------------------------
115 OvsPostEvent(UINT32 portNo
,
118 POVS_EVENT_QUEUE_ELEM elem
;
119 POVS_EVENT_QUEUE queue
;
121 BOOLEAN triggerPollAll
= FALSE
;
126 InitializeListHead(&list
);
128 OVS_LOG_TRACE("Enter: portNo: %#x, status: %#x", portNo
, status
);
130 OvsAcquireEventQueueLock();
132 LIST_FORALL(&ovsEventQueue
, link
) {
133 queue
= CONTAINING_RECORD(link
, OVS_EVENT_QUEUE
, queueLink
);
134 if ((status
& queue
->mask
) == 0 ||
138 if (queue
->numElems
> (OVS_MAX_VPORT_ARRAY_SIZE
>> 1) ||
139 portNo
== OVS_DEFAULT_PORT_NO
) {
140 queue
->pollAll
= TRUE
;
142 elem
= (POVS_EVENT_QUEUE_ELEM
)OvsAllocateMemoryWithTag(
143 sizeof(*elem
), OVS_EVENT_POOL_TAG
);
145 queue
->pollAll
= TRUE
;
147 elem
->portNo
= portNo
;
148 elem
->status
= (status
& queue
->mask
);
149 InsertTailList(&queue
->elemList
, &elem
->link
);
151 OVS_LOG_INFO("Queue: %p, numElems: %d",
152 queue
, queue
->numElems
);
155 if (queue
->pollAll
) {
156 PLIST_ENTRY curr
, next
;
157 triggerPollAll
= TRUE
;
159 LIST_FORALL_SAFE(&queue
->elemList
, curr
, next
) {
160 RemoveEntryList(curr
);
161 elem
= CONTAINING_RECORD(curr
, OVS_EVENT_QUEUE_ELEM
, link
);
162 OvsFreeMemoryWithTag(elem
, OVS_EVENT_POOL_TAG
);
166 if (queue
->pendingIrp
!= NULL
) {
167 PDRIVER_CANCEL cancelRoutine
;
168 irp
= queue
->pendingIrp
;
169 queue
->pendingIrp
= NULL
;
170 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
172 InsertTailList(&list
, &irp
->Tail
.Overlay
.ListEntry
);
176 OvsReleaseEventQueueLock();
177 while (!IsListEmpty(&list
)) {
178 entry
= RemoveHeadList(&list
);
179 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
180 OVS_LOG_INFO("Wakeup thread with IRP: %p", irp
);
181 OvsCompleteIrpRequest(irp
, 0, STATUS_SUCCESS
);
183 OVS_LOG_TRACE("Exit: triggered pollAll: %s",
184 (triggerPollAll
? "TRUE" : "FALSE"));
189 * --------------------------------------------------------------------------
190 * Subscribe for event notification.
193 * STATUS_SUCCESS for valid request and enough resource.
194 * STATUS_NO_RESOURCES for queue allocation failure
195 * STATUS_INVALID_PARAMETER for invalid request
198 * Event queue is created for the current open instance.
199 * --------------------------------------------------------------------------
202 OvsSubscribeEventIoctl(PFILE_OBJECT fileObject
,
206 POVS_EVENT_SUBSCRIBE request
= (POVS_EVENT_SUBSCRIBE
)inputBuffer
;
207 NTSTATUS status
= STATUS_SUCCESS
;
208 POVS_OPEN_INSTANCE instance
;
209 POVS_EVENT_QUEUE queue
= NULL
;
211 OVS_LOG_TRACE("Enter: fileObject: %p, inputLength: %d", fileObject
,
214 if (inputLength
< sizeof (OVS_EVENT_SUBSCRIBE
) ||
215 (request
->mask
& OVS_EVENT_MASK_ALL
) == 0) {
216 OVS_LOG_TRACE("Exit: subscribe failed with invalid request.");
217 return STATUS_INVALID_PARAMETER
;
220 OvsAcquireEventQueueLock();
222 instance
= OvsGetOpenInstance(fileObject
, request
->dpNo
);
224 if (instance
== NULL
) {
225 status
= STATUS_INVALID_PARAMETER
;
226 OVS_LOG_WARN("can not find open instance");
227 goto done_event_subscribe
;
231 * XXX for now, we don't allow change mask.
233 queue
= (POVS_EVENT_QUEUE
)instance
->eventQueue
;
234 if (request
->subscribe
&& queue
) {
235 if (queue
->mask
!= request
->mask
) {
236 status
= STATUS_INVALID_PARAMETER
;
237 OVS_LOG_WARN("Can not chnage mask when the queue is subscribed");
239 status
= STATUS_SUCCESS
;
240 goto done_event_subscribe
;
241 } else if (!request
->subscribe
&& queue
== NULL
) {
242 status
= STATUS_SUCCESS
;
243 goto done_event_subscribe
;
246 if (request
->subscribe
) {
247 queue
= (POVS_EVENT_QUEUE
)OvsAllocateMemoryWithTag(
248 sizeof(OVS_EVENT_QUEUE
), OVS_EVENT_POOL_TAG
);
250 status
= STATUS_NO_MEMORY
;
251 OVS_LOG_WARN("Fail to allocate event queue");
252 goto done_event_subscribe
;
254 InitializeListHead(&queue
->elemList
);
255 queue
->mask
= request
->mask
;
256 queue
->pendingIrp
= NULL
;
258 queue
->pollAll
= TRUE
; /* always poll all in the begining */
259 InsertHeadList(&ovsEventQueue
, &queue
->queueLink
);
261 instance
->eventQueue
= queue
;
262 queue
->instance
= instance
;
264 queue
= (POVS_EVENT_QUEUE
)instance
->eventQueue
;
265 RemoveEntryList(&queue
->queueLink
);
267 instance
->eventQueue
= NULL
;
269 done_event_subscribe
:
270 if (!request
->subscribe
&& queue
) {
271 POVS_EVENT_QUEUE_ELEM elem
;
272 PLIST_ENTRY link
, next
;
274 if (queue
->pendingIrp
) {
275 PDRIVER_CANCEL cancelRoutine
;
276 irp
= queue
->pendingIrp
;
277 queue
->pendingIrp
= NULL
;
278 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
279 if (cancelRoutine
== NULL
) {
283 OvsReleaseEventQueueLock();
285 OvsCompleteIrpRequest(queue
->pendingIrp
, 0, STATUS_SUCCESS
);
287 LIST_FORALL_SAFE(&queue
->elemList
, link
, next
) {
288 elem
= CONTAINING_RECORD(link
, OVS_EVENT_QUEUE_ELEM
, link
);
289 OvsFreeMemoryWithTag(elem
, OVS_EVENT_POOL_TAG
);
291 OvsFreeMemoryWithTag(queue
, OVS_EVENT_POOL_TAG
);
293 OvsReleaseEventQueueLock();
295 OVS_LOG_TRACE("Exit: subscribe event with status: %#x.", status
);
300 * --------------------------------------------------------------------------
301 * Cancel wait IRP for event
303 * Please note, when this routine is called, it is always guaranteed that
306 * Side effects: Pending IRP is completed.
307 * --------------------------------------------------------------------------
310 OvsCancelIrp(PDEVICE_OBJECT deviceObject
,
313 PIO_STACK_LOCATION irpSp
;
314 PFILE_OBJECT fileObject
;
315 POVS_EVENT_QUEUE queue
;
316 POVS_OPEN_INSTANCE instance
;
318 UNREFERENCED_PARAMETER(deviceObject
);
320 IoReleaseCancelSpinLock(irp
->CancelIrql
);
322 irpSp
= IoGetCurrentIrpStackLocation(irp
);
323 fileObject
= irpSp
->FileObject
;
325 if (fileObject
== NULL
) {
328 OvsAcquireEventQueueLock();
329 instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
330 if (instance
== NULL
|| instance
->eventQueue
== NULL
) {
331 OvsReleaseEventQueueLock();
334 queue
= instance
->eventQueue
;
335 if (queue
->pendingIrp
== irp
) {
336 queue
->pendingIrp
= NULL
;
338 OvsReleaseEventQueueLock();
340 OvsCompleteIrpRequest(irp
, 0, STATUS_CANCELLED
);
344 * --------------------------------------------------------------------------
348 * STATUS_SUCCESS for valid request
349 * STATUS_DEVICE_BUSY if already in waiting state.
350 * STATUS_INVALID_PARAMETER for invalid request
351 * STATUS_PENDING wait for event
354 * May return pending to IO manager.
355 * --------------------------------------------------------------------------
358 OvsWaitEventIoctl(PIRP irp
,
359 PFILE_OBJECT fileObject
,
364 POVS_EVENT_POLL poll
;
365 POVS_EVENT_QUEUE queue
;
366 POVS_OPEN_INSTANCE instance
;
367 BOOLEAN cancelled
= FALSE
;
368 OVS_LOG_TRACE("Enter: inputLength: %u", inputLength
);
370 if (inputLength
< sizeof (OVS_EVENT_POLL
)) {
371 OVS_LOG_TRACE("Exit: Invalid input buffer length.");
372 return STATUS_INVALID_PARAMETER
;
374 poll
= (POVS_EVENT_POLL
)inputBuffer
;
376 OvsAcquireEventQueueLock();
378 instance
= OvsGetOpenInstance(fileObject
, poll
->dpNo
);
379 if (instance
== NULL
) {
380 OvsReleaseEventQueueLock();
381 OVS_LOG_TRACE("Exit: Can not find open instance, dpNo: %d", poll
->dpNo
);
382 return STATUS_INVALID_PARAMETER
;
385 queue
= (POVS_EVENT_QUEUE
)instance
->eventQueue
;
387 OvsReleaseEventQueueLock();
388 OVS_LOG_TRACE("Exit: Event queue does not exist");
389 return STATUS_INVALID_PARAMETER
;
391 if (queue
->pendingIrp
) {
392 OvsReleaseEventQueueLock();
393 OVS_LOG_TRACE("Exit: Event queue already in pending state");
394 return STATUS_DEVICE_BUSY
;
397 status
= (queue
->numElems
!= 0 || queue
->pollAll
) ?
398 STATUS_SUCCESS
: STATUS_PENDING
;
399 if (status
== STATUS_PENDING
) {
400 PDRIVER_CANCEL cancelRoutine
;
401 IoMarkIrpPending(irp
);
402 IoSetCancelRoutine(irp
, OvsCancelIrp
);
404 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
409 queue
->pendingIrp
= irp
;
412 OvsReleaseEventQueueLock();
414 OvsCompleteIrpRequest(irp
, 0, STATUS_CANCELLED
);
415 OVS_LOG_INFO("Event IRP cancelled: %p", irp
);
417 OVS_LOG_TRACE("Exit: return status: %#x", status
);
422 *--------------------------------------------------------------------------
423 * Poll event queued in the event queue.always synchronous.
426 * STATUS_SUCCESS event was dequeued
427 * STATUS_UNSUCCESSFUL the queue is empty.
428 * --------------------------------------------------------------------------
431 OvsRemoveEventEntry(POVS_OPEN_INSTANCE instance
,
432 POVS_EVENT_ENTRY entry
)
434 NTSTATUS status
= STATUS_UNSUCCESSFUL
;
435 POVS_EVENT_QUEUE queue
;
436 POVS_EVENT_QUEUE_ELEM elem
;
438 OvsAcquireEventQueueLock();
440 queue
= (POVS_EVENT_QUEUE
)instance
->eventQueue
;
444 goto remove_event_done
;
447 if (queue
->numElems
) {
448 elem
= (POVS_EVENT_QUEUE_ELEM
)RemoveHeadList(&queue
->elemList
);
449 entry
->portNo
= elem
->portNo
;
450 entry
->status
= elem
->status
;
451 OvsFreeMemoryWithTag(elem
, OVS_EVENT_POOL_TAG
);
453 status
= STATUS_SUCCESS
;
457 OvsReleaseEventQueueLock();