]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Internal branch sync. Included in this change:
authorVMware, Inc <>
Mon, 15 Oct 2012 04:54:51 +0000 (21:54 -0700)
committerDmitry Torokhov <dtor@vmware.com>
Fri, 19 Oct 2012 18:32:41 +0000 (11:32 -0700)
. VMCI update to support VM-to-VM communication

. VIX updates

. changes in shared code that don't affect open-vm-tools functionality

Signed-off-by: Dmitry Torokhov <dtor@vmware.com>
17 files changed:
open-vm-tools/lib/include/guestStats.h
open-vm-tools/lib/include/vix.h
open-vm-tools/lib/include/vm_version.h
open-vm-tools/lib/include/vmci_defs.h
open-vm-tools/lib/include/vmware/tools/utils.h
open-vm-tools/modules/linux/shared/vmci_defs.h
open-vm-tools/modules/linux/shared/vmci_kernel_if.h
open-vm-tools/modules/linux/vmci/common/vmciContext.c
open-vm-tools/modules/linux/vmci/common/vmciDatagram.c
open-vm-tools/modules/linux/vmci/common/vmciQPair.c
open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c
open-vm-tools/modules/linux/vmci/common/vmciRoute.c
open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c
open-vm-tools/modules/linux/vmci/linux/vmci_version.h
open-vm-tools/modules/shared/vmxnet/vmnet_def.h
open-vm-tools/services/plugins/vix/vixTools.c
open-vm-tools/services/plugins/vix/vixToolsInt.h

index 11523c3428accb979f2b3144ccd851ba47f29af5..356a10289a84c0d864f29e2a1744d32e58242efc 100644 (file)
@@ -30,6 +30,8 @@
 #define INCLUDE_ALLOW_VMKERNEL
 #include "includeCheck.h"
 
+#include "vm_basic_types.h"
+
 typedef
 #include "vmware_pack_begin.h"
 struct GuestMemInfo {
index 47d862d2a21512ceeb6d26ac30f584028fe031db..f396d65add7deaaa3e2d865b476739306f52fd36 100644 (file)
@@ -383,6 +383,12 @@ enum {
    VIX_E_MNTAPI_OPEN_FAILURE                    = 24321,
    VIX_E_MNTAPI_VOLUME_NOT_WRITABLE             = 24322,
 
+   /* Success on operation that completes asynchronously */
+   VIX_ASYNC                                    = 25000,
+
+   /* Async errors */
+   VIX_E_ASYNC_MIXEDMODE_UNSUPPORTED            = 26000,
+
    /* Network Errors */
    VIX_E_NET_HTTP_UNSUPPORTED_PROTOCOL     = 30001,
    VIX_E_NET_HTTP_URL_MALFORMAT            = 30003,
index 84f442fdb460fb6c35725ba0dc9e526aac8e5165..f5a59f33a060bf8d536bfbe09f2e2232d44ed943 100644 (file)
  * a parameter that no longer match the content of the dormant license
  * file.
  */
+#define PRODUCT_MAC_DESKTOP_VERSION_STRING_FOR_LICENSE "5.0"
+
 #if defined(VMX86_TOOLS)
 /* This product doesn't use a license */
 #  define PRODUCT_VERSION_STRING_FOR_LICENSE ""
 #    define PRODUCT_LICENSE_VERSION "1.0"
 #  elif defined(VMX86_DESKTOP)
 #    if defined(__APPLE__)
-#      define PRODUCT_LICENSE_VERSION "5.0"
+#      define PRODUCT_LICENSE_VERSION PRODUCT_MAC_DESKTOP_VERSION_STRING_FOR_LICENSE
 #    else
 #      define PRODUCT_LICENSE_VERSION "9.0"
 #    endif
index 48595d9cc8a044b55545384839009fc57c16e85f..591d7081c2fa8dae5afdc0a1e71ed60dbbbc98f4 100644 (file)
@@ -90,10 +90,10 @@ typedef enum VMCIIntrType {
 
 
 /*
- * A single VMCI device has an upper limit of 128MB on the amount of
+ * A single VMCI device has an upper limit of 1024MB on the amount of
  * memory that can be used for queue pairs.
  */
-#define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024)
+#define VMCI_MAX_GUEST_QP_MEMORY (1024 * 1024 * 1024)
 
 /*
  * Queues with pre-mapped data pages must be small, so that we don't pin
index 8ad9bcb10fda38b58c803b5b73ba1258032d8f1a..13a5e3d84323529be1eca11480510f792a45cccc 100644 (file)
@@ -131,6 +131,9 @@ typedef gboolean (*SignalSourceCb)(const siginfo_t *, gpointer);
 GSource *
 VMTools_NewSignalSource(int signum);
 
+gchar *
+VMTools_GetLibdir(void);
+
 #endif
 
 GSource *
index 6984fd165cee26f4f520cab3b7eb67587e6dbf62..0379f29c245f64476dff436ccd86341ce40bbd56 100644 (file)
@@ -90,10 +90,10 @@ typedef enum VMCIIntrType {
 
 
 /*
- * A single VMCI device has an upper limit of 128MB on the amount of
+ * A single VMCI device has an upper limit of 1024MB on the amount of
  * memory that can be used for queue pairs.
  */
-#define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024)
+#define VMCI_MAX_GUEST_QP_MEMORY (1024 * 1024 * 1024)
 
 /*
  * Queues with pre-mapped data pages must be small, so that we don't pin
index 0fe0d20fb85f5f05125dce0dbc934e113dfc6281..2993c77f486ca57c46ab9a11fe6014b98480669f 100644 (file)
@@ -314,7 +314,7 @@ void VMCIKernelIf_Exit(void);
 #if defined(_WIN32)
 void VMCIKernelIf_DrainDelayedWork(void);
 #endif // _WIN32
-#endif // SOLARIS || _WIN32 || __APPLE__
+#endif // SOLARIS || _WIN32 || __APPLE__ || VMKERNEL
 
 #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \
                            defined(SOLARIS) || defined(__APPLE__))
@@ -350,15 +350,19 @@ typedef uint32 VMCIGuestMemID;
 #if defined(VMKERNEL) || defined(__linux__)  || defined(_WIN32) || \
     defined(__APPLE__)
   struct QueuePairPageStore;
-  int VMCIHost_RegisterUserMemory(struct QueuePairPageStore *pageStore,
+  int VMCIHost_RegisterUserMemory(unsigned int index,
+                                  struct QueuePairPageStore *pageStore,
                                   struct VMCIQueue *produceQ,
                                   struct VMCIQueue *consumeQ);
-  void VMCIHost_UnregisterUserMemory(struct VMCIQueue *produceQ,
+  void VMCIHost_UnregisterUserMemory(unsigned int index,
+                                     struct VMCIQueue *produceQ,
                                      struct VMCIQueue *consumeQ);
-  int VMCIHost_MapQueues(struct VMCIQueue *produceQ,
+  int VMCIHost_MapQueues(unsigned int index,
+                         struct VMCIQueue *produceQ,
                          struct VMCIQueue *consumeQ,
                          uint32 flags);
-  int VMCIHost_UnmapQueues(VMCIGuestMemID gid,
+  int VMCIHost_UnmapQueues(unsigned int index,
+                           VMCIGuestMemID gid,
                            struct VMCIQueue *produceQ,
                            struct VMCIQueue *consumeQ);
   void VMCI_InitQueueMutex(struct VMCIQueue *produceQ,
@@ -369,23 +373,25 @@ typedef uint32 VMCIGuestMemID;
   void VMCI_ReleaseQueueMutex(struct VMCIQueue *queue);
 #else // Below are the guest OS'es without host side support.
 #  define VMCI_InitQueueMutex(_pq, _cq)
-#  define VMCI_CleanupQueueMutex(_pq, _cq)
+#  define VMCI_CleanupQueueMutex(_pq, _cq) do { } while (0)
 #  define VMCI_AcquireQueueMutex(_q, _cb) VMCI_SUCCESS
-#  define VMCI_ReleaseQueueMutex(_q)
-#  define VMCIHost_RegisterUserMemory(_ps, _pq, _cq) VMCI_ERROR_UNAVAILABLE
-#  define VMCIHost_UnregisterUserMemory(_pq, _cq)
-#  define VMCIHost_MapQueues(_pq, _cq, _f) VMCI_SUCCESS
-#  define VMCIHost_UnmapQueues(_gid, _pq, _cq) VMCI_SUCCESS
+#  define VMCI_ReleaseQueueMutex(_q) do { } while (0)
+#  define VMCIHost_RegisterUserMemory(_idx, _ps, _pq, _cq) VMCI_ERROR_UNAVAILABLE
+#  define VMCIHost_UnregisterUserMemory(_idx, _pq, _cq) do { } while (0)
+#  define VMCIHost_MapQueues(_idx, _pq, _cq, _f) VMCI_SUCCESS
+#  define VMCIHost_UnmapQueues(_idx, _gid, _pq, _cq) VMCI_SUCCESS
 #endif
 
 #if defined(VMKERNEL)
-  void VMCIHost_MarkQueuesAvailable(struct VMCIQueue *produceQ,
+  void VMCIHost_MarkQueuesAvailable(unsigned int index,
+                                    struct VMCIQueue *produceQ,
                                     struct VMCIQueue *consumeQ);
-  void VMCIHost_MarkQueuesUnavailable(struct VMCIQueue *produceQ,
+  void VMCIHost_MarkQueuesUnavailable(unsigned int index,
+                                      struct VMCIQueue *produceQ,
                                       struct VMCIQueue *consumeQ);
 #else
-#  define VMCIHost_MarkQueuesAvailable(_q, _p) while(0) { }
-#  define VMCIHost_MarkQueuesUnavailable(_q, _p) while(0) { }
+#  define VMCIHost_MarkQueuesAvailable(_idx, _q, _p) do { } while (0)
+#  define VMCIHost_MarkQueuesUnavailable(_idx, _q, _p) do { } while(0)
 #endif
 
 #if defined(VMKERNEL) || defined(__linux__)
@@ -398,14 +404,16 @@ typedef uint32 VMCIGuestMemID;
 
 #if (!defined(VMKERNEL) && defined(__linux__)) || defined(_WIN32) ||  \
    defined(__APPLE__) || defined(SOLARIS)
-  int VMCIHost_GetUserMemory(VA64 produceUVA, VA64 consumeUVA,
+  int VMCIHost_GetUserMemory(unsigned int index,
+                             VA64 produceUVA, VA64 consumeUVA,
                              struct VMCIQueue *produceQ,
                              struct VMCIQueue *consumeQ);
-  void VMCIHost_ReleaseUserMemory(struct VMCIQueue *produceQ,
+  void VMCIHost_ReleaseUserMemory(unsigned int index,
+                                  struct VMCIQueue *produceQ,
                                   struct VMCIQueue *consumeQ);
 #else
-#  define VMCIHost_GetUserMemory(_puva, _cuva, _pq, _cq) VMCI_ERROR_UNAVAILABLE
-#  define VMCIHost_ReleaseUserMemory(_pq, _cq) ASSERT_NOT_IMPLEMENTED(FALSE)
+#  define VMCIHost_GetUserMemory(_idx, _puva, _cuva, _pq, _cq) VMCI_ERROR_UNAVAILABLE
+#  define VMCIHost_ReleaseUserMemory(_idx, _pq, _cq) ASSERT_NOT_IMPLEMENTED(FALSE)
 #endif
 
 #if defined(_WIN32)
index bace03d920bc40d5ce51c00e759f12609ed6fae2..0e05de5e04f69b4ff80d77febfdde69fc9a7821f 100644 (file)
@@ -1977,7 +1977,8 @@ VMCIContext_NotifyDoorbell(VMCIId srcCID,                   // IN
    if (srcCID != handle.context) {
       VMCIPrivilegeFlags dstPrivFlags;
 
-      if (VMCI_CONTEXT_IS_VM(srcCID) && VMCI_CONTEXT_IS_VM(handle.context)) {
+      if (!vmkernel && VMCI_CONTEXT_IS_VM(srcCID) &&
+          VMCI_CONTEXT_IS_VM(handle.context)) {
          VMCI_DEBUG_LOG(4, (LGPFX"Doorbell notification from VM to VM not "
                             "supported (src=0x%x, dst=0x%x).\n",
                             srcCID, handle.context));
index d0fe015fd2c35ae1dc3bb0e9d2f6c1f4bc684511..6c59e6a7ba58b7038c1ff9806d6d56ccf2cf9c14 100644 (file)
@@ -553,6 +553,7 @@ VMCIDatagramDispatchAsHost(VMCIId contextID,  // IN:
 
    if (contextID == VMCI_HOST_CONTEXT_ID &&
        dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID) {
+      VMCI_DEBUG_LOG(4, (LGPFX"Host cannot talk to hypervisor\n"));
       return VMCI_ERROR_DST_UNREACHABLE;
    }
 
@@ -667,28 +668,35 @@ VMCIDatagramDispatchAsHost(VMCIId contextID,  // IN:
       if (contextID != dg->dst.context) {
          if (VMCIDenyInteraction(srcPrivFlags,
                                  VMCIContext_GetPrivFlags(dg->dst.context))) {
+            VMCI_DEBUG_LOG(4, (LGPFX"Interaction denied (%X/%X - %X/%X)\n",
+                           contextID, srcPrivFlags,
+                           dg->dst.context, VMCIContext_GetPrivFlags(dg->dst.context)));
             return VMCI_ERROR_NO_ACCESS;
          } else if (VMCI_CONTEXT_IS_VM(contextID)) {
             /*
              * If the sending context is a VM, it cannot reach another VM.
              */
 
-            VMCI_DEBUG_LOG(4, (LGPFX"Datagram communication between VMs not"
-                               "supported (src=0x%x, dst=0x%x).\n",
-                               contextID, dg->dst.context));
-            return VMCI_ERROR_DST_UNREACHABLE;
+            if (!vmkernel) {
+               VMCI_DEBUG_LOG(4, (LGPFX"Datagram communication between VMs not "
+                                  "supported (src=0x%x, dst=0x%x).\n",
+                                  contextID, dg->dst.context));
+               return VMCI_ERROR_DST_UNREACHABLE;
+            }
          }
       }
 
       /* We make a copy to enqueue. */
       newDG = VMCI_AllocKernelMem(dgSize, VMCI_MEMORY_NORMAL);
       if (newDG == NULL) {
+         VMCI_DEBUG_LOG(4, (LGPFX"No memory for datagram\n"));
          return VMCI_ERROR_NO_MEM;
       }
       memcpy(newDG, dg, dgSize);
       retval = VMCIContext_EnqueueDatagram(dg->dst.context, newDG);
       if (retval < VMCI_SUCCESS) {
          VMCI_FreeKernelMem(newDG, dgSize);
+         VMCI_DEBUG_LOG(4, (LGPFX"Enqueue failed\n"));
          return retval;
       }
    }
index a3d612f9dbec826a08ba97c7fd16fd7d4b45bda4..82d66ba8a05a058495569adb5301fc7a90a3e661 100644 (file)
@@ -294,7 +294,14 @@ VMCIQPairMapQueueHeaders(VMCIQueue *produceQ, // IN
 
    if (NULL == produceQ->qHeader || NULL == consumeQ->qHeader) {
       if (canBlock) {
-         result = VMCIHost_MapQueues(produceQ, consumeQ, 0);
+         /*
+          * We return data from creator of the queue in VM2VM case.
+          * That should be OK, as if they do not match then there
+          * is somebody else in progress of making them match, and
+          * you should not be looking at somebody else's queue if
+          * queue is active.
+          */
+         result = VMCIHost_MapQueues(0, produceQ, consumeQ, 0);
       } else {
          result = VMCI_ERROR_QUEUEPAIR_NOT_READY;
       }
index 8fac7d8106902ee5e8fb341190f66e373c06f30d..6d0fc7e6c02726ed06f3278203e19099a9b97a65 100644 (file)
  *            --------------  NEW  -------------
  *            |                                |
  *           \_/                              \_/
- *     CREATED_NO_MEM <-----------------> CREATED_MEM
+ *     CREATED (nomem) <-----------------> CREATED
  *            |    |                           |
  *            |    o-----------------------o   |
  *            |                            |   |
  *           \_/                          \_/ \_/
- *     ATTACHED_NO_MEM <----------------> ATTACHED_MEM
+ *     ATTACHED (nomem) <----------------> ATTACHED
  *            |                            |   |
  *            |     o----------------------o   |
  *            |     |                          |
  *           \_/   \_/                        \_/
- *     SHUTDOWN_NO_MEM <----------------> SHUTDOWN_MEM
+ *     SHUTDOWN (nomem) <----------------> SHUTDOWN
  *            |                                |
  *            |                                |
  *            -------------> gone <-------------
  *
  * In more detail. When a VMCI queue pair is first created, it will be in the
  * VMCIQPB_NEW state. It will then move into one of the following states:
- * - VMCIQPB_CREATED_NO_MEM: this state indicates that either:
+ * - VMCIQPB_CREATED with hasMem[0] FALSE: this state indicates that either:
  *     - the created was performed by a host endpoint, in which case there is no
  *       backing memory yet.
  *     - the create was initiated by an old-style VMX, that uses
  *       later point in time. This state can be distinguished from the one above
  *       by the context ID of the creator. A host side is not allowed to attach
  *       until the page store has been set.
- * - VMCIQPB_CREATED_MEM: this state is the result when the queue pair is created
- *     by a VMX using the queue pair device backend that sets the UVAs of the
- *     queue pair immediately and stores the information for later attachers. At
- *     this point, it is ready for the host side to attach to it.
+ * - VMCIQPB_CREATED with hasMem[0] TRUE: this state is the result when the
+ *     queue pair is created by a VMX using the queue pair device backend that
+ *     sets the UVAs of the queue pair immediately and stores the information
+ *     for later attachers. At this point, it is ready for the host side to attach
+ *     to it.
  * Once the queue pair is in one of the created states (with the exception of the
  * case mentioned for older VMX'en above), it is possible to attach to the queue
  * pair. Again we have two new states possible:
- * - VMCIQPB_ATTACHED_MEM: this state can be reached through the following paths:
- *     - from VMCIQPB_CREATED_NO_MEM when a new-style VMX allocates a queue pair,
+ * - VMCIQPB_ATTACHED with hasMem[0] TRUE: this state can be reached through
+ *   the following paths:
+ *     - from VMCIQPB_CREATED without memory when a new-style VMX allocates a queue pair,
  *       and attaches to a queue pair previously created by the host side.
- *     - from VMCIQPB_CREATED_MEM when the host side attaches to a queue pair
+ *     - from VMCIQPB_CREATED with memory when the host side attaches to a queue pair
  *       already created by a guest.
- *     - from VMCIQPB_ATTACHED_NO_MEM, when an old-style VMX calls
+ *     - from VMCIQPB_ATTACHED without memory, when an old-style VMX calls
  *       VMCIQPBroker_SetPageStore (see below).
- * - VMCIQPB_ATTACHED_NO_MEM: If the queue pair already was in the
- *     VMCIQPB_CREATED_NO_MEM due to a host side create, an old-style VMX will
- *     bring the queue pair into this state. Once VMCIQPBroker_SetPageStore is
- *     called to register the user memory, the VMCIQPB_ATTACH_MEM state will be
+ * - VMCIQPB_ATTACHED with hasMem[0] FALSE: If the queue pair already was in the
+ *     VMCIQPB_CREATED without memory due to a host side create, an old-style VMX
+ *     will bring the queue pair into this state. Once VMCIQPBroker_SetPageStore is
+ *     called to register the user memory, the VMCIQPB_ATTACH with memory state will be
  *     entered.
  * From the attached queue pair, the queue pair can enter the shutdown states
  * when either side of the queue pair detaches. If the guest side detaches first,
- * the queue pair will enter the VMCIQPB_SHUTDOWN_NO_MEM state, where the content
+ * the queue pair will enter the VMCIQPB_SHUTDOWN without memory state, where the content
  * of the queue pair will no longer be available. If the host side detaches first,
- * the queue pair will either enter the VMCIQPB_SHUTDOWN_MEM, if the guest memory
- * is currently mapped, or VMCIQPB_SHUTDOWN_NO_MEM, if the guest memory is not
+ * the queue pair will either enter the VMCIQPB_SHUTDOWN with memory, if the guest memory
+ * is currently mapped, or VMCIQPB_SHUTDOWN without memory, if the guest memory is not
  * mapped (e.g., the host detaches while a guest is stunned).
  *
  * New-style VMX'en will also unmap guest memory, if the guest is quiesced, e.g.,
  * during a snapshot operation. In that case, the guest memory will no longer be
- * available, and the queue pair will transition from *_MEM state to a *_NO_MEM
- * state. The VMX may later map the memory once more, in which case the queue
- * pair will transition from the *_NO_MEM state at that point back to the *_MEM
- * state. Note that the *_NO_MEM state may have changed, since the peer may have
- * either attached or detached in the meantime. The values are laid out such that
- * ++ on a state will move from a *_NO_MEM to a *_MEM state, and vice versa.
+ * available, and the queue pair will transition from memory to memory-less state.
+ * The VMX may later map the memory once more, in which case the queue
+ * pair will transition from the memory-less state at that point back to the memory
+ * state.
  */
 
 typedef enum {
    VMCIQPB_NEW,
-   VMCIQPB_CREATED_NO_MEM,
-   VMCIQPB_CREATED_MEM,
-   VMCIQPB_ATTACHED_NO_MEM,
-   VMCIQPB_ATTACHED_MEM,
-   VMCIQPB_SHUTDOWN_NO_MEM,
-   VMCIQPB_SHUTDOWN_MEM,
+   VMCIQPB_CREATED,
+   VMCIQPB_ATTACHED,
+   VMCIQPB_SHUTDOWN,
    VMCIQPB_GONE
 } QPBrokerState;
 
-#define QPBROKERSTATE_HAS_MEM(_qpb) (_qpb->state == VMCIQPB_CREATED_MEM || \
-                                     _qpb->state == VMCIQPB_ATTACHED_MEM || \
-                                     _qpb->state == VMCIQPB_SHUTDOWN_MEM)
 
 /*
  * In the queue pair broker, we always use the guest point of view for
@@ -160,7 +154,8 @@ typedef struct QPBrokerEntry {
    QueuePairEntry       qp;
    VMCIId               createId;
    VMCIId               attachId;
-   QPBrokerState        state;
+   QPBrokerState        stateQP;
+   Bool                 hasMem[2];
    Bool                 requireTrustedAttach;
    Bool                 createdByTrusted;
    Bool                 vmciPageFiles;  // Created by VMX using VMCI page files
@@ -171,6 +166,7 @@ typedef struct QPBrokerEntry {
    VMCIEventReleaseCB   wakeupCB;
    void                *clientData;
    void                *localMem; // Kernel memory for local queue pair
+   Bool                 isVM2VM;
 } QPBrokerEntry;
 
 #if !defined(VMKERNEL)
@@ -256,7 +252,7 @@ static int VMCIQueuePairAllocHostWork(VMCIHandle *handle, VMCIQueue **produceQ,
                                       void *clientData);
 static int VMCIQueuePairDetachHostWork(VMCIHandle handle);
 
-static int QueuePairSaveHeaders(QPBrokerEntry *entry);
+static int QueuePairSaveHeaders(QPBrokerEntry *entry, VMCIId contextId);
 static void QueuePairResetSavedHeaders(QPBrokerEntry *entry);
 
 #if !defined(VMKERNEL)
@@ -285,6 +281,32 @@ extern int VMCI_SendDatagram(VMCIDatagram *);
 #endif
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPBEGetIndex --
+ *
+ *      Retrieve index into host's queue structures for queue entry.
+ *
+ * Results:
+ *      0 or 1.  Or crash.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static unsigned int
+VMCIQPBEGetIndex(const QPBrokerEntry *entry,      // IN
+                 VMCIId               contextId)  // IN
+{
+   ASSERT(entry->createId == contextId || entry->attachId == contextId);
+
+   return (entry->isVM2VM && entry->createId != contextId) ? 1 : 0;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -909,10 +931,12 @@ VMCIQPBrokerAllocInt(VMCIHandle handle,             // IN
        !(produceSize || consumeSize) ||
        !context || contextId == VMCI_INVALID_ID ||
        handle.context == VMCI_INVALID_ID) {
+      VMCI_DEBUG_LOG(5, ("Invalid argument - handle, flags, whatever\n"));
       return VMCI_ERROR_INVALID_ARGS;
    }
 
    if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
+      VMCI_DEBUG_LOG(5, ("Invalid argument - page store\n"));
       return VMCI_ERROR_INVALID_ARGS;
    }
 
@@ -1006,12 +1030,14 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
    int result;
    uint64 guestProduceSize;
    uint64 guestConsumeSize;
+   Bool isVM2VM;
 
    /*
     * Do not create if the caller asked not to.
     */
 
    if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
+      VMCI_DEBUG_LOG(5, ("QP Create - attach only\n"));
       return VMCI_ERROR_NOT_FOUND;
    }
 
@@ -1021,10 +1047,14 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
     */
 
    if (handle.context != contextId && handle.context != peer) {
+      VMCI_DEBUG_LOG(5, ("QP Create - contextId fail, %x != %x, %x\n",
+                         handle.context, contextId, peer));
       return VMCI_ERROR_NO_ACCESS;
    }
 
-   if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(peer)) {
+   isVM2VM = VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(peer);
+   if (!vmkernel && isVM2VM) {
+      VMCI_DEBUG_LOG(5, ("QP Create - VM2VM\n"));
       return VMCI_ERROR_DST_UNREACHABLE;
    }
 
@@ -1034,11 +1064,14 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
     */
 
    if (isLocal && peer != VMCI_INVALID_ID && contextId != peer) {
+      VMCI_DEBUG_LOG(5, ("QP Create - peer %x, context %x\n",
+                         peer, contextId));
       return VMCI_ERROR_NO_ACCESS;
    }
 
    entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
    if (!entry) {
+      VMCI_DEBUG_LOG(5, ("QP Create - no memory\n"));
       return VMCI_ERROR_NO_MEM;
    }
 
@@ -1067,7 +1100,7 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
    entry->qp.refCount = 1;
    entry->createId = contextId;
    entry->attachId = VMCI_INVALID_ID;
-   entry->state = VMCIQPB_NEW;
+   entry->stateQP = VMCIQPB_NEW;
    entry->requireTrustedAttach =
       (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
    entry->createdByTrusted =
@@ -1075,14 +1108,17 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
    entry->vmciPageFiles = FALSE;
    entry->wakeupCB = wakeupCB;
    entry->clientData = clientData;
+   entry->isVM2VM = FALSE;   /* It is not VM2VM until VM attaches... */
    entry->produceQ = VMCIHost_AllocQueue(guestProduceSize);
    if (entry->produceQ == NULL) {
       result = VMCI_ERROR_NO_MEM;
+      VMCI_DEBUG_LOG(5, ("QP Create - no memory PQ\n"));
       goto error;
    }
    entry->consumeQ = VMCIHost_AllocQueue(guestConsumeSize);
    if (entry->consumeQ == NULL) {
       result = VMCI_ERROR_NO_MEM;
+      VMCI_DEBUG_LOG(5, ("QP Create - no memory CQ\n"));
       goto error;
    }
 
@@ -1097,9 +1133,11 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
                                             VMCI_MEMORY_NONPAGED);
       if (entry->localMem == NULL) {
          result = VMCI_ERROR_NO_MEM;
+         VMCI_DEBUG_LOG(5, ("QP Create - no memory LM\n"));
          goto error;
       }
-      entry->state = VMCIQPB_CREATED_MEM;
+      entry->stateQP = VMCIQPB_CREATED;
+      entry->hasMem[0] = TRUE;
       entry->produceQ->qHeader = entry->localMem;
       entry->consumeQ->qHeader =
          (VMCIQueueHeader *)((uint8 *)entry->localMem +
@@ -1107,21 +1145,23 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
       VMCIQueueHeader_Init(entry->produceQ->qHeader, handle);
       VMCIQueueHeader_Init(entry->consumeQ->qHeader, handle);
    } else if (pageStore) {
-      ASSERT(entry->createId != VMCI_HOST_CONTEXT_ID || isLocal);
+      ASSERT(entry->createId != VMCI_HOST_CONTEXT_ID);
 
       /*
        * The VMX already initialized the queue pair headers, so no
        * need for the kernel side to do that.
        */
 
-      result = VMCIHost_RegisterUserMemory(pageStore,
+      result = VMCIHost_RegisterUserMemory(0, pageStore,
                                            entry->produceQ,
                                            entry->consumeQ);
       if (result < VMCI_SUCCESS) {
+         VMCI_DEBUG_LOG(5, ("QP Create - cannot register user memory\n"));
          goto error;
       }
-      VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
-      entry->state = VMCIQPB_CREATED_MEM;
+      VMCIHost_MarkQueuesAvailable(0, entry->produceQ, entry->consumeQ);
+      entry->stateQP = VMCIQPB_CREATED;
+      entry->hasMem[0] = TRUE;
    } else {
       /*
        * A create without a pageStore may be either a host side create (in which
@@ -1130,7 +1170,7 @@ VMCIQPBrokerCreate(VMCIHandle handle,             // IN
        * call as the next step).
        */
 
-      entry->state = VMCIQPB_CREATED_NO_MEM;
+      entry->stateQP = VMCIQPB_CREATED;
    }
 
    QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
@@ -1205,25 +1245,32 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
    const VMCIId contextId = VMCIContext_GetId(context);
    Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
    int result;
+   Bool isVM2VM;
 
-   if (entry->state != VMCIQPB_CREATED_NO_MEM &&
-       entry->state != VMCIQPB_CREATED_MEM) {
+   if (entry->stateQP != VMCIQPB_CREATED) {
+      VMCI_DEBUG_LOG(5, ("QP Attach - state is %x\n", entry->stateQP));
       return VMCI_ERROR_UNAVAILABLE;
    }
 
    if (isLocal) {
       if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
           contextId != entry->createId) {
+         VMCI_DEBUG_LOG(5, ("QP Attach - invalid args, ctx=%x, createId=%x\n",
+                            contextId, entry->createId));
          return VMCI_ERROR_INVALID_ARGS;
       }
    } else if (contextId == entry->createId || contextId == entry->attachId) {
+      VMCI_DEBUG_LOG(5, ("QP Attach - already, ctx=%x, create=%x, attach=%x\n",
+                         contextId, entry->createId, entry->attachId));
       return VMCI_ERROR_ALREADY_EXISTS;
    }
 
    ASSERT(entry->qp.refCount < 2);
    ASSERT(entry->attachId == VMCI_INVALID_ID);
 
-   if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(entry->createId)) {
+   isVM2VM = VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(entry->createId);
+   if (!vmkernel && isVM2VM) {
+      VMCI_DEBUG_LOG(5, ("QP Attach - VM2VM\n"));
       return VMCI_ERROR_DST_UNREACHABLE;
    }
 
@@ -1234,6 +1281,7 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
 
    if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
       if (!entry->createdByTrusted) {
+         VMCI_DEBUG_LOG(5, ("QP Attach - restricted vs trusted\n"));
          return VMCI_ERROR_NO_ACCESS;
       }
    }
@@ -1245,6 +1293,7 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
 
    if (entry->requireTrustedAttach) {
       if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
+         VMCI_DEBUG_LOG(5, ("QP Attach - trusted attach required\n"));
          return VMCI_ERROR_NO_ACCESS;
       }
    }
@@ -1255,6 +1304,8 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
     */
 
    if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
+      VMCI_DEBUG_LOG(5, ("QP Attach - bad peer id %x != %x\n",
+                         contextId, entry->qp.peer));
       return VMCI_ERROR_NO_ACCESS;
    }
 
@@ -1265,6 +1316,7 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
        */
 
       if (!VMCIContext_SupportsHostQP(context)) {
+         VMCI_DEBUG_LOG(5, ("QP Attach - no attach to host qp\n"));
          return VMCI_ERROR_INVALID_RESOURCE;
       }
    } else if (contextId == VMCI_HOST_CONTEXT_ID) {
@@ -1281,15 +1333,17 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
       VMCIContext_Release(createContext);
 
       if (!supportsHostQP) {
+         VMCI_DEBUG_LOG(5, ("QP Attach - no host attach to qp\n"));
          return VMCI_ERROR_INVALID_RESOURCE;
       }
    }
 
    if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER)) {
+      VMCI_DEBUG_LOG(5, ("QP Attach - flags mismatch\n"));
       return VMCI_ERROR_QUEUEPAIR_MISMATCH;
    }
 
-   if (contextId != VMCI_HOST_CONTEXT_ID) {
+   if (contextId != VMCI_HOST_CONTEXT_ID && !isVM2VM) {
       /*
        * The queue pair broker entry stores values from the guest
        * point of view, so an attaching guest should match the values
@@ -1298,10 +1352,12 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
 
       if (entry->qp.produceSize != produceSize ||
           entry->qp.consumeSize != consumeSize) {
+         VMCI_DEBUG_LOG(5, ("QP Attach - queue size mismatch\n"));
          return VMCI_ERROR_QUEUEPAIR_MISMATCH;
       }
    } else if (entry->qp.produceSize != consumeSize ||
               entry->qp.consumeSize != produceSize) {
+      VMCI_DEBUG_LOG(5, ("QP Attach - host queue size mismatch\n"));
       return VMCI_ERROR_QUEUEPAIR_MISMATCH;
    }
 
@@ -1316,43 +1372,64 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
        * any memory associated with it already.
        */
 
-      if (entry->state != VMCIQPB_CREATED_NO_MEM) {
-         return VMCI_ERROR_INVALID_ARGS;
+      if (isVM2VM) {
+         if (!pageStore || entry->stateQP != VMCIQPB_CREATED) {
+            VMCI_DEBUG_LOG(5, ("QP Attach - bad QP state for VM2VM, %x, %p\n", entry->stateQP, pageStore));
+            return VMCI_ERROR_INVALID_ARGS;
+         }
+      } else {
+         if (entry->stateQP != VMCIQPB_CREATED || entry->hasMem[0]) {
+            VMCI_DEBUG_LOG(5, ("QP Attach - bad QP state, %x\n", entry->stateQP));
+            return VMCI_ERROR_INVALID_ARGS;
+         }
       }
 
       if (pageStore != NULL) {
+         unsigned int index;
+
+         ASSERT(entry->isVM2VM == FALSE);
+         entry->isVM2VM = isVM2VM;
+
          /*
           * Patch up host state to point to guest supplied memory. The VMX
           * already initialized the queue pair headers, so no need for the
           * kernel side to do that.
           */
 
-         result = VMCIHost_RegisterUserMemory(pageStore,
+         index = isVM2VM ? 1 : 0;
+         result = VMCIHost_RegisterUserMemory(index,
+                                              pageStore,
                                               entry->produceQ,
                                               entry->consumeQ);
          if (result < VMCI_SUCCESS) {
+            VMCI_DEBUG_LOG(5, ("QP Attach - cannot register memory\n"));
+            entry->isVM2VM = FALSE;
             return result;
          }
-         VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
+         VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
          if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
-            result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ,
+            result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ,
                                         entry->qp.flags);
             if (result < VMCI_SUCCESS) {
-               VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
+               VMCIHost_ReleaseUserMemory(index, entry->produceQ, entry->consumeQ);
+               entry->isVM2VM = FALSE;
+               VMCI_DEBUG_LOG(5, ("QP Attach - cannot map queues\n"));
                return result;
             }
          }
-         entry->state = VMCIQPB_ATTACHED_MEM;
+         entry->stateQP = VMCIQPB_ATTACHED;
+         entry->hasMem[index] = TRUE;
       } else {
-         entry->state = VMCIQPB_ATTACHED_NO_MEM;
+         entry->stateQP = VMCIQPB_ATTACHED;
       }
-   } else if (entry->state == VMCIQPB_CREATED_NO_MEM) {
+   } else if (entry->stateQP == VMCIQPB_CREATED && !entry->hasMem[0]) {
       /*
        * The host side is attempting to attach to a queue pair that doesn't have
        * any memory associated with it. This must be a pre NOVMVM vmx that hasn't
        * set the page store information yet, or a quiesced VM.
        */
 
+      VMCI_DEBUG_LOG(5, ("QP Attach - QP without memory\n"));
       return VMCI_ERROR_UNAVAILABLE;
    } else {
       /*
@@ -1362,9 +1439,19 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
        */
 
       if (flags & VMCI_QPFLAG_NONBLOCK) {
-         result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, flags);
-         if (result < VMCI_SUCCESS) {
-            return result;
+         /*
+          * We only have to do work here if this is a host-to-VM queuepair.
+          * Otherwise there's nothing to map, since the pages backing the
+          * queues are allocated directly out of host memory.
+          */
+
+         if (!isLocal) {
+            VMCIHost_MarkQueuesAvailable(0, entry->produceQ, entry->consumeQ);
+            result = VMCIHost_MapQueues(0, entry->produceQ, entry->consumeQ, flags);
+            if (result < VMCI_SUCCESS) {
+               VMCI_DEBUG_LOG(5, ("QP Attach - cannot map queues for host\n"));
+               return result;
+            }
          }
          entry->qp.flags |= flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
       }
@@ -1373,10 +1460,10 @@ VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
        * The host side has successfully attached to a queue pair.
        */
 
-      entry->state = VMCIQPB_ATTACHED_MEM;
+      entry->stateQP = VMCIQPB_ATTACHED;
    }
 
-   if (entry->state == VMCIQPB_ATTACHED_MEM) {
+   if (entry->stateQP == VMCIQPB_ATTACHED && entry->hasMem[0] && (!entry->isVM2VM || entry->hasMem[1])) {
       result = QueuePairNotifyPeer(TRUE, entry->qp.handle, contextId,
                                    entry->createId);
       if (result < VMCI_SUCCESS) {
@@ -1450,6 +1537,7 @@ VMCIQPBroker_SetPageStore(VMCIHandle handle,      // IN
    QPBrokerEntry *entry;
    int result;
    const VMCIId contextId = VMCIContext_GetId(context);
+   unsigned int index;
 
    if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
       return VMCI_ERROR_INVALID_ARGS;
@@ -1494,33 +1582,30 @@ VMCIQPBroker_SetPageStore(VMCIHandle handle,      // IN
       goto out;
    }
 
-   if (entry->state != VMCIQPB_CREATED_NO_MEM &&
-       entry->state != VMCIQPB_ATTACHED_NO_MEM) {
+   index = VMCIQPBEGetIndex(entry, contextId);
+
+   if (entry->hasMem[index] ||
+       (entry->stateQP != VMCIQPB_CREATED && entry->stateQP == VMCIQPB_ATTACHED)) {
       result = VMCI_ERROR_UNAVAILABLE;
       goto out;
    }
 
-   result = VMCIHost_GetUserMemory(produceUVA, consumeUVA,
+   result = VMCIHost_GetUserMemory(index, produceUVA, consumeUVA,
                                    entry->produceQ, entry->consumeQ);
    if (result < VMCI_SUCCESS) {
       goto out;
    }
-   VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
-   result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE);
+   VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
+   result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ, 0);
    if (result < VMCI_SUCCESS) {
-     VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
+     VMCIHost_ReleaseUserMemory(index, entry->produceQ, entry->consumeQ);
      goto out;
    }
 
-   if (entry->state == VMCIQPB_CREATED_NO_MEM) {
-      entry->state = VMCIQPB_CREATED_MEM;
-   } else {
-      ASSERT(entry->state == VMCIQPB_ATTACHED_NO_MEM);
-      entry->state = VMCIQPB_ATTACHED_MEM;
-   }
+   entry->hasMem[index] = TRUE;
    entry->vmciPageFiles = TRUE;
 
-   if (entry->state == VMCIQPB_ATTACHED_MEM) {
+   if (entry->stateQP == VMCIQPB_ATTACHED && entry->hasMem[0] && (!entry->isVM2VM || entry->hasMem[1])) {
       result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
       if (result < VMCI_SUCCESS) {
          VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
@@ -1576,6 +1661,7 @@ VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
    VMCIId peerId;
    Bool isLocal = FALSE;
    int result;
+   unsigned int index;
 
    if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
       return VMCI_ERROR_INVALID_ARGS;
@@ -1605,6 +1691,8 @@ VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
       goto out;
    }
 
+   index = VMCIQPBEGetIndex(entry, contextId);
+
    if (contextId == entry->createId) {
       peerId = entry->attachId;
       entry->createId = VMCI_INVALID_ID;
@@ -1630,8 +1718,9 @@ VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
 
       VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
       headersMapped = entry->produceQ->qHeader || entry->consumeQ->qHeader;
-      if (QPBROKERSTATE_HAS_MEM(entry)) {
-         result = VMCIHost_UnmapQueues(INVALID_VMCI_GUEST_MEM_ID,
+      if (entry->hasMem[index]) {
+         VMCIHost_MarkQueuesUnavailable(index, entry->produceQ, entry->consumeQ);
+         result = VMCIHost_UnmapQueues(index, INVALID_VMCI_GUEST_MEM_ID,
                                        entry->produceQ,
                                        entry->consumeQ);
          if (result < VMCI_SUCCESS) {
@@ -1639,16 +1728,19 @@ VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
                           "(handle=0x%x:0x%x,result=%d).\n", handle.context,
                           handle.resource, result));
          }
-         VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ);
          if (entry->vmciPageFiles) {
-            VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
+            VMCIHost_ReleaseUserMemory(index, entry->produceQ, entry->consumeQ);
          } else {
-            VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
+            VMCIHost_UnregisterUserMemory(index, entry->produceQ, entry->consumeQ);
          }
+         entry->hasMem[index] = FALSE;
       }
       if (!headersMapped) {
          QueuePairResetSavedHeaders(entry);
       }
+      if (index == 1) {
+         entry->isVM2VM = FALSE;
+      }
       VMCI_ReleaseQueueMutex(entry->produceQ);
       if (!headersMapped && entry->wakeupCB) {
          entry->wakeupCB(entry->clientData);
@@ -1665,7 +1757,10 @@ VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
 
       if (isLocal) {
          VMCI_FreeKernelMem(entry->localMem, QPE_NUM_PAGES(entry->qp) * PAGE_SIZE);
+         entry->hasMem[0] = FALSE;
       }
+      ASSERT(entry->hasMem[0] == FALSE);
+      ASSERT(entry->hasMem[1] == FALSE);
       VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ);
       VMCIHost_FreeQueue(entry->produceQ, entry->qp.produceSize);
       VMCIHost_FreeQueue(entry->consumeQ, entry->qp.consumeSize);
@@ -1675,11 +1770,7 @@ VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
    } else {
       ASSERT(peerId != VMCI_INVALID_ID);
       QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
-      if (contextId == VMCI_HOST_CONTEXT_ID && QPBROKERSTATE_HAS_MEM(entry)) {
-         entry->state = VMCIQPB_SHUTDOWN_MEM;
-      } else {
-         entry->state = VMCIQPB_SHUTDOWN_NO_MEM;
-      }
+      entry->stateQP = VMCIQPB_SHUTDOWN;
       if (!isLocal) {
          VMCIContext_QueuePairDestroy(context, handle);
       }
@@ -1719,6 +1810,8 @@ VMCIQPBroker_Map(VMCIHandle  handle,      // IN
    const VMCIId contextId = VMCIContext_GetId(context);
    Bool isLocal = FALSE;
    int result;
+   unsigned int endpoint;
+   unsigned int index;
 
    if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
       return VMCI_ERROR_INVALID_ARGS;
@@ -1747,6 +1840,8 @@ VMCIQPBroker_Map(VMCIHandle  handle,      // IN
       result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
       goto out;
    }
+   index = VMCIQPBEGetIndex(entry, contextId);
+   endpoint = contextId == entry->createId ? 0 : 1;
 
    isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
 
@@ -1757,9 +1852,9 @@ VMCIQPBroker_Map(VMCIHandle  handle,      // IN
        */
 
       VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
-      VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
+      VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
       if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
-         result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ,
+         result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ,
                                      entry->qp.flags);
       } else {
          result = VMCI_SUCCESS;
@@ -1776,9 +1871,9 @@ VMCIQPBroker_Map(VMCIHandle  handle,      // IN
    } else  if (contextId != VMCI_HOST_CONTEXT_ID) {
       QueuePairPageStore pageStore;
 
-      ASSERT(entry->state == VMCIQPB_CREATED_NO_MEM ||
-             entry->state == VMCIQPB_SHUTDOWN_NO_MEM ||
-             entry->state == VMCIQPB_ATTACHED_NO_MEM);
+      ASSERT((entry->stateQP == VMCIQPB_CREATED ||
+              entry->stateQP == VMCIQPB_SHUTDOWN ||
+              entry->stateQP == VMCIQPB_ATTACHED) && !entry->hasMem[0]);
       ASSERT(!isLocal);
 
       pageStore.pages = guestMem;
@@ -1786,20 +1881,11 @@ VMCIQPBroker_Map(VMCIHandle  handle,      // IN
 
       VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
       QueuePairResetSavedHeaders(entry);
-      result = VMCIHost_RegisterUserMemory(&pageStore, entry->produceQ, entry->consumeQ);
-      VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
+      result = VMCIHost_RegisterUserMemory(index, &pageStore, entry->produceQ, entry->consumeQ);
+      VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
       VMCI_ReleaseQueueMutex(entry->produceQ);
       if (result == VMCI_SUCCESS) {
-         /*
-          * Move state from *_NO_MEM to *_MEM.
-          */
-
-         entry->state++;
-
-         ASSERT(entry->state == VMCIQPB_CREATED_MEM ||
-                entry->state == VMCIQPB_SHUTDOWN_MEM ||
-                entry->state == VMCIQPB_ATTACHED_MEM);
-
+         entry->hasMem[index] = TRUE;
          if (entry->wakeupCB) {
             entry->wakeupCB(entry->clientData);
          }
@@ -1833,7 +1919,8 @@ out:
  */
 
 static int
-QueuePairSaveHeaders(QPBrokerEntry *entry) // IN
+QueuePairSaveHeaders(QPBrokerEntry *entry, // IN
+                     VMCIId contextId)     // IN
 {
    int result;
 
@@ -1844,11 +1931,21 @@ QueuePairSaveHeaders(QPBrokerEntry *entry) // IN
        *  it again, and we don't want to map in the headers
        *  unnecessarily.
        */
-
       return VMCI_SUCCESS;
    }
    if (NULL == entry->produceQ->qHeader || NULL == entry->consumeQ->qHeader) {
-      result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE);
+      unsigned int index;
+
+      /*
+       * If this is second VM, do not save headers: qHeader is for VM which
+       * created queue pair only.  And no API which uses savedHeader should
+       * be used together with VM2VM queue pair anyway.
+       */
+      index = VMCIQPBEGetIndex(entry, contextId);
+      if (index != 0) {
+         return VMCI_SUCCESS;
+      }
+      result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ, 0);
       if (result < VMCI_SUCCESS) {
          return result;
       }
@@ -1924,6 +2021,7 @@ VMCIQPBroker_Unmap(VMCIHandle  handle,   // IN
    const VMCIId contextId = VMCIContext_GetId(context);
    Bool isLocal = FALSE;
    int result;
+   unsigned int index;
 
    if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
       return VMCI_ERROR_INVALID_ARGS;
@@ -1951,24 +2049,22 @@ VMCIQPBroker_Unmap(VMCIHandle  handle,   // IN
       result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
       goto out;
    }
-
+   index = VMCIQPBEGetIndex(entry, contextId);
    isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
 
    if (contextId != VMCI_HOST_CONTEXT_ID) {
-      ASSERT(entry->state != VMCIQPB_CREATED_NO_MEM &&
-             entry->state != VMCIQPB_SHUTDOWN_NO_MEM &&
-             entry->state != VMCIQPB_ATTACHED_NO_MEM);
+      ASSERT(entry->hasMem[index]);
       ASSERT(!isLocal);
 
       VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
-      result = QueuePairSaveHeaders(entry);
+      result = QueuePairSaveHeaders(entry, contextId);
       if (result < VMCI_SUCCESS) {
          VMCI_WARNING((LGPFX"Failed to save queue headers for queue pair "
                        "(handle=0x%x:0x%x,result=%d).\n", handle.context,
                        handle.resource, result));
       }
-      VMCIHost_UnmapQueues(gid, entry->produceQ, entry->consumeQ);
-      VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ);
+      VMCIHost_MarkQueuesUnavailable(index, entry->produceQ, entry->consumeQ);
+      VMCIHost_UnmapQueues(index, gid, entry->produceQ, entry->consumeQ);
       if (!vmkernel) {
          /*
           * On hosted, when we unmap queue pairs, the VMX will also
@@ -1978,13 +2074,8 @@ VMCIQPBroker_Unmap(VMCIHandle  handle,   // IN
           * memory with a possibly new user VA.
           */
 
-         VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
-
-         /*
-          * Move state from *_MEM to *_NO_MEM.
-          */
-
-         entry->state--;
+         VMCIHost_UnregisterUserMemory(index, entry->produceQ, entry->consumeQ);
+         entry->hasMem[index] = FALSE;
       }
 
       VMCI_ReleaseQueueMutex(entry->produceQ);
index 2282d63e206c13eb35dc3359d36e6925c4c17413..81c9d077ceef60f2bfab427ca4794196d09e7e54 100644 (file)
@@ -219,7 +219,9 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
 
             ASSERT(VMCI_CONTEXT_IS_VM(dst->context));
 
-            return VMCI_ERROR_DST_UNREACHABLE;
+            if (!vmkernel) {
+               return VMCI_ERROR_DST_UNREACHABLE;
+            }
          }
 
          /* Pass it up to the guest. */
index fc262e072b72bb4cab165f26662c7828581c2276..a51bef89e665f366636662f154e9c3f200e18df2 100644 (file)
@@ -1886,13 +1886,15 @@ VMCIReleasePages(struct page **pages,  // IN
  */
 
 int
-VMCIHost_RegisterUserMemory(QueuePairPageStore *pageStore,  // IN
+VMCIHost_RegisterUserMemory(unsigned int index,             // IN
+                            QueuePairPageStore *pageStore,  // IN
                             VMCIQueue *produceQ,            // OUT
                             VMCIQueue *consumeQ)            // OUT
 {
    VA64 produceUVA;
    VA64 consumeUVA;
 
+   ASSERT(index == 0);
    ASSERT(produceQ->kernelIf->headerPage && consumeQ->kernelIf->headerPage);
 
    /*
@@ -1903,7 +1905,7 @@ VMCIHost_RegisterUserMemory(QueuePairPageStore *pageStore,  // IN
 
    produceUVA = pageStore->pages;
    consumeUVA = pageStore->pages + produceQ->kernelIf->numPages * PAGE_SIZE;
-   return VMCIHost_GetUserMemory(produceUVA, consumeUVA, produceQ, consumeQ);
+   return VMCIHost_GetUserMemory(index, produceUVA, consumeUVA, produceQ, consumeQ);
 }
 
 
@@ -1926,9 +1928,11 @@ VMCIHost_RegisterUserMemory(QueuePairPageStore *pageStore,  // IN
  */
 
 void
-VMCIHost_UnregisterUserMemory(VMCIQueue *produceQ,         // IN/OUT
+VMCIHost_UnregisterUserMemory(unsigned int index,          // IN
+                              VMCIQueue *produceQ,         // IN/OUT
                               VMCIQueue *consumeQ)         // IN/OUT
 {
+   ASSERT(index == 0);
    ASSERT(produceQ->kernelIf);
    ASSERT(consumeQ->kernelIf);
    ASSERT(!produceQ->qHeader && !consumeQ->qHeader);
@@ -1963,12 +1967,14 @@ VMCIHost_UnregisterUserMemory(VMCIQueue *produceQ,         // IN/OUT
  */
 
 int
-VMCIHost_MapQueues(VMCIQueue *produceQ,  // IN/OUT
+VMCIHost_MapQueues(unsigned int index,   // IN
+                   VMCIQueue *produceQ,  // IN/OUT
                    VMCIQueue *consumeQ,  // IN/OUT
                    uint32 flags)         // UNUSED
 {
    int result;
 
+   ASSERT(index == 0);
    if (!produceQ->qHeader || !consumeQ->qHeader) {
       struct page *headers[2];
 
@@ -2020,10 +2026,12 @@ VMCIHost_MapQueues(VMCIQueue *produceQ,  // IN/OUT
  */
 
 int
-VMCIHost_UnmapQueues(VMCIGuestMemID gid,   // IN
+VMCIHost_UnmapQueues(unsigned int index,   // IN
+                     VMCIGuestMemID gid,   // IN
                      VMCIQueue *produceQ,  // IN/OUT
                      VMCIQueue *consumeQ)  // IN/OUT
 {
+   ASSERT(index == 0);
    if (produceQ->qHeader) {
       ASSERT(consumeQ->qHeader);
 
@@ -2060,7 +2068,8 @@ VMCIHost_UnmapQueues(VMCIGuestMemID gid,   // IN
  */
 
 int
-VMCIHost_GetUserMemory(VA64 produceUVA,       // IN
+VMCIHost_GetUserMemory(unsigned int index,    // IN
+                       VA64 produceUVA,       // IN
                        VA64 consumeUVA,       // IN
                        VMCIQueue *produceQ,   // OUT
                        VMCIQueue *consumeQ)   // OUT
@@ -2068,6 +2077,7 @@ VMCIHost_GetUserMemory(VA64 produceUVA,       // IN
    int retval;
    int err = VMCI_SUCCESS;
 
+   ASSERT(index == 0);
    down_write(&current->mm->mmap_sem);
    retval = get_user_pages(current,
                            current->mm,
@@ -2123,12 +2133,14 @@ out:
  */
 
 void
-VMCIHost_ReleaseUserMemory(VMCIQueue *produceQ,  // IN/OUT
+VMCIHost_ReleaseUserMemory(unsigned int index,   // IN
+                           VMCIQueue *produceQ,  // IN/OUT
                            VMCIQueue *consumeQ)  // IN/OUT
 {
+   ASSERT(index == 0);
    ASSERT(produceQ->kernelIf->headerPage);
 
-   VMCIHost_UnregisterUserMemory(produceQ, consumeQ);
+   VMCIHost_UnregisterUserMemory(index, produceQ, consumeQ);
 }
 
 
index 7a5a9ef40aec6fa8383c7547023f9e258a550a56..d8380db2a33cc4a830e7c3dd92e1da557f269b68 100644 (file)
@@ -25,8 +25,8 @@
 #ifndef _VMCI_VERSION_H_
 #define _VMCI_VERSION_H_
 
-#define VMCI_DRIVER_VERSION          9.5.8.0
-#define VMCI_DRIVER_VERSION_COMMAS   9,5,8,0
-#define VMCI_DRIVER_VERSION_STRING   "9.5.8.0"
+#define VMCI_DRIVER_VERSION          9.5.9.0
+#define VMCI_DRIVER_VERSION_COMMAS   9,5,9,0
+#define VMCI_DRIVER_VERSION_STRING   "9.5.9.0"
 
 #endif /* _VMCI_VERSION_H_ */
index 6963dbaf873f0db1a2a41d8dd4367a8d8a236e06..dfce5b8992cac67ec1671986f57098efa84aa2db 100644 (file)
@@ -89,9 +89,6 @@
 #define VMNET_CAP_TSO6_EXT_HDRS      0x20000000  /* support TSO for ip6 ext hdrs */
 #define VMNET_CAP_SCHED              0x40000000  /* compliant with network scheduling */
 #define VMNET_CAP_SRIOV              0x80000000  /* Supports SR-IOV */
-#ifdef VMKTCPIP_RSS
-#define VMNET_CAP_RSS                0x100000000UL   /* support RSS FIXME get a 32 flag */
-#endif
 
 #define VMNET_CAP_SG_TX              VMNET_CAP_SG
 #define VMNET_CAP_SG_RX              0x200000000UL    /* Scatter-gather receive capability */
index de9782feb433c9a006d2ba95ce1f09304b9eb9b9..92f26ebc2246b1ea3b03d9609af4f984bb9cfd78 100644 (file)
 #endif
 
 /*
- * Only support Linux and Windows right now.
+ * Only support Linux right now.
+ *
+ * On Windows, the SAML impersonation story is too shaky to trust,
+ * and without that, there's no reason to support AliasManager APIs.
+ *
  * No support for open-vm-tools.
  */
-#if (defined(_WIN32) || defined(linux)) && !defined(OPEN_VM_TOOLS)
+#if defined(linux) && !defined(OPEN_VM_TOOLS)
 #define SUPPORT_VGAUTH 1
 #else
 #define SUPPORT_VGAUTH 0
 static gboolean gSupportVGAuth = USE_VGAUTH_DEFAULT;
 static gboolean QueryVGAuthConfig(GKeyFile *confDictRef);
 
+/*
+ * XXX
+ *
+ * Holds the current impersonation token.
+ *
+ * This is a hack, dependent on there only being one impersonation
+ * possible at a time anyways.  We need the HANDLE from inside the
+ * VGAuthUserHandle to pass to other functions, so we can't throw
+ * it out until Unimpersonate().
+ *
+ * A cleaner solution would be to not treat the userToken as a void *
+ * (which is really a HANDLE on Windows) but instead make a small wrapper
+ * struct containing a type and an optional HANDLE.  But this would
+ * require massive changes all over, and make it very hard to turn off
+ * VGAuth compilation.
+ */
+
+static VGAuthUserHandle *currentUserHandle = NULL;
+
 #endif
 
 
@@ -7577,9 +7600,13 @@ abort:
 void
 VixToolsUnimpersonateUser(void *userToken)
 {
-   if (VGAUTH_GENERIC_USER_TOKEN == userToken) {
+#if SUPPORT_VGAUTH
+   if (NULL != currentUserHandle) {
       GuestAuthUnimpersonate();
-   } else if (PROCESS_CREATOR_USER_TOKEN != userToken) {
+      return;
+   }
+#endif
+   if (PROCESS_CREATOR_USER_TOKEN != userToken) {
 #if defined(_WIN32)
       Impersonate_Undo();
 #else
@@ -7606,10 +7633,21 @@ VixToolsUnimpersonateUser(void *userToken)
 void
 VixToolsLogoutUser(void *userToken)    // IN
 {
-   if (PROCESS_CREATOR_USER_TOKEN == userToken ||
-       VGAUTH_GENERIC_USER_TOKEN == userToken) {
+   if (PROCESS_CREATOR_USER_TOKEN == userToken) {
+      return;
+   }
+
+#if SUPPORT_VGAUTH
+   if (NULL != currentUserHandle) {
+#ifdef _WIN32
+      // close the handle we copied out
+      CloseHandle((HANDLE) userToken);
+#endif
+      VGAuth_UserHandleFree(currentUserHandle);
+      currentUserHandle = NULL;
       return;
    }
+#endif
 
    if (NULL != userToken) {
       AuthToken authToken = (AuthToken) userToken;
@@ -7639,6 +7677,21 @@ VixToolsGetImpersonatedUsername(void *userToken)
    char *userName = NULL;
    char *homeDir = NULL;
 
+#if SUPPORT_VGAUTH
+   if (NULL != currentUserHandle) {
+      VGAuthContext *ctx;
+      VGAuthError vgErr = TheVGAuthContext(&ctx);
+      ASSERT(vgErr == VGAUTH_E_OK);
+
+      vgErr = VGAuth_UserHandleUsername(ctx, currentUserHandle, &userName);
+      if (VGAUTH_FAILED(vgErr)) {
+         Warning("%s: Unable to get username from userhandle %p\n",
+                 __FUNCTION__, currentUserHandle);
+      }
+      return userName;
+   }
+#endif
+
    if (!ProcMgr_GetImpersonatedUserInfo(&userName, &homeDir)) {
       return Util_SafeStrdup("XXX failed to get username XXX");
    }
@@ -9241,6 +9294,12 @@ VixToolsListMappedAliases(VixCommandRequestHeader *requestMsg, // IN
       goto abort;
    }
 
+   vgErr = VGAuth_QueryMappedAliases(ctx, 0, NULL, &num, &maList);
+   if (VGAUTH_FAILED(vgErr)) {
+      err = VixToolsTranslateVGAuthError(vgErr);
+      goto abort;
+   }
+
    endDestPtr = resultBuffer + maxBufferSize;
    destPtr += Str_Sprintf(destPtr, endDestPtr - destPtr, "%s",
                           VIX_XML_ESCAPED_TAG);
@@ -10819,6 +10878,7 @@ GuestAuthPasswordAuthenticateImpersonate(
    VGAuthError vgErr;
    VGAuthUserHandle *newHandle = NULL;
 
+   Debug(">%s\n", __FUNCTION__);
    err = VixMsg_DeObfuscateNamePassword(obfuscatedNamePassword,
                                         &username,
                                         &password);
@@ -10848,15 +10908,22 @@ GuestAuthPasswordAuthenticateImpersonate(
       goto done;
    }
 
-   *userToken = VGAUTH_GENERIC_USER_TOKEN;
+#ifdef _WIN32
+   // this is making a copy of the token, be sure to close it
+   err = VGAuth_UserHandleAccessToken(ctx, newHandle, userToken);
+   if (VGAUTH_FAILED(vgErr)) {
+      err = VixToolsTranslateVGAuthError(vgErr);
+      goto done;
+   }
+#endif
+
+   currentUserHandle = newHandle;
 
    err = VIX_OK;
 
 done:
 
-   if (newHandle) {
-      VGAuth_UserHandleFree(newHandle);
-   }
+   Debug("<%s\n", __FUNCTION__);
 
    return err;
 #else
@@ -10928,16 +10995,22 @@ GuestAuthSAMLAuthenticateAndImpersonate(
       goto done;
    }
 
-   *userToken = VGAUTH_GENERIC_USER_TOKEN;
+#ifdef _WIN32
+   // this is making a copy of the token, be sure to close it
+   err = VGAuth_UserHandleAccessToken(ctx, newHandle, userToken);
+   if (VGAUTH_FAILED(vgErr)) {
+      err = VixToolsTranslateVGAuthError(vgErr);
+      goto done;
+   }
+#endif
+
+   currentUserHandle = newHandle;
+
 
    err = VIX_OK;
 
 done:
 
-   if (newHandle) {
-      VGAuth_UserHandleFree(newHandle);
-   }
-
    Debug("<%s\n", __FUNCTION__);
 
    return err;
@@ -10973,6 +11046,7 @@ GuestAuthUnimpersonate(void)
 
    vgErr = VGAuth_EndImpersonation(ctx);
    ASSERT(vgErr == VGAUTH_E_OK);
+
 #else
    ASSERT(0);
 #endif
index 5b37c5c897111eb27eccbd8760da4e0020fd7eb8..1de5f74cac3d6e48ba14f261e3e2aa9577e18d16 100644 (file)
@@ -33,7 +33,6 @@
 
 
 #define PROCESS_CREATOR_USER_TOKEN       ((void *)1)
-#define VGAUTH_GENERIC_USER_TOKEN        ((void *)2)
 
 #ifdef _WIN32