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();