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.
27 #define OVS_DBG_MOD OVS_DBG_EVENT
30 LIST_ENTRY ovsEventQueue;
31 static NDIS_SPIN_LOCK eventQueueLock;
32 UINT32 ovsNumEventQueue;
38 InitializeListHead(&ovsEventQueue);
39 NdisAllocateSpinLock(&eventQueueLock);
40 return STATUS_SUCCESS;
44 OvsCleanupEventQueue()
46 ASSERT(IsListEmpty(&ovsEventQueue));
47 ASSERT(ovsNumEventQueue == 0);
48 NdisFreeSpinLock(&eventQueueLock);
52 OvsAcquireEventQueueLock()
54 NdisAcquireSpinLock(&eventQueueLock);
58 OvsReleaseEventQueueLock()
60 NdisReleaseSpinLock(&eventQueueLock);
64 * --------------------------------------------------------------------------
65 * Cleanup the event queue of the OpenInstance.
66 * --------------------------------------------------------------------------
69 OvsCleanupEvent(POVS_OPEN_INSTANCE instance)
71 POVS_EVENT_QUEUE queue;
73 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
75 POVS_EVENT_QUEUE_ELEM elem;
76 PLIST_ENTRY link, next;
78 OvsAcquireEventQueueLock();
79 RemoveEntryList(&queue->queueLink);
81 if (queue->pendingIrp) {
82 PDRIVER_CANCEL cancelRoutine;
83 irp = queue->pendingIrp;
84 cancelRoutine = IoSetCancelRoutine(irp, NULL);
85 queue->pendingIrp = NULL;
86 if (cancelRoutine == NULL) {
90 instance->eventQueue = NULL;
91 OvsReleaseEventQueueLock();
93 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
96 LIST_FORALL_SAFE(&queue->elemList, link, next) {
97 elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link);
100 OvsFreeMemory(queue);
105 * --------------------------------------------------------------------------
106 * When event is generated, we need to post the event to all
107 * the event queues. If there is pending Irp waiting for event
108 * complete the Irp to wakeup the user thread.
110 * Side effects: User thread may be woken up.
111 * --------------------------------------------------------------------------
114 OvsPostEvent(UINT32 portNo,
117 POVS_EVENT_QUEUE_ELEM elem;
118 POVS_EVENT_QUEUE queue;
120 BOOLEAN triggerPollAll = FALSE;
125 InitializeListHead(&list);
127 OVS_LOG_TRACE("Enter: portNo: %#x, status: %#x", portNo, status);
129 OvsAcquireEventQueueLock();
131 LIST_FORALL(&ovsEventQueue, link) {
132 queue = CONTAINING_RECORD(link, OVS_EVENT_QUEUE, queueLink);
133 if ((status & queue->mask) == 0 ||
137 if (queue->numElems > (OVS_MAX_VPORT_ARRAY_SIZE >> 1) ||
138 portNo == OVS_DEFAULT_PORT_NO) {
139 queue->pollAll = TRUE;
141 elem = (POVS_EVENT_QUEUE_ELEM)OvsAllocateMemory(sizeof(*elem));
143 queue->pollAll = TRUE;
145 elem->portNo = portNo;
146 elem->status = (status & queue->mask);
147 InsertTailList(&queue->elemList, &elem->link);
149 OVS_LOG_INFO("Queue: %p, numElems: %d",
150 queue, queue->numElems);
153 if (queue->pollAll) {
154 PLIST_ENTRY curr, next;
155 triggerPollAll = TRUE;
157 LIST_FORALL_SAFE(&queue->elemList, curr, next) {
158 RemoveEntryList(curr);
159 elem = CONTAINING_RECORD(curr, OVS_EVENT_QUEUE_ELEM, link);
164 if (queue->pendingIrp != NULL) {
165 PDRIVER_CANCEL cancelRoutine;
166 irp = queue->pendingIrp;
167 queue->pendingIrp = NULL;
168 cancelRoutine = IoSetCancelRoutine(irp, NULL);
170 InsertTailList(&list, &irp->Tail.Overlay.ListEntry);
174 OvsReleaseEventQueueLock();
175 while (!IsListEmpty(&list)) {
176 entry = RemoveHeadList(&list);
177 irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
178 OVS_LOG_INFO("Wakeup thread with IRP: %p", irp);
179 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
181 OVS_LOG_TRACE("Exit: triggered pollAll: %s",
182 (triggerPollAll ? "TRUE" : "FALSE"));
187 * --------------------------------------------------------------------------
188 * Subscribe for event notification.
191 * STATUS_SUCCESS for valid request and enough resource.
192 * STATUS_NO_RESOURCES for queue allocation failure
193 * STATUS_INVALID_PARAMETER for invalid request
196 * Event queue is created for the current open instance.
197 * --------------------------------------------------------------------------
200 OvsSubscribeEventIoctl(PFILE_OBJECT fileObject,
204 POVS_EVENT_SUBSCRIBE request = (POVS_EVENT_SUBSCRIBE)inputBuffer;
205 NTSTATUS status = STATUS_SUCCESS;
206 POVS_OPEN_INSTANCE instance;
207 POVS_EVENT_QUEUE queue = NULL;
209 OVS_LOG_TRACE("Enter: fileObject: %p, inputLength: %d", fileObject,
212 if (inputLength < sizeof (OVS_EVENT_SUBSCRIBE) ||
213 (request->mask & OVS_EVENT_MASK_ALL) == 0) {
214 OVS_LOG_TRACE("Exit: subscribe failed with invalid request.");
215 return STATUS_INVALID_PARAMETER;
218 OvsAcquireEventQueueLock();
220 instance = OvsGetOpenInstance(fileObject, request->dpNo);
222 if (instance == NULL) {
223 status = STATUS_INVALID_PARAMETER;
224 OVS_LOG_WARN("can not find open instance");
225 goto done_event_subscribe;
229 * XXX for now, we don't allow change mask.
231 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
232 if (request->subscribe && queue) {
233 if (queue->mask != request->mask) {
234 status = STATUS_INVALID_PARAMETER;
235 OVS_LOG_WARN("Can not chnage mask when the queue is subscribed");
237 status = STATUS_SUCCESS;
238 goto done_event_subscribe;
239 } else if (!request->subscribe && queue == NULL) {
240 status = STATUS_SUCCESS;
241 goto done_event_subscribe;
244 if (request->subscribe) {
245 queue = (POVS_EVENT_QUEUE)OvsAllocateMemory(sizeof (OVS_EVENT_QUEUE));
247 status = STATUS_NO_MEMORY;
248 OVS_LOG_WARN("Fail to allocate event queue");
249 goto done_event_subscribe;
251 InitializeListHead(&queue->elemList);
252 queue->mask = request->mask;
253 queue->pendingIrp = NULL;
255 queue->pollAll = TRUE; /* always poll all in the begining */
256 InsertHeadList(&ovsEventQueue, &queue->queueLink);
258 instance->eventQueue = queue;
259 queue->instance = instance;
261 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
262 RemoveEntryList(&queue->queueLink);
264 instance->eventQueue = NULL;
266 done_event_subscribe:
267 if (!request->subscribe && queue) {
268 POVS_EVENT_QUEUE_ELEM elem;
269 PLIST_ENTRY link, next;
271 if (queue->pendingIrp) {
272 PDRIVER_CANCEL cancelRoutine;
273 irp = queue->pendingIrp;
274 queue->pendingIrp = NULL;
275 cancelRoutine = IoSetCancelRoutine(irp, NULL);
276 if (cancelRoutine == NULL) {
280 OvsReleaseEventQueueLock();
282 OvsCompleteIrpRequest(queue->pendingIrp, 0, STATUS_SUCCESS);
284 LIST_FORALL_SAFE(&queue->elemList, link, next) {
285 elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link);
288 OvsFreeMemory(queue);
290 OvsReleaseEventQueueLock();
292 OVS_LOG_TRACE("Exit: subscribe event with status: %#x.", status);
296 #if defined OVS_USE_NL_INTERFACE && OVS_USE_NL_INTERFACE == 0
298 * --------------------------------------------------------------------------
299 * Poll event queued in the event queue. always synchronous.
302 * STATUS_SUCCESS for valid request
303 * STATUS_BUFFER_TOO_SMALL if outputBuffer is too small.
304 * STATUS_INVALID_PARAMETER for invalid request
307 * Event will be removed from event queue.
308 * --------------------------------------------------------------------------
311 OvsPollEventIoctl(PFILE_OBJECT fileObject,
318 POVS_EVENT_POLL poll;
319 POVS_EVENT_STATUS eventStatus;
320 POVS_EVENT_ENTRY entry;
321 POVS_EVENT_QUEUE queue;
322 POVS_EVENT_QUEUE_ELEM elem;
323 POVS_OPEN_INSTANCE instance;
326 OVS_LOG_TRACE("Enter: inputLength:%d, outputLength: %d",
327 inputLength, outputLength);
330 if (inputLength < sizeof (OVS_EVENT_POLL)) {
331 OVS_LOG_TRACE("Exit: input buffer too small");
332 return STATUS_INVALID_PARAMETER;
334 *replyLen = sizeof (OVS_EVENT_STATUS) + sizeof (OVS_EVENT_ENTRY);
335 if (outputLength < *replyLen) {
336 OVS_LOG_TRACE("Exit: output buffer too small");
337 return STATUS_BUFFER_TOO_SMALL;
339 poll = (POVS_EVENT_POLL)inputBuffer;
341 OvsAcquireEventQueueLock();
342 instance = OvsGetOpenInstance(fileObject, poll->dpNo);
343 if (instance == NULL) {
344 OvsReleaseEventQueueLock();
346 OVS_LOG_TRACE("Exit: can not find Open instance");
347 return STATUS_INVALID_PARAMETER;
350 eventStatus = (POVS_EVENT_STATUS)outputBuffer;
352 (outputLength - sizeof (OVS_EVENT_STATUS)) / sizeof (OVS_EVENT_ENTRY);
353 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
354 if (queue->pollAll) {
355 eventStatus->numberEntries = 1;
357 entry = &eventStatus->eventEntries[0];
358 entry->portNo = OVS_DEFAULT_PORT_NO;
359 entry->status = OVS_DEFAULT_EVENT_STATUS;
360 queue->pollAll = FALSE;
361 goto event_poll_done;
363 numEntry = MIN(numEntry, queue->numElems);
364 eventStatus->numberEntries = numEntry;
366 for (i = 0; i < numEntry; i++) {
367 elem = (POVS_EVENT_QUEUE_ELEM)RemoveHeadList(&queue->elemList);
368 entry = &eventStatus->eventEntries[i];
369 entry->portNo = elem->portNo;
370 entry->status = elem->status;
375 OvsReleaseEventQueueLock();
376 *replyLen = sizeof (OVS_EVENT_STATUS) +
377 numEntry * sizeof (OVS_EVENT_ENTRY);
378 OVS_LOG_TRACE("Exit: numEventPolled: %d", numEntry);
379 return STATUS_SUCCESS;
381 #endif /* OVS_USE_NL_INTERFACE */
385 * --------------------------------------------------------------------------
386 * Cancel wait IRP for event
388 * Please note, when this routine is called, it is always guaranteed that
391 * Side effects: Pending IRP is completed.
392 * --------------------------------------------------------------------------
395 OvsCancelIrp(PDEVICE_OBJECT deviceObject,
398 PIO_STACK_LOCATION irpSp;
399 PFILE_OBJECT fileObject;
400 POVS_EVENT_QUEUE queue;
401 POVS_OPEN_INSTANCE instance;
403 UNREFERENCED_PARAMETER(deviceObject);
405 IoReleaseCancelSpinLock(irp->CancelIrql);
407 irpSp = IoGetCurrentIrpStackLocation(irp);
408 fileObject = irpSp->FileObject;
410 if (fileObject == NULL) {
413 OvsAcquireEventQueueLock();
414 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
415 if (instance == NULL || instance->eventQueue == NULL) {
416 OvsReleaseEventQueueLock();
419 queue = instance->eventQueue;
420 if (queue->pendingIrp == irp) {
421 queue->pendingIrp = NULL;
423 OvsReleaseEventQueueLock();
425 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
429 * --------------------------------------------------------------------------
433 * STATUS_SUCCESS for valid request
434 * STATUS_DEVICE_BUSY if already in waiting state.
435 * STATUS_INVALID_PARAMETER for invalid request
436 * STATUS_PENDING wait for event
439 * May return pending to IO manager.
440 * --------------------------------------------------------------------------
443 OvsWaitEventIoctl(PIRP irp,
444 PFILE_OBJECT fileObject,
449 POVS_EVENT_POLL poll;
450 POVS_EVENT_QUEUE queue;
451 POVS_OPEN_INSTANCE instance;
452 BOOLEAN cancelled = FALSE;
453 OVS_LOG_TRACE("Enter: inputLength: %u", inputLength);
455 if (inputLength < sizeof (OVS_EVENT_POLL)) {
456 OVS_LOG_TRACE("Exit: Invalid input buffer length.");
457 return STATUS_INVALID_PARAMETER;
459 poll = (POVS_EVENT_POLL)inputBuffer;
461 OvsAcquireEventQueueLock();
463 instance = OvsGetOpenInstance(fileObject, poll->dpNo);
464 if (instance == NULL) {
465 OvsReleaseEventQueueLock();
466 OVS_LOG_TRACE("Exit: Can not find open instance, dpNo: %d", poll->dpNo);
467 return STATUS_INVALID_PARAMETER;
470 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
471 if (queue->pendingIrp) {
472 OvsReleaseEventQueueLock();
473 OVS_LOG_TRACE("Exit: Event queue already in pending state");
474 return STATUS_DEVICE_BUSY;
477 status = (queue->numElems != 0 || queue->pollAll) ?
478 STATUS_SUCCESS : STATUS_PENDING;
479 if (status == STATUS_PENDING) {
480 PDRIVER_CANCEL cancelRoutine;
481 IoMarkIrpPending(irp);
482 IoSetCancelRoutine(irp, OvsCancelIrp);
484 cancelRoutine = IoSetCancelRoutine(irp, NULL);
489 queue->pendingIrp = irp;
492 OvsReleaseEventQueueLock();
494 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
495 OVS_LOG_INFO("Event IRP cancelled: %p", irp);
497 OVS_LOG_TRACE("Exit: return status: %#x", status);
502 *--------------------------------------------------------------------------
503 * Poll event queued in the event queue.always synchronous.
506 * STATUS_SUCCESS event was dequeued
507 * STATUS_UNSUCCESSFUL the queue is empty.
508 * --------------------------------------------------------------------------
511 OvsRemoveEventEntry(POVS_OPEN_INSTANCE instance,
512 POVS_EVENT_ENTRY entry)
514 NTSTATUS status = STATUS_UNSUCCESSFUL;
515 POVS_EVENT_QUEUE queue;
516 POVS_EVENT_QUEUE_ELEM elem;
518 OvsAcquireEventQueueLock();
520 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
524 goto remove_event_done;
527 if (queue->numElems) {
528 elem = (POVS_EVENT_QUEUE_ELEM)RemoveHeadList(&queue->elemList);
529 entry->portNo = elem->portNo;
530 entry->status = elem->status;
533 status = STATUS_SUCCESS;
537 OvsReleaseEventQueueLock();