]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Unify VMCI guest and host queue pair code.
authorVMware, Inc <>
Tue, 29 Mar 2011 18:48:16 +0000 (11:48 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Tue, 29 Mar 2011 18:48:16 +0000 (11:48 -0700)
This change unifies the two VMCI queue pair implementations
for guest and host. The main part of the change is moving the
guest functions to the host module, and add the use of the
VMCI routing function in the vmciQPair module to correctly
select either guest or host routes. For vmkernel, we still
disable most of the guest functionality, since the vmkernel
has its own implementation of much of the queue pair code
anyway. To reduce the vmkernel only part of the queue pair
code is left as a future clean up task.

Other notable changes were that for both Linux and Mac, the
host and guest tracked queue pairs differently
(VMCIQueueKernelIf). For Linux, it was straight forward to
combine the two at the cost of adding a pointer to the
VMCIQueueKernelIf structure in the guest. For Mac OS, the host
and the guest take completely different approaches, so the
unified VMCIQueueKernelIf is now a union of the host and guest
versions.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/modules/linux/shared/vmci_kernel_if.h
open-vm-tools/modules/linux/vmci/stubs.c
open-vm-tools/modules/linux/vmci/vmciKernelIf.c
open-vm-tools/modules/linux/vmci/vmciQPair.c
open-vm-tools/modules/linux/vmci/vmciQueuePair.c
open-vm-tools/modules/linux/vmci/vmciQueuePair.h
open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h [deleted file]
open-vm-tools/modules/linux/vmci/vmci_drv.c
open-vm-tools/modules/linux/vmci/vmci_version.h

index 51bc36423ec0525e8e7906881befe6692d44773e..296c1dd09d68774912000c34ce265170a2ebe079 100644 (file)
@@ -29,7 +29,7 @@
 
 #if !defined(linux) && !defined(_WIN32) && !defined(__APPLE__) && \
     !defined(VMKERNEL) && !defined(SOLARIS)
-#error "Platform not supported."
+#  error "Platform not supported."
 #endif
 
 #if defined(_WIN32)
 #endif
 
 #if defined(linux) && !defined(VMKERNEL)
-#  include <linux/wait.h>
+#  include "driver-config.h"
 #  include "compat_cred.h"
+#  include "compat_module.h"
 #  include "compat_semaphore.h"
 #  include "compat_spinlock.h"
 #  include "compat_version.h"
+#  include <linux/wait.h>
 #endif // linux
 
 #ifdef __APPLE__
@@ -317,8 +319,7 @@ int VMCI_PopulatePPNList(uint8 *callBuf, const PPNSet *ppnSet);
 
 struct VMCIQueue;
 
-#if !defined(VMX86_TOOLS)
-#if  !defined(VMKERNEL)
+#if !defined(VMKERNEL)
 struct PageStoreAttachInfo;
 struct VMCIQueue *VMCIHost_AllocQueue(uint64 queueSize);
 void VMCIHost_FreeQueue(struct VMCIQueue *queue, uint64 queueSize);
@@ -343,8 +344,6 @@ void VMCIHost_SaveProduceQ(struct PageStoreAttachInfo *attach,
                            const uint64 produceQSize);
 #endif // _WIN32
 
-#endif // !VMX86_TOOLS
-
 #ifdef _WIN32
 void VMCI_InitQueueMutex(struct VMCIQueue *produceQ,
                              struct VMCIQueue *consumeQ);
index c2da3e1955c75d6531d17124f6171f837dc25da5..304cff5c39147eb474ee8d46c7c82cc096e97010 100644 (file)
 #include "vmciDoorbell.h"
 
 
-/*
- *------------------------------------------------------------------------------
- *
- *  VMCIQPBroker_Lock --
- *
- *     Stub.  Not called in the guest driver (yet).
- *
- *  Result:
- *     Always VMCI_ERROR_GENERIC.
- *
- *------------------------------------------------------------------------------
- */
-void
-VMCIQPBroker_Lock(void)
-{
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- *  VMCIQPBroker_Unlock --
- *
- *     Stub.  Not called in the guest driver (yet).
- *
- *  Result:
- *     Always VMCI_ERROR_GENERIC.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIQPBroker_Unlock(void)
-{
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- *  QueuePair_Detach --
- *
- *     Stub.  Not called in the guest driver (yet).
- *
- *  Result:
- *     Always VMCI_ERROR_GENERIC.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_Detach(VMCIHandle handle,
-                    VMCIContext *context,
-                    Bool detach)
-{
-   return VMCI_ERROR_GENERIC;
-}
-
-
 /*
  *------------------------------------------------------------------------------
  *
index 2ebc61f7bd343c4d54a1c78ff04102bbb959a5d7..0c06e75f35383b51a3ccbbb5c6dd58e7b64ca4d7 100644 (file)
 #include "compat_page.h"
 #include "compat_mm.h"
 #include "compat_highmem.h"
-#include "vm_basic_types.h"
 #include "vm_assert.h"
+#include "vm_basic_types.h"
+#include "vmci_iocontrols.h"
 #include "vmci_kernel_if.h"
-#ifndef VMX86_TOOLS
-#  include "vmciQueuePair.h"
-#endif
-
 #include "vmciQueue.h"
-#include "vmci_iocontrols.h"
+#include "vmciQueuePair.h"
 
 
 /*
  * The Kernel specific component of the VMCIQueue structure.
  */
 
-#if defined VMX86_TOOLS
-struct VMCIQueueKernelIf {
-   struct page *page[0];
-};
-#else
 struct VMCIQueueKernelIf {
    struct page **page;
 };
-#endif
 
 typedef struct VMCIDelayedWorkInfo {
    compat_work work;
@@ -860,7 +851,6 @@ VMCIMutex_Release(VMCIMutex *mutex) // IN:
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *-----------------------------------------------------------------------------
  *
@@ -893,8 +883,8 @@ VMCI_AllocQueue(uint64 size) // IN: size of queue (not including header)
    const uint64 numDataPages = CEILING(size, PAGE_SIZE);
    const uint queueSize =
       PAGE_SIZE +
-      sizeof *queue +
-      numDataPages * sizeof queue->kernelIf->page[0];
+      sizeof *queue + sizeof *(queue->kernelIf) +
+      numDataPages * sizeof *(queue->kernelIf->page);
 
    qHeader = (VMCIQueueHeader *)vmalloc(queueSize);
    if (!qHeader) {
@@ -904,6 +894,8 @@ VMCI_AllocQueue(uint64 size) // IN: size of queue (not including header)
    queue = (VMCIQueue *)((uint8 *)qHeader + PAGE_SIZE);
    queue->qHeader = qHeader;
    queue->kernelIf = (VMCIQueueKernelIf *)((uint8 *)queue + sizeof *queue);
+   queue->kernelIf->page = (struct page **)((uint8 *)queue->kernelIf +
+                                            sizeof *(queue->kernelIf));
 
    for (i = 0; i < numDataPages; i++) {
       queue->kernelIf->page[i] = alloc_pages(GFP_KERNEL, 0);
@@ -1116,7 +1108,6 @@ VMCI_PopulatePPNList(uint8 *callBuf,       // OUT:
 
    return VMCI_SUCCESS;
 }
-#endif
 
 
 #ifdef __KERNEL__
@@ -1410,8 +1401,6 @@ VMCIWellKnownID_AllowMap(VMCIId wellKnownID,           // IN:
 }
 
 
-#ifndef VMX86_TOOLS
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -1635,5 +1624,3 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach,      // IN/OUT
                       attach->numConsumePages *
                       sizeof attach->consumePages[0]);
 }
-
-#endif  /* Host only code */
index 329bed6276d40b336cfe3aaa3f5f2431b863e091..9aafba908126d93ff0542c15bcba27155d6c7901 100644 (file)
  *        functions are compatible with those definitions.
  */
 
-/* Must come before any kernel header file. */
-#if defined(__linux__) && !defined(VMKERNEL)
-#  include "driver-config.h"
-#  include "compat_module.h"
-#endif
-
 #include "vmci_kernel_if.h"
 #include "vm_assert.h"
 #include "vmci_handle_array.h"
 #include "vmci_defs.h"
-#if defined VMKERNEL || !defined VMX86_TOOLS
-#  include "vmciQueuePair.h"
-#else
-#  include "vmciGuestKernelIf.h"
-#  include "vmciQueuePairInt.h"
-#endif
-
 #include "vmciKernelAPI.h"
+#include "vmciQueuePair.h"
+#include "vmciRoute.h"
 
 /*
  * VMCIQPair
@@ -95,6 +84,7 @@ struct VMCIQPair {
    VMCIId peer;
    uint32 flags;
    VMCIPrivilegeFlags privFlags;
+   Bool guestEndpoint;
 };
 
 #define VMCI_QPAIR_NO_QUEUE(_qp) (!(_qp)->produceQ->qHeader || \
@@ -134,6 +124,9 @@ VMCIQPair_Alloc(VMCIQPair **qpair,            // OUT
 {
    VMCIQPair *myQPair;
    int retval;
+   VMCIHandle src = VMCI_INVALID_HANDLE;
+   VMCIHandle dst = VMCI_MAKE_HANDLE(peer, VMCI_INVALID_ID);
+   VMCIRoute route;
 
    myQPair = VMCI_AllocKernelMem(sizeof *myQPair, VMCI_MEMORY_NONPAGED);
    if (!myQPair) {
@@ -147,6 +140,21 @@ VMCIQPair_Alloc(VMCIQPair **qpair,            // OUT
    myQPair->flags = flags;
    myQPair->privFlags = privFlags;
 
+   retval = VMCI_Route(&src, &dst, FALSE, &route);
+   if (retval < VMCI_SUCCESS) {
+      if (VMCI_HasGuestDevice()) {
+         route = VMCI_ROUTE_AS_GUEST;
+      } else {
+         route = VMCI_ROUTE_AS_HOST;
+      }
+   }
+
+   if (VMCI_ROUTE_AS_HOST == route) {
+      myQPair->guestEndpoint = FALSE;
+   } else {
+      myQPair->guestEndpoint = TRUE;
+   }
+
    retval = VMCIQueuePair_Alloc(handle,
                                 &myQPair->produceQ,
                                 myQPair->produceQSize,
@@ -154,7 +162,8 @@ VMCIQPair_Alloc(VMCIQPair **qpair,            // OUT
                                 myQPair->consumeQSize,
                                 myQPair->peer,
                                 myQPair->flags,
-                                myQPair->privFlags);
+                                myQPair->privFlags,
+                                myQPair->guestEndpoint);
 
    if (retval < VMCI_SUCCESS) {
       VMCI_FreeKernelMem(myQPair, sizeof *myQPair);
@@ -198,7 +207,7 @@ VMCIQPair_Detach(VMCIQPair **qpair) // IN/OUT
    }
 
    oldQPair = *qpair;
-   result = VMCIQueuePair_Detach(oldQPair->handle);
+   result = VMCIQueuePair_Detach(oldQPair->handle, oldQPair->guestEndpoint);
 
    if  (result >= VMCI_SUCCESS) {
 #ifdef DEBUG
@@ -700,7 +709,7 @@ DequeueLocked(VMCIQueue *produceQ,                        // IN
    size_t read;
    ssize_t result;
 
-#if !defined VMX86_TOOLS && !defined VMX86_VMX
+#if !defined VMX86_VMX
    if (UNLIKELY(!produceQ->qHeader ||
                 !consumeQ->qHeader)) {
       return VMCI_ERROR_QUEUEPAIR_NODATA;
@@ -778,11 +787,11 @@ VMCIQPair_Enqueue(VMCIQPair *qpair,        // IN
 
    VMCIQPairLock(qpair);
 
-   result =  EnqueueLocked(qpair->produceQ,
-                           qpair->consumeQ,
-                           qpair->produceQSize,
-                           buf, bufSize, bufType,
-                           VMCIMemcpyToQueue);
+   result = EnqueueLocked(qpair->produceQ,
+                          qpair->consumeQ,
+                          qpair->produceQSize,
+                          buf, bufSize, bufType,
+                          VMCIMemcpyToQueue);
 
    VMCIQPairUnlock(qpair);
 
@@ -822,12 +831,12 @@ VMCIQPair_Dequeue(VMCIQPair *qpair,        // IN
 
    VMCIQPairLock(qpair);
 
-   result =  DequeueLocked(qpair->produceQ,
-                           qpair->consumeQ,
-                           qpair->consumeQSize,
-                           buf, bufSize, bufType,
-                           VMCIMemcpyFromQueue,
-                           TRUE);
+   result = DequeueLocked(qpair->produceQ,
+                          qpair->consumeQ,
+                          qpair->consumeQSize,
+                          buf, bufSize, bufType,
+                          VMCIMemcpyFromQueue,
+                          TRUE);
 
    VMCIQPairUnlock(qpair);
 
@@ -868,12 +877,12 @@ VMCIQPair_Peek(VMCIQPair *qpair,    // IN
 
    VMCIQPairLock(qpair);
 
-   result =  DequeueLocked(qpair->produceQ,
-                           qpair->consumeQ,
-                           qpair->consumeQSize,
-                           buf, bufSize, bufType,
-                           VMCIMemcpyFromQueue,
-                           FALSE);
+   result = DequeueLocked(qpair->produceQ,
+                          qpair->consumeQ,
+                          qpair->consumeQSize,
+                          buf, bufSize, bufType,
+                          VMCIMemcpyFromQueue,
+                          FALSE);
 
    VMCIQPairUnlock(qpair);
 
@@ -917,11 +926,11 @@ VMCIQPair_EnqueueV(VMCIQPair *qpair,        // IN
 
    VMCIQPairLock(qpair);
 
-   result =  EnqueueLocked(qpair->produceQ,
-                           qpair->consumeQ,
-                           qpair->produceQSize,
-                           iov, iovSize, bufType,
-                           VMCIMemcpyToQueueV);
+   result = EnqueueLocked(qpair->produceQ,
+                          qpair->consumeQ,
+                          qpair->produceQSize,
+                          iov, iovSize, bufType,
+                          VMCIMemcpyToQueueV);
 
    VMCIQPairUnlock(qpair);
 
@@ -961,12 +970,12 @@ VMCIQPair_DequeueV(VMCIQPair *qpair,         // IN
       return VMCI_ERROR_INVALID_ARGS;
    }
 
-   result =  DequeueLocked(qpair->produceQ,
-                           qpair->consumeQ,
-                           qpair->consumeQSize,
-                           iov, iovSize, bufType,
-                           VMCIMemcpyFromQueueV,
-                           TRUE);
+   result = DequeueLocked(qpair->produceQ,
+                          qpair->consumeQ,
+                          qpair->consumeQSize,
+                          iov, iovSize, bufType,
+                          VMCIMemcpyFromQueueV,
+                          TRUE);
 
    VMCIQPairUnlock(qpair);
 
@@ -1007,12 +1016,12 @@ VMCIQPair_PeekV(VMCIQPair *qpair,           // IN
 
    VMCIQPairLock(qpair);
 
-   result =  DequeueLocked(qpair->produceQ,
-                           qpair->consumeQ,
-                           qpair->consumeQSize,
-                           iov, iovSize, bufType,
-                           VMCIMemcpyFromQueueV,
-                           FALSE);
+   result = DequeueLocked(qpair->produceQ,
+                          qpair->consumeQ,
+                          qpair->consumeQSize,
+                          iov, iovSize, bufType,
+                          VMCIMemcpyFromQueueV,
+                          FALSE);
 
    VMCIQPairUnlock(qpair);
 
index 6da36ab7cd008c02cdeb7359d927f61b59cc00a2..862c1601195d35772cd303133b23fd3f885abf32 100644 (file)
 /*
  * vmciQueuePair.c --
  *
- *     Implements the VMCI QueuePair API.
+ *    VMCI QueuePair API implementation in the host driver.
  */
 
-#ifdef __linux__
+#if defined(__linux__) && !defined(VMKERNEL)
 #  include "driver-config.h"
-#  include <asm/page.h>
-#  include <linux/module.h>
-#elif defined(_WIN32)
-#  include <wdm.h>
-#elif defined(__APPLE__)
-#  include <IOKit/IOLib.h>
-#endif /* __linux__ */
-
+#  include "compat_kernel.h"
+#  include "compat_module.h"
+#endif // __linux__
+#include "vmci_kernel_if.h"
 #include "vm_assert.h"
-#include "vm_atomic.h"
+#include "vmci_defs.h"
 #include "vmci_handle_array.h"
-#include "vmci_kernel_if.h"
+#include "vmci_infrastructure.h"
+#include "vmciCommonInt.h"
+#include "vmciContext.h"
+#include "vmciDatagram.h"
 #include "vmciEvent.h"
-#include "vmciInt.h"
+#include "vmciHashtable.h"
 #include "vmciKernelAPI.h"
-#include "vmciQueuePairInt.h"
-#include "vmciUtil.h"
+#include "vmciQueuePair.h"
+#include "vmciResource.h"
+#include "vmciRoute.h"
+#ifdef VMX86_TOOLS
+#  include "vmciInt.h"
+#  include "vmciUtil.h"
+#elif defined(VMKERNEL)
+#  include "vmciVmkInt.h"
+#  include "vm_libc.h"
+#  include "helper_ext.h"
+#  include "vmciDriver.h"
+#else
+#  include "vmciDriver.h"
+#endif
+
+#define LGPFX "VMCIQueuePair: "
+
+/*
+ * The context that creates the QueuePair becomes producer of produce queue,
+ * and consumer of consume queue. The context on other end for the QueuePair
+ * has roles reversed for these two queues.
+ */
+
+typedef struct QueuePairEntry {
+   VMCIListItem       listItem;
+   VMCIHandle         handle;
+   VMCIId             peer;
+   uint32             flags;
+   uint64             produceSize;
+   uint64             consumeSize;
+   uint32             refCount;
+} QueuePairEntry;
+
+typedef struct QPBrokerEntry {
+   QueuePairEntry       qp;
+   VMCIId               createId;
+   VMCIId               attachId;
+   Bool                 pageStoreSet;
+   Bool                 allowAttach;
+   Bool                 requireTrustedAttach;
+   Bool                 createdByTrusted;
+#ifdef VMKERNEL
+   QueuePairPageStore   store;
+#elif defined(__linux__) || defined(_WIN32) || defined(__APPLE__)
+   /*
+    * Always created but only used if a host endpoint attaches to this
+    * queue.
+    */
+
+   VMCIQueue           *produceQ;
+   VMCIQueue           *consumeQ;
+   char                 producePageFile[VMCI_PATH_MAX];
+   char                 consumePageFile[VMCI_PATH_MAX];
+   PageStoreAttachInfo *attachInfo;
+#endif
+} QPBrokerEntry;
+
+#if !defined(VMKERNEL)
+typedef struct QPGuestEndpoint {
+   QueuePairEntry qp;
+   uint64         numPPNs;
+   void          *produceQ;
+   void          *consumeQ;
+   Bool           hibernateFailure;
+   PPNSet         ppnSet;
+} QPGuestEndpoint;
+#endif
+
+#ifdef VMKERNEL
+typedef VMCILock VMCIQPLock;
+# define VMCIQPLock_Init(_l, _r) VMCI_InitLock(_l, "VMCIQPLock",        \
+                                               VMCI_LOCK_RANK_HIGH); \
+                                 _r = VMCI_SUCCESS
+# define VMCIQPLock_Destroy(_l)  VMCI_CleanupLock(_l)
+# define VMCIQPLock_Acquire(_l)  VMCI_GrabLock(_l, NULL)
+# define VMCIQPLock_Release(_l)  VMCI_ReleaseLock(_l, 0)
+#else
+typedef VMCIMutex VMCIQPLock;
+# define VMCIQPLock_Init(_l, _r) _r = VMCIMutex_Init(_l)
+# define VMCIQPLock_Destroy(_l)  VMCIMutex_Destroy(_l)
+# define VMCIQPLock_Acquire(_l)  VMCIMutex_Acquire(_l)
+# define VMCIQPLock_Release(_l)  VMCIMutex_Release(_l)
+#endif
+
+typedef struct QueuePairList {
+   VMCIList       head;
+   Atomic_uint32  hibernate;
+   VMCIQPLock     lock;
+} QueuePairList;
+
+static QueuePairList qpBrokerList;
+
+#if !defined(VMKERNEL)
+  static QueuePairList qpGuestEndpoints;
+  static VMCIHandleArray *hibernateFailedList;
+  static VMCILock hibernateFailedListLock;
+#endif
+
+static QueuePairEntry *QueuePairList_FindEntry(QueuePairList *qpList,
+                                               VMCIHandle handle);
+static void QueuePairList_AddEntry(QueuePairList *qpList,
+                                   QueuePairEntry *entry);
+static void QueuePairList_RemoveEntry(QueuePairList *qpList,
+                                      QueuePairEntry *entry);
+static QueuePairEntry *QueuePairList_GetHead(QueuePairList *qpList);
+
+static int QueuePairNotifyPeer(Bool attach, VMCIHandle handle, VMCIId myId,
+                               VMCIId peerId);
+static int VMCIQPBrokerAllocInt(VMCIHandle handle, VMCIId peer,
+                                uint32 flags, VMCIPrivilegeFlags privFlags,
+                                uint64 produceSize,
+                                uint64 consumeSize,
+                                QueuePairPageStore *pageStore,
+                                VMCIContext *context,
+                                QPBrokerEntry **ent);
+
+#if !defined(VMKERNEL)
+static int VMCIQueuePairAllocHostWork(VMCIHandle *handle, VMCIQueue **produceQ,
+                                      uint64 produceSize, VMCIQueue **consumeQ,
+                                      uint64 consumeSize,
+                                      VMCIId peer, uint32 flags,
+                                      VMCIPrivilegeFlags privFlags);
+static int VMCIQueuePairDetachHostWork(VMCIHandle handle);
+
+static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle);
+
+static QPGuestEndpoint *QPGuestEndpointCreate(VMCIHandle handle,
+                                            VMCIId peer, uint32 flags,
+                                            uint64 produceSize,
+                                            uint64 consumeSize,
+                                            void *produceQ, void *consumeQ);
+static void QPGuestEndpointDestroy(QPGuestEndpoint *entry);
+static int VMCIQueuePairAllocHypercall(const QPGuestEndpoint *entry);
+static int VMCIQueuePairAllocGuestWork(VMCIHandle *handle, VMCIQueue **produceQ,
+                                       uint64 produceSize, VMCIQueue **consumeQ,
+                                       uint64 consumeSize,
+                                       VMCIId peer, uint32 flags,
+                                       VMCIPrivilegeFlags privFlags);
+static int VMCIQueuePairDetachGuestWork(VMCIHandle handle);
+static int VMCIQueuePairDetachHypercall(VMCIHandle handle);
+static void VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry);
+static void VMCIQPUnmarkHibernateFailed(QPGuestEndpoint *entry);
+
+extern int VMCI_SendDatagram(VMCIDatagram *);
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueuePair_Alloc --
+ *
+ *      Allocates a VMCI QueuePair. Only checks validity of input
+ *      arguments. The real work is done in the host or guest
+ *      specific function.
+ *
+ * Results:
+ *      VMCI_SUCCESS on success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIQueuePair_Alloc(VMCIHandle *handle,           // IN/OUT
+                    VMCIQueue  **produceQ,        // OUT
+                    uint64     produceSize,       // IN
+                    VMCIQueue  **consumeQ,        // OUT
+                    uint64     consumeSize,       // IN
+                    VMCIId     peer,              // IN
+                    uint32     flags,             // IN
+                    VMCIPrivilegeFlags privFlags, // IN
+                    Bool       guestEndpoint)     // IN
+{
+   if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) ||
+       (flags & ~VMCI_QP_ALL_FLAGS)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   if (guestEndpoint) {
+      return VMCIQueuePairAllocGuestWork(handle, produceQ, produceSize, consumeQ,
+                                         consumeSize, peer, flags, privFlags);
+   } else {
+      return VMCIQueuePairAllocHostWork(handle, produceQ, produceSize, consumeQ,
+                                        consumeSize, peer, flags, privFlags);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueuePair_Detach --
+ *
+ *      Detaches from a VMCI QueuePair. Only checks validity of input argument.
+ *      Real work is done in the host or guest specific function.
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      Memory is freed.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIQueuePair_Detach(VMCIHandle handle,   // IN
+                     Bool guestEndpoint)  // IN
+{
+   if (VMCI_HANDLE_INVALID(handle)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   if (guestEndpoint) {
+      return VMCIQueuePairDetachGuestWork(handle);
+   } else {
+      return VMCIQueuePairDetachHostWork(handle);
+   }
+}
+#endif // !defined(VMKERNEL)
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairList_Init --
+ *
+ *      Initializes the list of QueuePairs.
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE int
+QueuePairList_Init(QueuePairList *qpList)  // IN
+{
+   int ret;
+
+   VMCIList_Init(&qpList->head);
+   Atomic_Write(&qpList->hibernate, 0);
+   VMCIQPLock_Init(&qpList->lock, ret);
+
+   return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairList_Destroy --
+ *
+ *      Destroy the list's lock.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+QueuePairList_Destroy(QueuePairList *qpList)
+{
+   VMCIQPLock_Destroy(&qpList->lock);
+   VMCIList_Init(&qpList->head);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_Lock --
+ *
+ *      Acquires the lock protecting a VMCI queue pair broker transaction.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIQPBroker_Lock(void)
+{
+   VMCIQPLock_Acquire(&qpBrokerList.lock);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_Unlock --
+ *
+ *      Releases the lock protecting a VMCI queue pair broker transaction.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIQPBroker_Unlock(void)
+{
+   VMCIQPLock_Release(&qpBrokerList.lock);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairList_FindEntry --
+ *
+ *      Finds the entry in the list corresponding to a given handle. Assumes
+ *      that the list is locked.
+ *
+ * Results:
+ *      Pointer to entry.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static QueuePairEntry *
+QueuePairList_FindEntry(QueuePairList *qpList,  // IN
+                        VMCIHandle handle)      // IN
+{
+   VMCIListItem *next;
+
+   if (VMCI_HANDLE_INVALID(handle)) {
+      return NULL;
+   }
+
+   VMCIList_Scan(next, &qpList->head) {
+      QueuePairEntry *entry = VMCIList_Entry(next, QueuePairEntry, listItem);
+
+      if (VMCI_HANDLE_EQUAL(entry->handle, handle)) {
+         return entry;
+      }
+   }
+
+   return NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairList_AddEntry --
+ *
+ *      Adds the given entry to the list. Assumes that the list is locked.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+QueuePairList_AddEntry(QueuePairList *qpList,  // IN
+                       QueuePairEntry *entry)  // IN
+{
+   if (entry) {
+      VMCIList_Insert(&entry->listItem, &qpList->head);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairList_RemoveEntry --
+ *
+ *      Removes the given entry from the list. Assumes that the list is locked.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+QueuePairList_RemoveEntry(QueuePairList *qpList,  // IN
+                          QueuePairEntry *entry)  // IN
+{
+   if (entry) {
+      VMCIList_Remove(&entry->listItem, &qpBrokerList.head);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairList_GetHead --
+ *
+ *      Returns the entry from the head of the list. Assumes that the list is
+ *      locked.
+ *
+ * Results:
+ *      Pointer to entry.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static QueuePairEntry *
+QueuePairList_GetHead(QueuePairList *qpList)
+{
+   VMCIListItem *first = VMCIList_First(&qpList->head);
+
+   if (first) {
+      QueuePairEntry *entry = VMCIList_Entry(first, QueuePairEntry, listItem);
+      return entry;
+   }
+
+   return NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairDenyConnection --
+ *
+ *      On ESX we check if the domain names of the two contexts match.
+ *      Otherwise we deny the connection.  We always allow the connection on
+ *      hosted.
+ *
+ * Results:
+ *      Boolean result.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+QueuePairDenyConnection(VMCIId contextId, // IN:  Unused on hosted
+                        VMCIId peerId)    // IN:  Unused on hosted
+{
+#ifndef VMKERNEL
+   return FALSE; /* Allow on hosted. */
+#else
+   char contextDomain[VMCI_DOMAIN_NAME_MAXLEN];
+   char peerDomain[VMCI_DOMAIN_NAME_MAXLEN];
+
+   ASSERT(contextId != VMCI_INVALID_ID);
+   if (peerId == VMCI_INVALID_ID) {
+      return FALSE; /* Allow. */
+   }
+   if (VMCIContext_GetDomainName(contextId, contextDomain,
+                                 sizeof contextDomain) != VMCI_SUCCESS) {
+      return TRUE; /* Deny. */
+   }
+   if (VMCIContext_GetDomainName(peerId, peerDomain, sizeof peerDomain) !=
+       VMCI_SUCCESS) {
+      return TRUE; /* Deny. */
+   }
+   return strcmp(contextDomain, peerDomain) ? TRUE : /* Deny. */
+                                              FALSE; /* Allow. */
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_Init --
+ *
+ *      Initalizes queue pair broker state.
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIQPBroker_Init(void)
+{
+   return QueuePairList_Init(&qpBrokerList);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_Exit --
+ *
+ *      Destroys the queue pair broker state.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIQPBroker_Exit(void)
+{
+   QPBrokerEntry *entry;
+
+   VMCIQPBroker_Lock();
+
+   while ((entry = (QPBrokerEntry *)QueuePairList_GetHead(&qpBrokerList))) {
+      QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
+      VMCI_FreeKernelMem(entry, sizeof *entry);
+   }
+
+   VMCIQPBroker_Unlock();
+   QueuePairList_Destroy(&qpBrokerList);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_Alloc --
+ *
+ *      Requests that a queue pair be allocated with the VMCI queue
+ *      pair broker. Allocates a queue pair entry if one does not
+ *      exist. Attaches to one if it exists, and retrieves the page
+ *      files backing that QueuePair.  Assumes that the queue pair
+ *      broker lock is held.
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      Memory may be allocated.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIQPBroker_Alloc(VMCIHandle handle,             // IN
+                   VMCIId peer,                   // IN
+                   uint32 flags,                  // IN
+                   VMCIPrivilegeFlags privFlags,  // IN
+                   uint64 produceSize,            // IN
+                   uint64 consumeSize,            // IN
+                   QueuePairPageStore *pageStore, // IN/OUT
+                   VMCIContext *context)          // IN: Caller
+{
+   return VMCIQPBrokerAllocInt(handle, peer, flags, privFlags,
+                               produceSize, consumeSize,
+                               pageStore, context, NULL);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBrokerAllocInt --
+ *
+ *      QueuePair_Alloc for use when setting up queue pair endpoints
+ *      on the host. Like QueuePair_Alloc, but returns a pointer to
+ *      the QPBrokerEntry on success.
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      Memory may be allocated.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VMCIQPBrokerAllocInt(VMCIHandle handle,             // IN
+                     VMCIId peer,                   // IN
+                     uint32 flags,                  // IN
+                     VMCIPrivilegeFlags privFlags,  // IN
+                     uint64 produceSize,            // IN
+                     uint64 consumeSize,            // IN
+                     QueuePairPageStore *pageStore, // IN/OUT
+                     VMCIContext *context,          // IN: Caller
+                     QPBrokerEntry **ent)           // OUT
+{
+   QPBrokerEntry *entry = NULL;
+   int result;
+   const VMCIId contextId = VMCIContext_GetId(context);
+   Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
+
+   if (VMCI_HANDLE_INVALID(handle) ||
+       (flags & ~VMCI_QP_ALL_FLAGS) ||
+       (isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID ||
+                     handle.context != contextId)) ||
+       !(produceSize || consumeSize) ||
+       !context || contextId == VMCI_INVALID_ID ||
+       handle.context == VMCI_INVALID_ID) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+#ifdef VMKERNEL
+   if (!pageStore || (!pageStore->shared && !isLocal)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+#else
+   /*
+    * On hosted, pageStore can be NULL if the caller doesn't want the
+    * information
+    */
+   if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+#endif // VMKERNEL
+
+
+   /*
+    * In the initial argument check, we ensure that non-vmkernel hosts
+    * are not allowed to create local queue pairs.
+    */
+
+   ASSERT(vmkernel || !isLocal);
+
+   if (!isLocal && VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
+      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair "
+                         "(handle=0x%x:0x%x).\n",
+                         contextId, handle.context, handle.resource));
+      result = VMCI_ERROR_ALREADY_EXISTS;
+      goto out;
+   }
+
+   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
+   if (!entry) { /* Create case. */
+      /*
+       * Do not create if the caller asked not to.
+       */
+
+      if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
+         result = VMCI_ERROR_NOT_FOUND;
+         goto out;
+      }
+
+      /*
+       * Creator's context ID should match handle's context ID or the creator
+       * must allow the context in handle's context ID as the "peer".
+       */
+
+      if (handle.context != contextId && handle.context != peer) {
+         result = VMCI_ERROR_NO_ACCESS;
+         goto out;
+      }
+
+      /*
+       * Check if we should allow this QueuePair connection.
+       */
+
+      if (QueuePairDenyConnection(contextId, peer)) {
+         result = VMCI_ERROR_NO_ACCESS;
+         goto out;
+      }
+
+      entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
+      if (!entry) {
+         result = VMCI_ERROR_NO_MEM;
+         goto out;
+      }
+
+      memset(entry, 0, sizeof *entry);
+      entry->qp.handle = handle;
+      entry->qp.peer = peer;
+      entry->qp.flags = flags;
+      entry->qp.produceSize = produceSize;
+      entry->qp.consumeSize = consumeSize;
+      entry->qp.refCount = 1;
+      entry->createId = contextId;
+      entry->attachId = VMCI_INVALID_ID;
+      entry->pageStoreSet = FALSE;
+      entry->allowAttach = TRUE;
+      entry->requireTrustedAttach =
+         (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
+      entry->createdByTrusted =
+         (privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
+
+#ifndef VMKERNEL
+      {
+         uint64 numProducePages;
+         uint64 numConsumePages;
+
+         entry->produceQ = VMCIHost_AllocQueue(produceSize);
+         if (entry->produceQ == NULL) {
+            result = VMCI_ERROR_NO_MEM;
+            goto errorDealloc;
+         }
+
+         entry->consumeQ = VMCIHost_AllocQueue(consumeSize);
+         if (entry->consumeQ == NULL) {
+            result = VMCI_ERROR_NO_MEM;
+            goto errorDealloc;
+         }
+
+         entry->attachInfo = VMCI_AllocKernelMem(sizeof *entry->attachInfo,
+                                                 VMCI_MEMORY_NORMAL);
+         if (entry->attachInfo == NULL) {
+            result = VMCI_ERROR_NO_MEM;
+            goto errorDealloc;
+         }
+         memset(entry->attachInfo, 0, sizeof *entry->attachInfo);
+
+         VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ);
+
+         numProducePages = CEILING(produceSize, PAGE_SIZE) + 1;
+         numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1;
+
+         entry->attachInfo->numProducePages = numProducePages;
+         entry->attachInfo->numConsumePages = numConsumePages;
+      }
+#endif /* !VMKERNEL */
+
+      VMCIList_InitEntry(&entry->qp.listItem);
+
+      QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
+      result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
+   } else { /* Attach case. */
+
+      /*
+       * Check for failure conditions.
+       */
+
+      if (isLocal) {
+         if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
+             contextId != entry->createId) {
+            result = VMCI_ERROR_INVALID_ARGS;
+            goto out;
+         }
+      } else if (contextId == entry->createId || contextId == entry->attachId) {
+         result = VMCI_ERROR_ALREADY_EXISTS;
+         goto out;
+      }
+
+      /*
+       * QueuePairs are create/destroy entities.  There's no notion of
+       * disconnecting/re-attaching, so once a queue pair entry has
+       * been attached to, no further attaches are allowed. This
+       * guards against both re-attaching and attaching to a queue
+       * pair that already has two peers.
+       */
+
+      if (!entry->allowAttach) {
+         result = VMCI_ERROR_UNAVAILABLE;
+         goto out;
+      }
+      ASSERT(entry->qp.refCount < 2);
+      ASSERT(entry->attachId == VMCI_INVALID_ID);
+
+      /*
+       * If we are attaching from a restricted context then the queuepair
+       * must have been created by a trusted endpoint.
+       */
+
+      if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
+         if (!entry->createdByTrusted) {
+            result = VMCI_ERROR_NO_ACCESS;
+            goto out;
+         }
+      }
+
+      /*
+       * If we are attaching to a queuepair that was created by a restricted
+       * context then we must be trusted.
+       */
+
+      if (entry->requireTrustedAttach) {
+         if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
+            result = VMCI_ERROR_NO_ACCESS;
+            goto out;
+         }
+      }
+
+      /*
+       * If the creator specifies VMCI_INVALID_ID in "peer" field, access
+       * control check is not performed.
+       */
+
+      if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
+         result = VMCI_ERROR_NO_ACCESS;
+         goto out;
+      }
+
+#ifndef VMKERNEL
+      /*
+       * VMKernel doesn't need to check the capabilities because the
+       * whole system is installed as the kernel and matching VMX.
+       */
+
+      if (entry->createId == VMCI_HOST_CONTEXT_ID) {
+         /*
+          * Do not attach if the caller doesn't support Host Queue Pairs
+          * and a host created this queue pair.
+          */
+
+         if (!VMCIContext_SupportsHostQP(context)) {
+            result = VMCI_ERROR_INVALID_RESOURCE;
+            goto out;
+         }
+      } else if (contextId == VMCI_HOST_CONTEXT_ID) {
+         VMCIContext *createContext;
+         Bool supportsHostQP;
+
+         /*
+          * Do not attach a host to a user created queue pair if that
+          * user doesn't support host queue pair end points.
+          */
+
+         createContext = VMCIContext_Get(entry->createId);
+         supportsHostQP = VMCIContext_SupportsHostQP(createContext);
+         VMCIContext_Release(createContext);
+
+         if (!supportsHostQP) {
+            result = VMCI_ERROR_INVALID_RESOURCE;
+            goto out;
+         }
+      }
+#endif // !VMKERNEL
+
+      if (entry->qp.produceSize != consumeSize ||
+          entry->qp.consumeSize != produceSize ||
+          entry->qp.flags != (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
+         result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
+         goto out;
+      }
+
+      /*
+       * On VMKERNEL (e.g., ESX) we don't allow an attach until
+       * the page store information has been set.
+       *
+       * However, on hosted products we support an attach to a
+       * QueuePair that hasn't had its page store established yet.  In
+       * fact, that's how a VMX guest will approach a host-created
+       * QueuePair.  After the VMX guest does the attach, VMX will
+       * receive the CREATE status code to indicate that it should
+       * create the page files for the QueuePair contents.  It will
+       * then issue a separate call down to set the page store.  That
+       * will complete the attach case.
+       */
+      if (vmkernel && !entry->pageStoreSet) {
+         result = VMCI_ERROR_QUEUEPAIR_NOTSET;
+         goto out;
+      }
+
+      /*
+       * Check if we should allow this QueuePair connection.
+       */
+
+      if (QueuePairDenyConnection(contextId, entry->createId)) {
+         result = VMCI_ERROR_NO_ACCESS;
+         goto out;
+      }
+
+#ifdef VMKERNEL
+      pageStore->store = entry->store.store;
+#else
+      if (pageStore && entry->pageStoreSet) {
+         ASSERT(entry->producePageFile[0] && entry->consumePageFile[0]);
+         if (pageStore->producePageFileSize < sizeof entry->consumePageFile) {
+            result = VMCI_ERROR_NO_MEM;
+            goto out;
+         }
+         if (pageStore->consumePageFileSize < sizeof entry->producePageFile) {
+            result = VMCI_ERROR_NO_MEM;
+            goto out;
+         }
+
+         if (pageStore->user) {
+            if (VMCI_CopyToUser(pageStore->producePageFile,
+                                entry->consumePageFile,
+                                sizeof entry->consumePageFile)) {
+               result = VMCI_ERROR_GENERIC;
+               goto out;
+            }
+
+            if (VMCI_CopyToUser(pageStore->consumePageFile,
+                                entry->producePageFile,
+                                sizeof entry->producePageFile)) {
+               result = VMCI_ERROR_GENERIC;
+               goto out;
+            }
+         } else {
+            memcpy(VMCIVA64ToPtr(pageStore->producePageFile),
+                   entry->consumePageFile,
+                   sizeof entry->consumePageFile);
+            memcpy(VMCIVA64ToPtr(pageStore->consumePageFile),
+                   entry->producePageFile,
+                   sizeof entry->producePageFile);
+         }
+      }
+#endif // VMKERNEL
+
+      /*
+       * We only send notification if the other end of the QueuePair
+       * is not the host (in hosted products).  In the case that a
+       * host created the QueuePair, we'll send notification when the
+       * guest issues the SetPageStore() (see next function).  The
+       * reason is that the host can't use the QueuePair until the
+       * SetPageStore() is complete.
+       *
+       * Note that in ESX we always send the notification now
+       * because the host can begin to enqueue immediately.
+       */
+
+      if (vmkernel || entry->createId != VMCI_HOST_CONTEXT_ID) {
+         result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
+         if (result < VMCI_SUCCESS) {
+            goto out;
+         }
+      }
+
+      entry->attachId = contextId;
+      entry->qp.refCount++;
+      entry->allowAttach = FALSE;
+
+      /*
+       * Default response to an attach is _ATTACH.  However, if a host
+       * created the QueuePair then we're a guest (because
+       * host-to-host isn't supported).  And thus, the guest's VMX
+       * needs to create the backing for the port.  So, we send up a
+       * _CREATE response.
+       */
+
+      if (!vmkernel && entry->createId == VMCI_HOST_CONTEXT_ID) {
+         result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
+      } else {
+         result = VMCI_SUCCESS_QUEUEPAIR_ATTACH;
+      }
+   }
+
+#ifndef VMKERNEL
+   goto out;
+
+   /*
+    * Cleanup is only necessary on hosted
+    */
+
+errorDealloc:
+   if (entry->produceQ != NULL) {
+      VMCI_FreeKernelMem(entry->produceQ, sizeof *entry->produceQ);
+   }
+   if (entry->consumeQ != NULL) {
+      VMCI_FreeKernelMem(entry->consumeQ, sizeof *entry->consumeQ);
+   }
+   if (entry->attachInfo != NULL) {
+      VMCI_FreeKernelMem(entry->attachInfo, sizeof *entry->attachInfo);
+   }
+   VMCI_FreeKernelMem(entry, sizeof *entry);
+#endif // !VMKERNEL
+
+out:
+   if (result >= VMCI_SUCCESS) {
+      ASSERT(entry);
+      if (ent != NULL) {
+         *ent = entry;
+      }
+
+      /*
+       * When attaching to local queue pairs, the context already has
+       * an entry tracking the queue pair, so don't add another one.
+       */
+
+      if (!isLocal || result == VMCI_SUCCESS_QUEUEPAIR_CREATE) {
+         ASSERT(!VMCIHandleArray_HasEntry(context->queuePairArray, handle));
+         VMCIHandleArray_AppendEntry(&context->queuePairArray, handle);
+      } else {
+         ASSERT(VMCIHandleArray_HasEntry(context->queuePairArray, handle));
+      }
+   }
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_SetPageStore --
+ *
+ *      The creator of a queue pair uses this to regsiter the page
+ *      store for a given queue pair.  Assumes that the queue pair
+ *      broker lock is held.
+ *
+ *      Note now that sometimes the client that attaches to a queue
+ *      pair will set the page store.  This happens on hosted products
+ *      because the host doesn't have a mechanism for creating the
+ *      backing memory for queue contents.  ESX does and so this is a
+ *      moot point there.  For example, note that in
+ *      VMCIQPBrokerAllocInt() an attaching guest receives the _CREATE
+ *      result code (instead of _ATTACH) on hosted products only, not
+ *      on VMKERNEL.
+ *
+ *      As a result, this routine now always creates the host
+ *      information even if the queue pair is only used by guests.  At
+ *      the time a guest creates a queue pair it doesn't know if a
+ *      host or guest will attach.  So, the host information always
+ *      has to be created.
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIQPBroker_SetPageStore(VMCIHandle handle,             // IN
+                          QueuePairPageStore *pageStore, // IN
+                          VMCIContext *context)          // IN: Caller
+{
+   QPBrokerEntry *entry;
+   int result;
+   const VMCIId contextId = VMCIContext_GetId(context);
+#ifndef VMKERNEL
+   QueuePairPageStore normalizedPageStore;
+#endif
+
+   if (VMCI_HANDLE_INVALID(handle) || !pageStore ||
+       !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore) ||
+       !context || contextId == VMCI_INVALID_ID) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
+      VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair "
+                    "(handle=0x%x:0x%x).\n", contextId, handle.context,
+                    handle.resource));
+      result = VMCI_ERROR_NOT_FOUND;
+      goto out;
+   }
+
+#ifndef VMKERNEL
+   /*
+    * If the client supports Host QueuePairs then it must provide the
+    * UVA's of the mmap()'d files backing the QueuePairs.
+    */
+
+   if (VMCIContext_SupportsHostQP(context) &&
+       (pageStore->producePageUVA == 0 ||
+        pageStore->consumePageUVA == 0)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+#endif // !VMKERNEL
+
+   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
+   if (!entry) {
+      result = VMCI_ERROR_NOT_FOUND;
+      goto out;
+   }
+
+   /*
+    * If I'm the owner then I can set the page store.
+    *
+    * Or, if a host created the QueuePair and I'm the attached peer
+    * then I can set the page store.
+    */
+
+   if (entry->createId != contextId &&
+       (entry->createId != VMCI_HOST_CONTEXT_ID ||
+        entry->attachId != contextId)) {
+      result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
+      goto out;
+   }
+   if (entry->pageStoreSet) {
+      result = VMCI_ERROR_UNAVAILABLE;
+      goto out;
+   }
+#ifdef VMKERNEL
+   entry->store = *pageStore;
+#else
+   /*
+    * Normalize the page store information from the point of view of
+    * the VMX process with respect to the QueuePair.  If VMX has
+    * attached to a host-created QueuePair and is passing down
+    * PageStore information then we must switch the produce/consume
+    * queue information before applying it to the QueuePair.
+    *
+    * In other words, the QueuePair structure (entry->state) is
+    * oriented with respect to the host that created it.  However, VMX
+    * is sending down information relative to its view of the world
+    * which is opposite of the host's.
+    */
+
+   if (entry->createId == contextId) {
+      normalizedPageStore.producePageFile = pageStore->producePageFile;
+      normalizedPageStore.consumePageFile = pageStore->consumePageFile;
+      normalizedPageStore.producePageFileSize = pageStore->producePageFileSize;
+      normalizedPageStore.consumePageFileSize = pageStore->consumePageFileSize;
+      normalizedPageStore.producePageUVA = pageStore->producePageUVA;
+      normalizedPageStore.consumePageUVA = pageStore->consumePageUVA;
+   } else {
+      normalizedPageStore.producePageFile = pageStore->consumePageFile;
+      normalizedPageStore.consumePageFile = pageStore->producePageFile;
+      normalizedPageStore.producePageFileSize = pageStore->consumePageFileSize;
+      normalizedPageStore.consumePageFileSize = pageStore->producePageFileSize;
+      normalizedPageStore.producePageUVA = pageStore->consumePageUVA;
+      normalizedPageStore.consumePageUVA = pageStore->producePageUVA;
+   }
+
+   if (normalizedPageStore.producePageFileSize > sizeof entry->producePageFile) {
+      result = VMCI_ERROR_NO_MEM;
+       goto out;
+   }
+   if (normalizedPageStore.consumePageFileSize > sizeof entry->consumePageFile) {
+      result = VMCI_ERROR_NO_MEM;
+      goto out;
+   }
+   if (pageStore->user) {
+      if (VMCI_CopyFromUser(entry->producePageFile,
+                            normalizedPageStore.producePageFile,
+                            (size_t)normalizedPageStore.producePageFileSize)) {
+         result = VMCI_ERROR_GENERIC;
+         goto out;
+      }
+
+      if (VMCI_CopyFromUser(entry->consumePageFile,
+                            normalizedPageStore.consumePageFile,
+                            (size_t)normalizedPageStore.consumePageFileSize)) {
+         result = VMCI_ERROR_GENERIC;
+         goto out;
+      }
+   } else {
+      memcpy(entry->consumePageFile,
+             VMCIVA64ToPtr(normalizedPageStore.consumePageFile),
+             (size_t)normalizedPageStore.consumePageFileSize);
+      memcpy(entry->producePageFile,
+             VMCIVA64ToPtr(normalizedPageStore.producePageFile),
+             (size_t)normalizedPageStore.producePageFileSize);
+   }
+
+   /*
+    * Copy the data into the attachInfo structure
+    */
+
+   memcpy(&entry->attachInfo->producePageFile[0],
+          &entry->producePageFile[0],
+          (size_t)normalizedPageStore.producePageFileSize);
+   memcpy(&entry->attachInfo->consumePageFile[0],
+          &entry->consumePageFile[0],
+          (size_t)normalizedPageStore.consumePageFileSize);
+
+   /*
+    * NOTE: The UVAs that follow may be 0.  In this case an older VMX has
+    * issued a SetPageFile call without mapping the backing files for the
+    * queue contents.  The result of this is that the queue pair cannot
+    * be connected by host.
+    */
+
+   entry->attachInfo->produceBuffer = normalizedPageStore.producePageUVA;
+   entry->attachInfo->consumeBuffer = normalizedPageStore.consumePageUVA;
+
+   if (VMCIContext_SupportsHostQP(context)) {
+      result = VMCIHost_GetUserMemory(entry->attachInfo,
+                                      entry->produceQ,
+                                      entry->consumeQ);
+
+      if (result < VMCI_SUCCESS) {
+         goto out;
+      }
+   }
+#endif // VMKERNEL
+
+   /*
+    * In the event that the QueuePair was created by a host in a
+    * hosted kernel, then we send notification now that the QueuePair
+    * contents backing files are attached to the Queues.  Note in
+    * VMCIQPBrokerAllocInt(), above, we skipped this step when the
+    * creator was a host (on hosted).
+    */
+
+   if (!vmkernel && entry->createId == VMCI_HOST_CONTEXT_ID) {
+      result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
+      if (result < VMCI_SUCCESS) {
+         goto out;
+      }
+   }
+
+   entry->pageStoreSet = TRUE;
+   result = VMCI_SUCCESS;
+
+out:
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBroker_Detach --
+ *
+ *      Informs the VMCI queue pair broker that a context has detached
+ *      from a given QueuePair handle.  Assumes that the queue pair
+ *      broker lock is held.  If the "detach" input parameter is
+ *      FALSE, the queue pair entry is not removed from the list of
+ *      queue pairs registered with the queue pair broker, and the
+ *      context is not detached from the given handle.  If "detach" is
+ *      TRUE, the detach operation really happens.  With "detach" set
+ *      to FALSE, the caller can query if the "actual" detach
+ *      operation would succeed or not.  The return value from this
+ *      function remains the same irrespective of the value of the
+ *      boolean "detach".
+ *
+ *      Also note that the result code for a VM detaching from a
+ *      VM-host queue pair is always VMCI_SUCCESS_LAST_DETACH.  This
+ *      is so that VMX can unlink the backing files.  On the host side
+ *      the files are either locked (Mac OS/Linux) or the contents are
+ *      saved (Windows).
+ *
+ * Results:
+ *      Success or failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
+                    VMCIContext *context, // IN
+                    Bool detach)          // IN: Really detach?
+{
+   QPBrokerEntry *entry;
+   int result;
+   const VMCIId contextId = VMCIContext_GetId(context);
+   VMCIId peerId;
+   Bool isLocal = FALSE;
+
+   if (VMCI_HANDLE_INVALID(handle) ||
+       !context || contextId == VMCI_INVALID_ID) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
+      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
+                         "(handle=0x%x:0x%x).\n",
+                         contextId, handle.context, handle.resource));
+      result = VMCI_ERROR_NOT_FOUND;
+      goto out;
+   }
+
+   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
+   if (!entry) {
+      result = VMCI_ERROR_NOT_FOUND;
+      goto out;
+   }
+
+   isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
+
+   ASSERT(vmkernel || !isLocal);
+
+   if (contextId != entry->createId && contextId != entry->attachId) {
+      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+      goto out;
+   }
+
+   if (contextId == entry->createId) {
+      peerId = entry->attachId;
+   } else {
+      peerId = entry->createId;
+   }
+
+   if (!detach) {
+      /* Do not update the queue pair entry. */
+
+      ASSERT(entry->qp.refCount == 1 || entry->qp.refCount == 2);
+
+      if (entry->qp.refCount == 1 ||
+          (!vmkernel && peerId == VMCI_HOST_CONTEXT_ID)) {
+         result = VMCI_SUCCESS_LAST_DETACH;
+      } else {
+         result = VMCI_SUCCESS;
+      }
+
+      goto out;
+   }
+
+   if (contextId == entry->createId) {
+      entry->createId = VMCI_INVALID_ID;
+   } else {
+      entry->attachId = VMCI_INVALID_ID;
+   }
+   entry->qp.refCount--;
+
+#ifdef _WIN32
+   /*
+    * If the caller detaching is a usermode process (e.g., VMX), then
+    * we must detach the mappings now.  On Windows.
+    *
+    * VMCIHost_SaveProduceQ() will save the guest's produceQ so that
+    * the host can pick up the data after the guest is gone.
+    *
+    * We save the ProduceQ whenever the guest detaches (even if VMX
+    * continues to run).  If we didn't do this, then we'd have the
+    * problem of finding and releasing the memory when the client goes
+    * away because we won't be able to find the client in the list of
+    * QueuePair entries.  The detach code path (has already) set the
+    * contextId for detached end-point to VMCI_INVALID_ID.  (See just
+    * a few lines above where that happens.)  Sure, we could fix that,
+    * and then we could look at all entries finding ones where the
+    * contextId of either creator or attach matches the going away
+    * context's Id.  But, if we just copy out the guest's produceQ
+    * -always- then we reduce the logic changes elsewhere.
+    */
+
+   /*
+    * Some example paths through this code:
+    *
+    * Guest-to-guest: the code will call ReleaseUserMemory() once when
+    * the first guest detaches.  And then a second time when the
+    * second guest detaches.  That's OK.  Nobody is using the user
+    * memory (because there is no host attached) and
+    * ReleaseUserMemory() tracks its resources.
+    *
+    * Host detaches first: the code will not call anything because
+    * contextId == VMCI_HOST_CONTEXT_ID and because (in the second if
+    * () clause below) refCount > 0.
+    *
+    * Guest detaches second: the first if clause, below, will not be
+    * taken because refCount is already 0.  The second if () clause
+    * (below) will be taken and it will simply call
+    * ReleaseUserMemory().
+    *
+    * Guest detaches first: the code will call SaveProduceQ().
+    *
+    * Host detaches second: the code will call ReleaseUserMemory()
+    * which will free the kernel allocated Q memory.
+    */
+
+   if (entry->pageStoreSet &&
+       contextId != VMCI_HOST_CONTEXT_ID &&
+       VMCIContext_SupportsHostQP(context) &&
+       entry->qp.refCount) {
+      /*
+       * It's important to pass down produceQ and consumeQ in the
+       * correct order because the produceQ that is to be saved is the
+       * guest's, so we have to be sure that the routine sees the
+       * guest's produceQ as (in this case) the first Q parameter.
+       */
+
+      if (entry->attachId == VMCI_HOST_CONTEXT_ID) {
+         VMCIHost_SaveProduceQ(entry->attachInfo,
+                               entry->produceQ,
+                               entry->consumeQ,
+                               entry->qp.produceSize);
+      } else if (entry->createId == VMCI_HOST_CONTEXT_ID) {
+         VMCIHost_SaveProduceQ(entry->attachInfo,
+                               entry->consumeQ,
+                               entry->produceQ,
+                               entry->qp.consumeSize);
+      } else {
+         VMCIHost_ReleaseUserMemory(entry->attachInfo,
+                                    entry->produceQ,
+                                    entry->consumeQ);
+      }
+   }
+#endif // _WIN32
+
+   if (!entry->qp.refCount) {
+      QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
+
+#ifndef VMKERNEL
+      if (entry->pageStoreSet &&
+          VMCIContext_SupportsHostQP(context)) {
+         VMCIHost_ReleaseUserMemory(entry->attachInfo,
+                                    entry->produceQ,
+                                    entry->consumeQ);
+      }
+      if (entry->attachInfo) {
+         VMCI_FreeKernelMem(entry->attachInfo, sizeof *entry->attachInfo);
+      }
+      if (entry->produceQ) {
+         VMCI_FreeKernelMem(entry->produceQ, sizeof *entry->produceQ);
+      }
+      if (entry->consumeQ) {
+         VMCI_FreeKernelMem(entry->consumeQ, sizeof *entry->consumeQ);
+      }
+#endif // !VMKERNEL
+
+      VMCI_FreeKernelMem(entry, sizeof *entry);
+      result = VMCI_SUCCESS_LAST_DETACH;
+   } else {
+      /*
+       * XXX: If we ever allow the creator to detach and attach again
+       * to the same queue pair, we need to handle the mapping of the
+       * shared memory region in vmkernel differently. Currently, we
+       * assume that an attaching VM always needs to swap the two
+       * queues.
+       */
+
+      ASSERT(peerId != VMCI_INVALID_ID);
+      QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
+      if (!vmkernel && peerId == VMCI_HOST_CONTEXT_ID) {
+         result = VMCI_SUCCESS_LAST_DETACH;
+      } else {
+         result = VMCI_SUCCESS;
+      }
+   }
+
+out:
+   if (result >= VMCI_SUCCESS && detach) {
+      if (!isLocal || result == VMCI_SUCCESS_LAST_DETACH) {
+         VMCIHandleArray_RemoveEntry(context->queuePairArray, handle);
+      }
+   }
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairNotifyPeer --
+ *
+ *      Enqueues an event datagram to notify the peer VM attached to
+ *      the given queue pair handle about attach/detach event by the
+ *      given VM.
+ *
+ * Results:
+ *      Payload size of datagram enqueued on success, error code otherwise.
+ *
+ * Side effects:
+ *      Memory is allocated.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+QueuePairNotifyPeer(Bool attach,       // IN: attach or detach?
+                    VMCIHandle handle, // IN
+                    VMCIId myId,       // IN
+                    VMCIId peerId)     // IN: CID of VM to notify
+{
+   int rv;
+   VMCIEventMsg *eMsg;
+   VMCIEventPayload_QP *evPayload;
+   char buf[sizeof *eMsg + sizeof *evPayload];
+
+   if (VMCI_HANDLE_INVALID(handle) || myId == VMCI_INVALID_ID ||
+       peerId == VMCI_INVALID_ID) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
 
-#define LGPFX "VMCIQueuePair: "
+   /*
+    * Notification message contains: queue pair handle and
+    * attaching/detaching VM's context id.
+    */
 
-typedef struct QueuePairEntry {
-   VMCIListItem  listItem;
-   VMCIHandle    handle;
-   VMCIId        peer;
-   uint32        flags;
-   uint64        produceSize;
-   uint64        consumeSize;
-   uint32        refCount;
-} QueuePairEntry;
+   eMsg = (VMCIEventMsg *)buf;
 
-typedef struct QPGuestEndpoint {
-   QueuePairEntry qp;
-   uint64         numPPNs;
-   void          *produceQ;
-   void          *consumeQ;
-   Bool           hibernateFailure;
-   PPNSet         ppnSet;
-} QPGuestEndpoint;
+   /*
+    * In VMCIContext_EnqueueDatagram() we enforce the upper limit on number of
+    * pending events from the hypervisor to a given VM otherwise a rogue VM
+    * could do arbitrary number of attached and detaches causing memory
+    * pressure in the host kernel.
+   */
 
-typedef struct QueuePairList {
-   VMCIList       head;
-   Atomic_uint32  hibernate;
-   VMCIMutex      lock;
-} QueuePairList;
+   /* Clear out any garbage. */
+   memset(eMsg, 0, sizeof *eMsg + sizeof *evPayload);
 
-static QueuePairList qpGuestEndpoints;
-static VMCIHandleArray *hibernateFailedList;
-static VMCILock hibernateFailedListLock;
+   eMsg->hdr.dst = VMCI_MAKE_HANDLE(peerId, VMCI_EVENT_HANDLER);
+   eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
+                                    VMCI_CONTEXT_RESOURCE_ID);
+   eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *evPayload - sizeof eMsg->hdr;
+   eMsg->eventData.event = attach ? VMCI_EVENT_QP_PEER_ATTACH :
+                                    VMCI_EVENT_QP_PEER_DETACH;
+   evPayload = VMCIEventMsgPayload(eMsg);
+   evPayload->handle = handle;
+   evPayload->peerId = myId;
+
+   rv = VMCIDatagram_Dispatch(VMCI_HYPERVISOR_CONTEXT_ID, (VMCIDatagram *)eMsg,
+                              FALSE);
+   if (rv < VMCI_SUCCESS) {
+      VMCI_WARNING((LGPFX"Failed to enqueue QueuePair %s event datagram for "
+                    "context (ID=0x%x).\n", attach ? "ATTACH" : "DETACH",
+                    peerId));
+   }
 
-static QueuePairEntry *QueuePairList_FindEntry(QueuePairList *qpList,
-                                               VMCIHandle handle);
-static void QueuePairList_AddEntry(QueuePairList *qpList,
-                                   QueuePairEntry *entry);
-static void QueuePairList_RemoveEntry(QueuePairList *qpList,
-                                      QueuePairEntry *entry);
-static QueuePairEntry *QueuePairList_GetHead(QueuePairList *qpList);
-static QPGuestEndpoint *QPGuestEndpointCreate(VMCIHandle handle,
-                                            VMCIId peer, uint32 flags,
-                                            uint64 produceSize,
-                                            uint64 consumeSize,
-                                            void *produceQ, void *consumeQ);
-static void QPGuestEndpointDestroy(QPGuestEndpoint *entry);
-static int VMCIQueuePairAlloc_HyperCall(const QPGuestEndpoint *entry);
-static int VMCIQueuePairAllocHelper(VMCIHandle *handle, VMCIQueue **produceQ,
-                                    uint64 produceSize, VMCIQueue **consumeQ,
-                                    uint64 consumeSize,
-                                    VMCIId peer, uint32 flags);
-static int VMCIQueuePairDetachHelper(VMCIHandle handle);
-static int VMCIQueuePairDetachHyperCall(VMCIHandle handle);
-static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle);
-static void VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry);
-static void VMCIQPUnmarkHibernateFailed(QPGuestEndpoint *entry);
+   return rv;
+}
 
+#if !defined(VMKERNEL)
 
 /*
- *-----------------------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * QueuePairList_Init --
+ * VMCIQueuePairAllocHostWork --
  *
- *      Initializes a queue pair list.
+ *    This function implements the kernel API for allocating a queue
+ *    pair.
  *
  * Results:
- *      Success or failure.
+ *     VMCI_SUCCESS on succes and appropriate failure code otherwise.
  *
  * Side effects:
- *      None.
+ *     May allocate memory.
  *
- *-----------------------------------------------------------------------------
+ *----------------------------------------------------------------------
  */
 
-static INLINE int
-QueuePairList_Init(QueuePairList *qpList)
+static int
+VMCIQueuePairAllocHostWork(VMCIHandle *handle,           // IN/OUT
+                           VMCIQueue **produceQ,         // OUT
+                           uint64 produceSize,           // IN
+                           VMCIQueue **consumeQ,         // OUT
+                           uint64 consumeSize,           // IN
+                           VMCIId peer,                  // IN
+                           uint32 flags,                 // IN
+                           VMCIPrivilegeFlags privFlags) // IN
 {
-   int ret;
+   VMCIContext *context;
+   int result;
+   QPBrokerEntry *entry;
 
-   VMCIList_Init(&qpList->head);
-   Atomic_Write(&qpList->hibernate, 0);
-   ret = VMCIMutex_Init(&qpList->lock);
+   result = VMCI_SUCCESS;
 
-   return ret;
+   if (VMCI_HANDLE_INVALID(*handle)) {
+      VMCIId resourceID = VMCIResource_GetID(VMCI_HOST_CONTEXT_ID);
+      if (resourceID == VMCI_INVALID_ID) {
+         return VMCI_ERROR_NO_HANDLE;
+      }
+      *handle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID, resourceID);
+   }
+
+   context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID);
+   ASSERT(context);
+
+   entry = NULL;
+   VMCIQPBroker_Lock();
+   result = VMCIQPBrokerAllocInt(*handle, peer, flags, privFlags, produceSize,
+                                 consumeSize, NULL, context, &entry);
+
+   if (result >= VMCI_SUCCESS) {
+      ASSERT(entry != NULL);
+
+      if (entry->createId == VMCI_HOST_CONTEXT_ID) {
+         *produceQ = entry->produceQ;
+         *consumeQ = entry->consumeQ;
+      } else {
+         *produceQ = entry->consumeQ;
+         *consumeQ = entry->produceQ;
+      }
+
+      result = VMCI_SUCCESS;
+   } else {
+      *handle = VMCI_INVALID_HANDLE;
+      VMCI_DEBUG_LOG(4, (LGPFX"queue pair broker failed to alloc (result=%d).\n",
+                         result));
+   }
+
+   VMCIQPBroker_Unlock();
+   VMCIContext_Release(context);
+   return result;
 }
 
 
 /*
- *-----------------------------------------------------------------------------
+ *----------------------------------------------------------------------
  *
- * QueuePairList_Destroy --
+ * VMCIQueuePairDetachHostWork --
  *
- *      Cleans up state queue pair list state created by
- *      QueuePairList_Init. It destroys the lock protecting the
- *      QueuePair list.
+ *    This function implements the host kernel API for detaching from
+ *    a queue pair.
  *
  * Results:
- *      None.
+ *     VMCI_SUCCESS on success and appropriate failure code otherwise.
  *
  * Side effects:
- *      None.
+ *     May deallocate memory.
  *
- *-----------------------------------------------------------------------------
+ *----------------------------------------------------------------------
  */
 
-static INLINE void
-QueuePairList_Destroy(QueuePairList *qpList)
+static int
+VMCIQueuePairDetachHostWork(VMCIHandle handle) // IN
 {
-   VMCIList_Init(&qpList->head);
-   VMCIMutex_Destroy(&qpList->lock); /* No-op on Linux and Windows. */
+   int result;
+   VMCIContext *context;
+
+   context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID);
+
+   VMCIQPBroker_Lock();
+   result = VMCIQPBroker_Detach(handle, context, TRUE);
+   VMCIQPBroker_Unlock();
+
+   VMCIContext_Release(context);
+   return result;
 }
 
 
@@ -212,22 +1719,14 @@ VMCIQPGuestEndpoints_Exit(void)
 {
    QPGuestEndpoint *entry;
 
-   VMCIMutex_Acquire(&qpGuestEndpoints.lock);
+   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
    while ((entry = (QPGuestEndpoint *)QueuePairList_GetHead(&qpGuestEndpoints))) {
       /*
        * Don't make a hypercall for local QueuePairs.
        */
       if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL)) {
-         VMCIQueuePairDetachMsg detachMsg;
-
-         detachMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
-                                              VMCI_QUEUEPAIR_DETACH);
-         detachMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
-         detachMsg.hdr.payloadSize = sizeof entry->qp.handle;
-         detachMsg.handle = entry->qp.handle;
-
-         (void)VMCI_SendDatagram((VMCIDatagram *)&detachMsg);
+         VMCIQueuePairDetachHypercall(entry->qp.handle);
       }
       /*
        * We cannot fail the exit, so let's reset refCount.
@@ -238,7 +1737,7 @@ VMCIQPGuestEndpoints_Exit(void)
    }
 
    Atomic_Write(&qpGuestEndpoints.hibernate, 0);
-   VMCIMutex_Release(&qpGuestEndpoints.lock);
+   VMCIQPLock_Release(&qpGuestEndpoints.lock);
    QueuePairList_Destroy(&qpGuestEndpoints);
    VMCI_CleanupLock(&hibernateFailedListLock);
    VMCIHandleArray_Destroy(hibernateFailedList);
@@ -265,205 +1764,8 @@ VMCIQPGuestEndpoints_Exit(void)
 void
 VMCIQPGuestEndpoints_Sync(void)
 {
-   VMCIMutex_Acquire(&qpGuestEndpoints.lock);
-   VMCIMutex_Release(&qpGuestEndpoints.lock);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_FindEntry --
- *
- *    Searches the list of QueuePairs to find if an entry already exists.
- *    Assumes that the lock on the list is held.
- *
- * Results:
- *    Pointer to the entry if it exists, NULL otherwise.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static QueuePairEntry *
-QueuePairList_FindEntry(QueuePairList *qpList, // IN
-                        VMCIHandle handle)     // IN
-{
-   VMCIListItem *next;
-
-   if (VMCI_HANDLE_INVALID(handle)) {
-      return NULL;
-   }
-
-   VMCIList_Scan(next, &qpList->head) {
-      QueuePairEntry *entry = VMCIList_Entry(next, QueuePairEntry, listItem);
-
-      if (VMCI_HANDLE_EQUAL(entry->handle, handle)) {
-         return entry;
-      }
-   }
-
-   return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_AddEntry --
- *
- *    Appends a QueuePair entry to the list. Assumes that the lock on the
- *    list is held.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-QueuePairList_AddEntry(QueuePairList *qpList, // IN
-                       QueuePairEntry *entry) // IN
-{
-   if (entry) {
-      VMCIList_Insert(&entry->listItem, &qpList->head);
-   }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_RemoveEntry --
- *
- *    Removes a QueuePair entry from the list. Assumes that the lock on the
- *    list is held.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-QueuePairList_RemoveEntry(QueuePairList *qpList, // IN
-                          QueuePairEntry *entry) // IN
-{
-   if (entry) {
-      VMCIList_Remove(&entry->listItem, &qpList->head);
-   }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_GetHead --
- *
- *      Returns the entry from the head of the list. Assumes that the list is
- *      locked.
- *
- * Results:
- *      Pointer to entry.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static QueuePairEntry *
-QueuePairList_GetHead(QueuePairList *qpList) // IN
-{
-   VMCIListItem *first = VMCIList_First(&qpList->head);
-
-   if (first) {
-      QueuePairEntry *entry = VMCIList_Entry(first, QueuePairEntry, listItem);
-      return entry;
-   }
-
-   return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePair_Alloc --
- *
- *      Allocates a VMCI QueuePair. Only checks validity of input
- *      arguments.  Real work is done in the OS-specific helper
- *      routine. The privilege flags argument is present to provide
- *      compatibility with the host API; anything other than
- *      VMCI_NO_PRIVILEGE_FLAGS will result in the error
- *      VMCI_ERROR_NO_ACCESS, since requesting privileges from the
- *      guest is not allowed.
- *
- * Results:
- *      VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQueuePair_Alloc(VMCIHandle *handle,           // IN/OUT
-                    VMCIQueue  **produceQ,        // OUT
-                    uint64     produceSize,       // IN
-                    VMCIQueue  **consumeQ,        // OUT
-                    uint64     consumeSize,       // IN
-                    VMCIId     peer,              // IN
-                    uint32     flags,             // IN
-                    VMCIPrivilegeFlags privFlags) // IN
-{
-   if (privFlags != VMCI_NO_PRIVILEGE_FLAGS) {
-      return VMCI_ERROR_NO_ACCESS;
-   }
-
-   if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) ||
-       (flags & ~VMCI_QP_ALL_FLAGS)) {
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-
-   return VMCIQueuePairAllocHelper(handle, produceQ, produceSize, consumeQ,
-                                   consumeSize, peer, flags);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePair_Detach --
- *
- *      Detaches from a VMCI QueuePair. Only checks validity of input argument.
- *      Real work is done in the OS-specific helper routine.
- *
- * Results:
- *      Success or failure.
- *
- * Side effects:
- *      Memory is freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQueuePair_Detach(VMCIHandle handle) // IN
-{
-   if (VMCI_HANDLE_INVALID(handle)) {
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-   return VMCIQueuePairDetachHelper(handle);
+   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
+   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 }
 
 
@@ -587,9 +1889,10 @@ QPGuestEndpointDestroy(QPGuestEndpoint *entry) // IN
 /*
  *-----------------------------------------------------------------------------
  *
- * VMCIQueuePairAlloc_HyperCall --
+ * VMCIQueuePairAllocHypercall --
  *
- *      Helper to make a QueuePairAlloc hypercall.
+ *      Helper to make a QueuePairAlloc hypercall when the driver is
+ *      supporting a guest device.
  *
  * Results:
  *      Result of the hypercall.
@@ -600,8 +1903,8 @@ QPGuestEndpointDestroy(QPGuestEndpoint *entry) // IN
  *-----------------------------------------------------------------------------
  */
 
-int
-VMCIQueuePairAlloc_HyperCall(const QPGuestEndpoint *entry) // IN
+static int
+VMCIQueuePairAllocHypercall(const QPGuestEndpoint *entry) // IN
 {
    VMCIQueuePairAllocMsg *allocMsg;
    size_t msgSize;
@@ -642,10 +1945,11 @@ VMCIQueuePairAlloc_HyperCall(const QPGuestEndpoint *entry) // IN
 /*
  *-----------------------------------------------------------------------------
  *
- * VMCIQueuePairAllocHelper --
+ * VMCIQueuePairAllocGuestWork --
  *
- *      Helper for VMCI QueuePairAlloc. Allocates physical pages for the
- *      QueuePair. Makes OS dependent calls through generic wrappers.
+ *      This functions handles the actual allocation of a VMCI queue
+ *      pair guest endpoint. Allocates physical pages for the queue
+ *      pair. It makes OS dependent calls through generic wrappers.
  *
  * Results:
  *      Success or failure.
@@ -657,13 +1961,15 @@ VMCIQueuePairAlloc_HyperCall(const QPGuestEndpoint *entry) // IN
  */
 
 static int
-VMCIQueuePairAllocHelper(VMCIHandle *handle,   // IN/OUT
-                         VMCIQueue **produceQ, // OUT
-                         uint64 produceSize,   // IN
-                         VMCIQueue **consumeQ, // OUT
-                         uint64 consumeSize,   // IN
-                         VMCIId peer,          // IN
-                         uint32 flags)         // IN
+VMCIQueuePairAllocGuestWork(VMCIHandle *handle,           // IN/OUT
+                            VMCIQueue **produceQ,         // OUT
+                            uint64 produceSize,           // IN
+                            VMCIQueue **consumeQ,         // OUT
+                            uint64 consumeSize,           // IN
+                            VMCIId peer,                  // IN
+                            uint32 flags,                 // IN
+                            VMCIPrivilegeFlags privFlags) // IN
+
 {
    const uint64 numProducePages = CEILING(produceSize, PAGE_SIZE) + 1;
    const uint64 numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1;
@@ -679,7 +1985,11 @@ VMCIQueuePairAllocHelper(VMCIHandle *handle,   // IN/OUT
 
    ASSERT(handle && produceQ && consumeQ && (produceSize || consumeSize));
 
-   VMCIMutex_Acquire(&qpGuestEndpoints.lock);
+   if (privFlags != VMCI_NO_PRIVILEGE_FLAGS) {
+      return VMCI_ERROR_NO_ACCESS;
+   }
+
+   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
    /* Do not allow alloc/attach if the device is being shutdown. */
    if (VMCI_DeviceShutdown()) {
@@ -793,9 +2103,9 @@ VMCIQueuePairAllocHelper(VMCIHandle *handle,   // IN/OUT
          goto error;
       }
    } else {
-      result = VMCIQueuePairAlloc_HyperCall(queuePairEntry);
+      result = VMCIQueuePairAllocHypercall(queuePairEntry);
       if (result < VMCI_SUCCESS) {
-         VMCI_WARNING((LGPFX"VMCIQueuePairAlloc_HyperCall result = %d.\n",
+         VMCI_WARNING((LGPFX"VMCIQueuePairAllocHypercall result = %d.\n",
                        result));
          goto error;
       }
@@ -822,12 +2132,12 @@ out:
       VMCIQueueHeader_Init((*consumeQ)->qHeader, *handle);
    }
 
-   VMCIMutex_Release(&qpGuestEndpoints.lock);
+   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
    return VMCI_SUCCESS;
 
 error:
-   VMCIMutex_Release(&qpGuestEndpoints.lock);
+   VMCIQPLock_Release(&qpGuestEndpoints.lock);
    if (queuePairEntry) {
       /* The queues will be freed inside the destroy routine. */
       QPGuestEndpointDestroy(queuePairEntry);
@@ -844,7 +2154,7 @@ error:
 errorKeepEntry:
    /* This path should only be used when an existing entry was found. */
    ASSERT(queuePairEntry->qp.refCount > 0);
-   VMCIMutex_Release(&qpGuestEndpoints.lock);
+   VMCIQPLock_Release(&qpGuestEndpoints.lock);
    return result;
 }
 
@@ -852,9 +2162,10 @@ errorKeepEntry:
 /*
  *-----------------------------------------------------------------------------
  *
- * VMCIQueuePairDetachHyperCall --
+ * VMCIQueuePairDetachHypercall --
  *
- *      Helper to make a QueuePairDetach hypercall.
+ *      Helper to make a QueuePairDetach hypercall when the driver is
+ *      supporting a guest device.
  *
  * Results:
  *      Result of the hypercall.
@@ -866,7 +2177,7 @@ errorKeepEntry:
  */
 
 int
-VMCIQueuePairDetachHyperCall(VMCIHandle handle) // IN
+VMCIQueuePairDetachHypercall(VMCIHandle handle) // IN
 {
    VMCIQueuePairDetachMsg detachMsg;
 
@@ -883,10 +2194,10 @@ VMCIQueuePairDetachHyperCall(VMCIHandle handle) // IN
 /*
  *-----------------------------------------------------------------------------
  *
- * VMCIQueuePairDetachHelper --
+ * VMCIQueuePairDetachGuestWork --
  *
- *      Helper for VMCI QueuePair detach interface on Linux. Frees the physical
- *      pages for the QueuePair.
+ *      Helper for VMCI QueuePair detach interface. Frees the physical
+ *      pages for the queue pair.
  *
  * Results:
  *      Success or failure.
@@ -898,7 +2209,7 @@ VMCIQueuePairDetachHyperCall(VMCIHandle handle) // IN
  */
 
 static int
-VMCIQueuePairDetachHelper(VMCIHandle handle)   // IN
+VMCIQueuePairDetachGuestWork(VMCIHandle handle)   // IN
 {
    int result;
    QPGuestEndpoint *entry;
@@ -906,7 +2217,7 @@ VMCIQueuePairDetachHelper(VMCIHandle handle)   // IN
 
    ASSERT(!VMCI_HANDLE_INVALID(handle));
 
-   VMCIMutex_Acquire(&qpGuestEndpoints.lock);
+   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
    entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints, handle);
    if (!entry) {
@@ -926,7 +2237,7 @@ VMCIQueuePairDetachHelper(VMCIHandle handle)   // IN
          }
       }
    } else {
-      result = VMCIQueuePairDetachHyperCall(handle);
+      result = VMCIQueuePairDetachHypercall(handle);
       if (entry->hibernateFailure) {
          if (result == VMCI_ERROR_NOT_FOUND) {
             /*
@@ -965,7 +2276,7 @@ out:
                                    * compiler.
                                    */
 
-   VMCIMutex_Release(&qpGuestEndpoints.lock);
+   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
    if (result >= VMCI_SUCCESS && refCount == 0) {
       QPGuestEndpointDestroy(entry);
@@ -1055,6 +2366,7 @@ VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry) // IN
    VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags);
 }
 
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -1158,7 +2470,7 @@ VMCIQPGuestEndpoints_Convert(Bool toLocal,     // IN
    if (toLocal) {
       VMCIListItem *next;
 
-      VMCIMutex_Acquire(&qpGuestEndpoints.lock);
+      VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
       VMCIList_Scan(next, &qpGuestEndpoints.head) {
          QPGuestEndpoint *entry = (QPGuestEndpoint *)VMCIList_Entry(
@@ -1212,7 +2524,7 @@ VMCIQPGuestEndpoints_Convert(Bool toLocal,     // IN
              * discard the content of the non-local queues.
              */
 
-            result = VMCIQueuePairDetachHyperCall(entry->qp.handle);
+            result = VMCIQueuePairDetachHypercall(entry->qp.handle);
             if (result < VMCI_SUCCESS) {
                VMCI_WARNING((LGPFX"Hibernate failed to detach from handle "
                              "%x:%x\n",
@@ -1239,7 +2551,7 @@ VMCIQPGuestEndpoints_Convert(Bool toLocal,     // IN
       }
       Atomic_Write(&qpGuestEndpoints.hibernate, 1);
 
-      VMCIMutex_Release(&qpGuestEndpoints.lock);
+      VMCIQPLock_Release(&qpGuestEndpoints.lock);
    } else {
       VMCILockFlags flags;
       VMCIHandle handle;
@@ -1266,3 +2578,5 @@ VMCIQPGuestEndpoints_Convert(Bool toLocal,     // IN
       Atomic_Write(&qpGuestEndpoints.hibernate, 0);
    }
 }
+
+#endif  /* !VMKERNEL */
index 609d0fc2169ba85a9cd52eeaa929f160441a6c8f..ec733becb74a1f162eb57240a49bd0214d76e282 100644 (file)
@@ -69,6 +69,43 @@ typedef struct QueuePairPageStore {
 
 #endif // !VMKERNEL
 
+#if (defined(__linux__) || defined(_WIN32) || defined(__APPLE__)) && !defined(VMKERNEL)
+struct VMCIQueue;
+
+typedef struct PageStoreAttachInfo {
+   char producePageFile[VMCI_PATH_MAX];
+   char consumePageFile[VMCI_PATH_MAX];
+   uint64 numProducePages;
+   uint64 numConsumePages;
+
+   /* User VAs in the VMX task */
+   VA64   produceBuffer;
+   VA64   consumeBuffer;
+
+   /*
+    * Platform-specific references to the physical pages backing the
+    * queue. These include a page for the header.
+    *
+    * PR361589 tracks this, too.
+    */
+
+#if defined(__linux__)
+   struct page **producePages;
+   struct page **consumePages;
+#elif defined(_WIN32)
+   void *kmallocPtr;
+   size_t kmallocSize;
+   PMDL produceMDL;
+   PMDL consumeMDL;
+#elif defined(__APPLE__)
+   /*
+    * All the Mac OS X fields are members of the VMCIQueue
+    */
+#endif
+} PageStoreAttachInfo;
+
+#endif // (__linux__ || _WIN32 || __APPLE__) && !VMKERNEL
+
 
 /*
  *------------------------------------------------------------------------------
@@ -99,7 +136,6 @@ VMCI_QP_PAGESTORE_IS_WELLFORMED(QueuePairPageStore *pageStore) // IN
 #endif // !VMKERNEL
 }
 
-
 int VMCIQPBroker_Init(void);
 void VMCIQPBroker_Exit(void);
 void VMCIQPBroker_Lock(void);
@@ -114,54 +150,16 @@ int VMCIQPBroker_SetPageStore(VMCIHandle handle,
                               VMCIContext *context);
 int VMCIQPBroker_Detach(VMCIHandle handle, VMCIContext *context, Bool detach);
 
-#if (defined(__linux__) || defined(_WIN32) || defined(__APPLE__)) && !defined(VMKERNEL)
-struct VMCIQueue;
-
-typedef struct PageStoreAttachInfo {
-   char producePageFile[VMCI_PATH_MAX];
-   char consumePageFile[VMCI_PATH_MAX];
-   uint64 numProducePages;
-   uint64 numConsumePages;
-
-   /* User VAs in the VMX task */
-   VA64   produceBuffer;
-   VA64   consumeBuffer;
-
-   /*
-    * Platform-specific references to the physical pages backing the
-    * queue. These include a page for the header.
-    *
-    * PR361589 tracks this, too.
-    */
-
-#if defined(__linux__)
-# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
-   struct kiobuf *produceIoBuf;
-   struct kiobuf *consumeIoBuf;
-# else
-   struct page **producePages;
-   struct page **consumePages;
-# endif
-#elif defined(_WIN32)
-   void *kmallocPtr;
-   size_t kmallocSize;
-   PMDL produceMDL;
-   PMDL consumeMDL;
-#elif defined(__APPLE__)
-   /*
-    * All the Mac OS X fields are members of the VMCIQueue
-    */
-#endif
-} PageStoreAttachInfo;
-
-#endif // (__linux__ || _WIN32 || __APPLE__) && !VMKERNEL
-
+void VMCIQPGuestEndpoints_Init(void);
+void VMCIQPGuestEndpoints_Exit(void);
+void VMCIQPGuestEndpoints_Sync(void);
+void VMCIQPGuestEndpoints_Convert(Bool toLocal, Bool deviceReset);
 
 int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
                         uint64 produceSize, VMCIQueue **consumeQ,
                         uint64 consumeSize, VMCIId peer, uint32 flags,
-                        VMCIPrivilegeFlags privFlags);
-int VMCIQueuePair_Detach(VMCIHandle handle);
+                        VMCIPrivilegeFlags privFlags, Bool guestEndpoint);
+int VMCIQueuePair_Detach(VMCIHandle handle, Bool guestEndpoint);
 
 
 #endif /* !_VMCI_QUEUE_PAIR_H_ */
diff --git a/open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h b/open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h
deleted file mode 100644 (file)
index a7cfe2a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- *********************************************************/
-
-/*
- * vmciQueuePairInt.h --
- *
- *     Helper function declarations for VMCI QueuePair API.
- */
-
-#ifndef _VMCI_QUEUE_PAIR_INT_H_
-#define _VMCI_QUEUE_PAIR_INT_H_
-
-#include "vmci_defs.h"
-#include "vmciQueue.h"
-
-void VMCIQPGuestEndpoints_Init(void);
-void VMCIQPGuestEndpoints_Exit(void);
-void VMCIQPGuestEndpoints_Sync(void);
-void VMCIQPGuestEndpoints_Convert(Bool toLocal, Bool deviceReset);
-
-int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
-                        uint64 produceSize, VMCIQueue **consumeQ,
-                        uint64 consumeSize, VMCIId peer, uint32 flags,
-                        VMCIPrivilegeFlags privFlags);
-int VMCIQueuePair_Detach(VMCIHandle handle);
-
-
-
-#endif /* !_VMCI_QUEUE_PAIR_INT_H_ */
-
index dc49eb0320f87499b7378d90b5450d6cee40397c..9a55afb65dad5586697464e48c67b544588b4d28 100644 (file)
@@ -50,7 +50,7 @@
 #include "vmciDoorbell.h"
 #include "vmciEvent.h"
 #include "vmciInt.h"
-#include "vmciQueuePairInt.h"
+#include "vmciQueuePair.h"
 #include "vmciResource.h"
 #include "vmciUtil.h"
 
index 904a50de40157aac0dcb2628b4bc278b066a1ebe..0f5aad60fced62d8686d449f41c562f017d700bf 100644 (file)
@@ -25,8 +25,8 @@
 #ifndef _VMCI_VERSION_H_
 #define _VMCI_VERSION_H_
 
-#define VMCI_DRIVER_VERSION          9.1.8.0
-#define VMCI_DRIVER_VERSION_COMMAS   9,1,8,0
-#define VMCI_DRIVER_VERSION_STRING   "9.1.8.0"
+#define VMCI_DRIVER_VERSION          9.1.9.0
+#define VMCI_DRIVER_VERSION_COMMAS   9,1,9,0
+#define VMCI_DRIVER_VERSION_STRING   "9.1.9.0"
 
 #endif /* _VMCI_VERSION_H_ */