1
/*********************************************************
2
* Copyright (C) 2010 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation version 2 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
*********************************************************/
22
* This file implements Queue accessor methods.
24
* VMCIQPair is a new interface that hides the queue pair internals.
25
* Rather than access each queue in a pair directly, operations are now
26
* performed on the queue as a whole. This is simpler and less
27
* error-prone, and allows for future queue pair features to be added
28
* under the hood with no change to the client code.
30
* This also helps in a particular case on Windows hosts, where the memory
31
* allocated by the client (e.g., VMX) will disappear when the client does
32
* (e.g., abnormal termination). The kernel can't lock user memory into
33
* its address space indefinitely. By guarding access to the queue
34
* contents we can correctly handle the case where the client disappears.
38
* + This entire file started its life as a cut-and-paste of the
39
* static INLINE functions in bora/public/vmci_queue_pair.h.
40
* From there, new copies of the routines were made named
41
* without the prefix VMCI, without the underscore (the one
42
* that followed VMCIQueue_). The no-underscore versions of
43
* the routines require that the mutexes are held.
45
* + The code -always- uses the xyzLocked() version of any given
46
* routine even when the wrapped function is a one-liner. The
47
* reason for this decision was to ensure that we didn't have
48
* copies of logic lying around that needed to be maintained.
50
* + Note that we still pass around 'const VMCIQueue *'s.
52
* + Note that mutex is a field within VMCIQueue. We skirt the
53
* issue of passing around a const VMCIQueue, even though the
54
* mutex field (__mutex, specifically) will get modified by not
55
* ever referring to the mutex -itself- except during
56
* initialization. Beyond that, the code only passes the
57
* pointer to the mutex, which is also a member of VMCIQueue,
58
* obviously, and which doesn't change after initialization.
59
* This eliminates having to redefine all the functions that
60
* are currently taking const VMCIQueue's so that these
61
* functions are compatible with those definitions.
64
#include "vmci_kernel_if.h"
65
#include "vm_assert.h"
66
#include "vmci_handle_array.h"
67
#include "vmci_defs.h"
68
#include "vmciKernelAPI.h"
69
#include "vmciQueuePair.h"
70
#include "vmciRoute.h"
75
* This structure is opaque to the clients.
86
VMCIPrivilegeFlags privFlags;
90
#define VMCI_QPAIR_NO_QUEUE(_qp) (!(_qp)->produceQ->qHeader || \
91
!(_qp)->consumeQ->qHeader)
95
*-----------------------------------------------------------------------------
99
* This is the client interface for allocating the memory for a
100
* VMCIQPair structure and then attaching to the underlying
101
* queue. If an error occurs allocating the memory for the
102
* VMCIQPair structure, no attempt is made to attach. If an
103
* error occurs attaching, then there's the VMCIQPair structure
110
* Windows blocking call.
112
*-----------------------------------------------------------------------------
115
VMCI_EXPORT_SYMBOL(VMCIQPair_Alloc)
117
VMCIQPair_Alloc(VMCIQPair **qpair, // OUT
118
VMCIHandle *handle, // OUT
119
uint64 produceQSize, // IN
120
uint64 consumeQSize, // IN
123
VMCIPrivilegeFlags privFlags) // IN
127
VMCIHandle src = VMCI_INVALID_HANDLE;
128
VMCIHandle dst = VMCI_MAKE_HANDLE(peer, VMCI_INVALID_ID);
131
myQPair = VMCI_AllocKernelMem(sizeof *myQPair, VMCI_MEMORY_NONPAGED);
133
return VMCI_ERROR_NO_MEM;
135
memset(myQPair, 0, sizeof *myQPair);
137
myQPair->produceQSize = produceQSize;
138
myQPair->consumeQSize = consumeQSize;
139
myQPair->peer = peer;
140
myQPair->flags = flags;
141
myQPair->privFlags = privFlags;
143
retval = VMCI_Route(&src, &dst, FALSE, &route);
144
if (retval < VMCI_SUCCESS) {
145
if (VMCI_GuestPersonalityActive()) {
146
route = VMCI_ROUTE_AS_GUEST;
148
route = VMCI_ROUTE_AS_HOST;
152
if (VMCI_ROUTE_AS_HOST == route) {
153
myQPair->guestEndpoint = FALSE;
155
myQPair->guestEndpoint = TRUE;
158
retval = VMCIQueuePair_Alloc(handle,
160
myQPair->produceQSize,
162
myQPair->consumeQSize,
166
myQPair->guestEndpoint);
168
if (retval < VMCI_SUCCESS) {
169
VMCI_FreeKernelMem(myQPair, sizeof *myQPair);
174
myQPair->handle = *handle;
181
*-----------------------------------------------------------------------------
183
* VMCIQPair_Detach --
185
* This is the client interface for detaching from a VMCIQPair.
186
* Note that this routine will free the memory allocated for the
187
* VMCIQPair structure, too.
193
* Will clear the caller's pointer to the VMCIQPair structure.
195
*-----------------------------------------------------------------------------
198
VMCI_EXPORT_SYMBOL(VMCIQPair_Detach)
200
VMCIQPair_Detach(VMCIQPair **qpair) // IN/OUT
205
if (!qpair || !(*qpair)) {
206
return VMCI_ERROR_INVALID_ARGS;
210
result = VMCIQueuePair_Detach(oldQPair->handle, oldQPair->guestEndpoint);
212
if (result >= VMCI_SUCCESS) {
214
oldQPair->handle = VMCI_INVALID_HANDLE;
215
oldQPair->produceQ = NULL;
216
oldQPair->consumeQ = NULL;
217
oldQPair->produceQSize = 0;
218
oldQPair->consumeQSize = 0;
220
oldQPair->privFlags = 0;
221
oldQPair->peer = VMCI_INVALID_ID;
224
VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair);
234
* "Windows blocking call."
236
* Note that on the Windows platform, kernel module clients may
237
* block when calling into any these rouintes. The reason is
238
* that a mutex has to be acquired in order to view/modify the
239
* VMCIQueue structure fields: pointers, handle, and buffer data.
240
* However, other platforms don't require the acquisition of a
241
* mutex and thus don't block.
246
*-----------------------------------------------------------------------------
250
* Helper routine that will lock the QPair before subsequent operations.
256
* Windows blocking call.
258
*-----------------------------------------------------------------------------
262
VMCIQPairLock(const VMCIQPair *qpair) // IN
264
#if !defined VMX86_VMX
265
VMCI_AcquireQueueMutex(qpair->produceQ);
271
*-----------------------------------------------------------------------------
273
* VMCIQPair_Unlock --
275
* Helper routine that will unlock the QPair after various operations.
283
*-----------------------------------------------------------------------------
287
VMCIQPairUnlock(const VMCIQPair *qpair) // IN
289
#if !defined VMX86_VMX
290
VMCI_ReleaseQueueMutex(qpair->produceQ);
296
*-----------------------------------------------------------------------------
298
* VMCIQPair_GetProduceIndexes --
300
* This is the client interface for getting the current indexes of the
301
* QPair from the point of the view of the caller as the producer.
308
* Windows blocking call.
310
*-----------------------------------------------------------------------------
313
VMCI_EXPORT_SYMBOL(VMCIQPair_GetProduceIndexes)
315
VMCIQPair_GetProduceIndexes(const VMCIQPair *qpair, // IN
316
uint64 *producerTail, // OUT
317
uint64 *consumerHead) // OUT
322
return VMCI_ERROR_INVALID_ARGS;
325
VMCIQPairLock(qpair);
327
if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
328
result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
330
VMCIQueueHeader_GetPointers(qpair->produceQ->qHeader,
331
qpair->consumeQ->qHeader,
334
result = VMCI_SUCCESS;
337
VMCIQPairUnlock(qpair);
339
if (result == VMCI_SUCCESS &&
340
((producerTail && *producerTail >= qpair->produceQSize) ||
341
(consumerHead && *consumerHead >= qpair->produceQSize))) {
342
return VMCI_ERROR_INVALID_SIZE;
350
*-----------------------------------------------------------------------------
352
* VMCIQPair_GetConsumeIndexes --
354
* This is the client interface for getting the current indexes of the
355
* QPair from the point of the view of the caller as the consumer.
362
* Windows blocking call.
364
*-----------------------------------------------------------------------------
367
VMCI_EXPORT_SYMBOL(VMCIQPair_GetConsumeIndexes)
369
VMCIQPair_GetConsumeIndexes(const VMCIQPair *qpair, // IN
370
uint64 *consumerTail, // OUT
371
uint64 *producerHead) // OUT
376
return VMCI_ERROR_INVALID_ARGS;
379
VMCIQPairLock(qpair);
381
if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
382
result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
384
VMCIQueueHeader_GetPointers(qpair->consumeQ->qHeader,
385
qpair->produceQ->qHeader,
388
result = VMCI_SUCCESS;
391
VMCIQPairUnlock(qpair);
393
if (result == VMCI_SUCCESS &&
394
((consumerTail && *consumerTail >= qpair->consumeQSize) ||
395
(producerHead && *producerHead >= qpair->consumeQSize))) {
396
return VMCI_ERROR_INVALID_SIZE;
404
*-----------------------------------------------------------------------------
406
* VMCIQPair_ProduceFreeSpace --
408
* This is the client interface for getting the amount of free
409
* space in the QPair from the point of the view of the caller as
410
* the producer which is the common case.
415
* Number of available bytes into which data can be enqueued if > 0.
418
* Windows blocking call.
420
*-----------------------------------------------------------------------------
423
VMCI_EXPORT_SYMBOL(VMCIQPair_ProduceFreeSpace)
425
VMCIQPair_ProduceFreeSpace(const VMCIQPair *qpair) // IN
430
return VMCI_ERROR_INVALID_ARGS;
433
VMCIQPairLock(qpair);
435
if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
438
result = VMCIQueueHeader_FreeSpace(qpair->produceQ->qHeader,
439
qpair->consumeQ->qHeader,
440
qpair->produceQSize);
443
VMCIQPairUnlock(qpair);
450
*-----------------------------------------------------------------------------
452
* VMCIQPair_ConsumeFreeSpace --
454
* This is the client interface for getting the amount of free
455
* space in the QPair from the point of the view of the caller as
456
* the consumer which is not the common case (see
457
* VMCIQPair_ProduceFreeSpace(), above).
462
* Number of available bytes into which data can be enqueued if > 0.
465
* Windows blocking call.
467
*-----------------------------------------------------------------------------
470
VMCI_EXPORT_SYMBOL(VMCIQPair_ConsumeFreeSpace)
472
VMCIQPair_ConsumeFreeSpace(const VMCIQPair *qpair) // IN
477
return VMCI_ERROR_INVALID_ARGS;
480
VMCIQPairLock(qpair);
482
if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
485
result = VMCIQueueHeader_FreeSpace(qpair->consumeQ->qHeader,
486
qpair->produceQ->qHeader,
487
qpair->consumeQSize);
490
VMCIQPairUnlock(qpair);
497
*-----------------------------------------------------------------------------
499
* VMCIQPair_ProduceBufReady --
501
* This is the client interface for getting the amount of
502
* enqueued data in the QPair from the point of the view of the
503
* caller as the producer which is not the common case (see
504
* VMCIQPair_ConsumeBufReady(), above).
508
* Empty queue if = 0.
509
* Number of bytes ready to be dequeued if > 0.
512
* Windows blocking call.
514
*-----------------------------------------------------------------------------
517
VMCI_EXPORT_SYMBOL(VMCIQPair_ProduceBufReady)
519
VMCIQPair_ProduceBufReady(const VMCIQPair *qpair) // IN
524
return VMCI_ERROR_INVALID_ARGS;
527
VMCIQPairLock(qpair);
529
if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
532
result = VMCIQueueHeader_BufReady(qpair->produceQ->qHeader,
533
qpair->consumeQ->qHeader,
534
qpair->produceQSize);
537
VMCIQPairUnlock(qpair);
544
*-----------------------------------------------------------------------------
546
* VMCIQPair_ConsumeBufReady --
548
* This is the client interface for getting the amount of
549
* enqueued data in the QPair from the point of the view of the
550
* caller as the consumer which is the normal case.
554
* Empty queue if = 0.
555
* Number of bytes ready to be dequeued if > 0.
558
* Windows blocking call.
560
*-----------------------------------------------------------------------------
563
VMCI_EXPORT_SYMBOL(VMCIQPair_ConsumeBufReady)
565
VMCIQPair_ConsumeBufReady(const VMCIQPair *qpair) // IN
570
return VMCI_ERROR_INVALID_ARGS;
573
VMCIQPairLock(qpair);
575
if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
578
result = VMCIQueueHeader_BufReady(qpair->consumeQ->qHeader,
579
qpair->produceQ->qHeader,
580
qpair->consumeQSize);
583
VMCIQPairUnlock(qpair);
590
*-----------------------------------------------------------------------------
594
* Enqueues a given buffer to the produce queue using the provided
595
* function. As many bytes as possible (space available in the queue)
598
* Assumes the queue->mutex has been acquired.
601
* VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue data.
602
* VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
603
* (as defined by the queue size).
604
* VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
605
* VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
607
* Otherwise, the number of bytes written to the queue is returned.
610
* Updates the tail pointer of the produce queue.
612
*-----------------------------------------------------------------------------
615
static INLINE ssize_t
616
EnqueueLocked(VMCIQueue *produceQ, // IN
617
const VMCIQueue *consumeQ, // IN
618
const uint64 produceQSize, // IN
619
const void *buf, // IN
620
size_t bufSize, // IN
622
VMCIMemcpyToQueueFunc memcpyToQueue) // IN
629
#if !defined VMX86_VMX
630
if (UNLIKELY(VMCI_EnqueueToDevNull(produceQ))) {
631
return (ssize_t) bufSize;
634
if (UNLIKELY(!produceQ->qHeader || !consumeQ->qHeader)) {
635
return VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
639
freeSpace = VMCIQueueHeader_FreeSpace(produceQ->qHeader,
642
if (freeSpace == 0) {
643
return VMCI_ERROR_QUEUEPAIR_NOSPACE;
646
if (freeSpace < VMCI_SUCCESS) {
647
return (ssize_t)freeSpace;
650
written = (size_t)(freeSpace > bufSize ? bufSize : freeSpace);
651
tail = VMCIQueueHeader_ProducerTail(produceQ->qHeader);
652
if (LIKELY(tail + written < produceQSize)) {
653
result = memcpyToQueue(produceQ, tail, buf, 0, written, bufType);
655
/* Tail pointer wraps around. */
657
const size_t tmp = (size_t)(produceQSize - tail);
659
result = memcpyToQueue(produceQ, tail, buf, 0, tmp, bufType);
660
if (result >= VMCI_SUCCESS) {
661
result = memcpyToQueue(produceQ, 0, buf, tmp, written - tmp, bufType);
665
if (result < VMCI_SUCCESS) {
669
VMCIQueueHeader_AddProducerTail(produceQ->qHeader, written, produceQSize);
675
*-----------------------------------------------------------------------------
679
* Dequeues data (if available) from the given consume queue. Writes data
680
* to the user provided buffer using the provided function.
682
* Assumes the queue->mutex has been acquired.
685
* VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
686
* VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
687
* (as defined by the queue size).
688
* VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
689
* Otherwise the number of bytes dequeued is returned.
692
* Updates the head pointer of the consume queue.
694
*-----------------------------------------------------------------------------
697
static INLINE ssize_t
698
DequeueLocked(VMCIQueue *produceQ, // IN
699
const VMCIQueue *consumeQ, // IN
700
const uint64 consumeQSize, // IN
702
size_t bufSize, // IN
704
VMCIMemcpyFromQueueFunc memcpyFromQueue, // IN
705
Bool updateConsumer) // IN
712
#if !defined VMX86_VMX
713
if (UNLIKELY(!produceQ->qHeader ||
714
!consumeQ->qHeader)) {
715
return VMCI_ERROR_QUEUEPAIR_NODATA;
719
bufReady = VMCIQueueHeader_BufReady(consumeQ->qHeader,
723
return VMCI_ERROR_QUEUEPAIR_NODATA;
725
if (bufReady < VMCI_SUCCESS) {
726
return (ssize_t)bufReady;
729
read = (size_t)(bufReady > bufSize ? bufSize : bufReady);
730
head = VMCIQueueHeader_ConsumerHead(produceQ->qHeader);
731
if (LIKELY(head + read < consumeQSize)) {
732
result = memcpyFromQueue(buf, 0, consumeQ, head, read, bufType);
734
/* Head pointer wraps around. */
736
const size_t tmp = (size_t)(consumeQSize - head);
738
result = memcpyFromQueue(buf, 0, consumeQ, head, tmp, bufType);
739
if (result >= VMCI_SUCCESS) {
740
result = memcpyFromQueue(buf, tmp, consumeQ, 0, read - tmp, bufType);
744
if (result < VMCI_SUCCESS) {
748
if (updateConsumer) {
749
VMCIQueueHeader_AddConsumerHead(produceQ->qHeader,
759
*-----------------------------------------------------------------------------
761
* VMCIQPair_Enqueue --
763
* This is the client interface for enqueueing data into the queue.
767
* Number of bytes enqueued if >= 0.
770
* Windows blocking call.
772
*-----------------------------------------------------------------------------
775
VMCI_EXPORT_SYMBOL(VMCIQPair_Enqueue)
777
VMCIQPair_Enqueue(VMCIQPair *qpair, // IN
778
const void *buf, // IN
779
size_t bufSize, // IN
784
if (!qpair || !buf) {
785
return VMCI_ERROR_INVALID_ARGS;
788
VMCIQPairLock(qpair);
790
result = EnqueueLocked(qpair->produceQ,
793
buf, bufSize, bufType,
796
VMCIQPairUnlock(qpair);
803
*-----------------------------------------------------------------------------
805
* VMCIQPair_Dequeue --
807
* This is the client interface for dequeueing data from the queue.
811
* Number of bytes dequeued if >= 0.
814
* Windows blocking call.
816
*-----------------------------------------------------------------------------
819
VMCI_EXPORT_SYMBOL(VMCIQPair_Dequeue)
821
VMCIQPair_Dequeue(VMCIQPair *qpair, // IN
823
size_t bufSize, // IN
828
if (!qpair || !buf) {
829
return VMCI_ERROR_INVALID_ARGS;
832
VMCIQPairLock(qpair);
834
result = DequeueLocked(qpair->produceQ,
837
buf, bufSize, bufType,
841
VMCIQPairUnlock(qpair);
848
*-----------------------------------------------------------------------------
852
* This is the client interface for peeking into a queue. (I.e.,
853
* copy data from the queue without updating the head pointer.)
857
* Number of bytes peeked, if >= 0.
860
* Windows blocking call.
862
*-----------------------------------------------------------------------------
865
VMCI_EXPORT_SYMBOL(VMCIQPair_Peek)
867
VMCIQPair_Peek(VMCIQPair *qpair, // IN
869
size_t bufSize, // IN
874
if (!qpair || !buf) {
875
return VMCI_ERROR_INVALID_ARGS;
878
VMCIQPairLock(qpair);
880
result = DequeueLocked(qpair->produceQ,
883
buf, bufSize, bufType,
887
VMCIQPairUnlock(qpair);
893
#if defined (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \
894
(defined(__linux__) && defined(__KERNEL__)) || \
895
(defined(_WIN32) && defined(WINNT_DDK))
898
*-----------------------------------------------------------------------------
900
* VMCIQPair_EnqueueV --
902
* This is the client interface for enqueueing data into the queue.
906
* Number of bytes enqueued if >= 0.
909
* Windows blocking call.
911
*-----------------------------------------------------------------------------
914
VMCI_EXPORT_SYMBOL(VMCIQPair_EnqueueV)
916
VMCIQPair_EnqueueV(VMCIQPair *qpair, // IN
918
size_t iovSize, // IN
923
if (!qpair || !iov) {
924
return VMCI_ERROR_INVALID_ARGS;
927
VMCIQPairLock(qpair);
929
result = EnqueueLocked(qpair->produceQ,
932
iov, iovSize, bufType,
935
VMCIQPairUnlock(qpair);
942
*-----------------------------------------------------------------------------
944
* VMCIQPair_DequeueV --
946
* This is the client interface for dequeueing data from the queue.
950
* Number of bytes dequeued if >= 0.
953
* Windows blocking call.
955
*-----------------------------------------------------------------------------
958
VMCI_EXPORT_SYMBOL(VMCIQPair_DequeueV)
960
VMCIQPair_DequeueV(VMCIQPair *qpair, // IN
962
size_t iovSize, // IN
967
VMCIQPairLock(qpair);
969
if (!qpair || !iov) {
970
return VMCI_ERROR_INVALID_ARGS;
973
result = DequeueLocked(qpair->produceQ,
976
iov, iovSize, bufType,
977
VMCIMemcpyFromQueueV,
980
VMCIQPairUnlock(qpair);
987
*-----------------------------------------------------------------------------
991
* This is the client interface for peeking into a queue. (I.e.,
992
* copy data from the queue without updating the head pointer.)
996
* Number of bytes peeked, if >= 0.
999
* Windows blocking call.
1001
*-----------------------------------------------------------------------------
1004
VMCI_EXPORT_SYMBOL(VMCIQPair_PeekV)
1006
VMCIQPair_PeekV(VMCIQPair *qpair, // IN
1008
size_t iovSize, // IN
1013
if (!qpair || !iov) {
1014
return VMCI_ERROR_INVALID_ARGS;
1017
VMCIQPairLock(qpair);
1019
result = DequeueLocked(qpair->produceQ,
1021
qpair->consumeQSize,
1022
iov, iovSize, bufType,
1023
VMCIMemcpyFromQueueV,
1026
VMCIQPairUnlock(qpair);
1031
#endif /* Systems that support struct iovec */