From: VMware, Inc <> Date: Mon, 15 Oct 2012 04:54:51 +0000 (-0700) Subject: Internal branch sync. Included in this change: X-Git-Tag: 2012.10.14-874563~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=20a0df267524ef95704c99a3131443a82e7b7a95;p=thirdparty%2Fopen-vm-tools.git Internal branch sync. Included in this change: . 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 --- diff --git a/open-vm-tools/lib/include/guestStats.h b/open-vm-tools/lib/include/guestStats.h index 11523c342..356a10289 100644 --- a/open-vm-tools/lib/include/guestStats.h +++ b/open-vm-tools/lib/include/guestStats.h @@ -30,6 +30,8 @@ #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" +#include "vm_basic_types.h" + typedef #include "vmware_pack_begin.h" struct GuestMemInfo { diff --git a/open-vm-tools/lib/include/vix.h b/open-vm-tools/lib/include/vix.h index 47d862d2a..f396d65ad 100644 --- a/open-vm-tools/lib/include/vix.h +++ b/open-vm-tools/lib/include/vix.h @@ -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, diff --git a/open-vm-tools/lib/include/vm_version.h b/open-vm-tools/lib/include/vm_version.h index 84f442fdb..f5a59f33a 100644 --- a/open-vm-tools/lib/include/vm_version.h +++ b/open-vm-tools/lib/include/vm_version.h @@ -375,6 +375,8 @@ * 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 "" @@ -390,7 +392,7 @@ # 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 diff --git a/open-vm-tools/lib/include/vmci_defs.h b/open-vm-tools/lib/include/vmci_defs.h index 48595d9cc..591d7081c 100644 --- a/open-vm-tools/lib/include/vmci_defs.h +++ b/open-vm-tools/lib/include/vmci_defs.h @@ -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 diff --git a/open-vm-tools/lib/include/vmware/tools/utils.h b/open-vm-tools/lib/include/vmware/tools/utils.h index 8ad9bcb10..13a5e3d84 100644 --- a/open-vm-tools/lib/include/vmware/tools/utils.h +++ b/open-vm-tools/lib/include/vmware/tools/utils.h @@ -131,6 +131,9 @@ typedef gboolean (*SignalSourceCb)(const siginfo_t *, gpointer); GSource * VMTools_NewSignalSource(int signum); +gchar * +VMTools_GetLibdir(void); + #endif GSource * diff --git a/open-vm-tools/modules/linux/shared/vmci_defs.h b/open-vm-tools/modules/linux/shared/vmci_defs.h index 6984fd165..0379f29c2 100644 --- a/open-vm-tools/modules/linux/shared/vmci_defs.h +++ b/open-vm-tools/modules/linux/shared/vmci_defs.h @@ -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 diff --git a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h index 0fe0d20fb..2993c77f4 100644 --- a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h +++ b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h @@ -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) diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.c b/open-vm-tools/modules/linux/vmci/common/vmciContext.c index bace03d92..0e05de5e0 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciContext.c @@ -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)); diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c b/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c index d0fe015fd..6c59e6a7b 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c @@ -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; } } diff --git a/open-vm-tools/modules/linux/vmci/common/vmciQPair.c b/open-vm-tools/modules/linux/vmci/common/vmciQPair.c index a3d612f9d..82d66ba8a 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciQPair.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciQPair.c @@ -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; } diff --git a/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c b/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c index 8fac7d810..6d0fc7e6c 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c @@ -59,24 +59,24 @@ * -------------- 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 @@ -84,57 +84,51 @@ * 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); diff --git a/open-vm-tools/modules/linux/vmci/common/vmciRoute.c b/open-vm-tools/modules/linux/vmci/common/vmciRoute.c index 2282d63e2..81c9d077c 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciRoute.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciRoute.c @@ -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. */ diff --git a/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c b/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c index fc262e072..a51bef89e 100644 --- a/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c +++ b/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c @@ -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(¤t->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); } diff --git a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h index 7a5a9ef40..d8380db2a 100644 --- a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h +++ b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h @@ -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_ */ diff --git a/open-vm-tools/modules/shared/vmxnet/vmnet_def.h b/open-vm-tools/modules/shared/vmxnet/vmnet_def.h index 6963dbaf8..dfce5b899 100644 --- a/open-vm-tools/modules/shared/vmxnet/vmnet_def.h +++ b/open-vm-tools/modules/shared/vmxnet/vmnet_def.h @@ -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 */ diff --git a/open-vm-tools/services/plugins/vix/vixTools.c b/open-vm-tools/services/plugins/vix/vixTools.c index de9782feb..92f26ebc2 100644 --- a/open-vm-tools/services/plugins/vix/vixTools.c +++ b/open-vm-tools/services/plugins/vix/vixTools.c @@ -120,10 +120,14 @@ #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 @@ -148,6 +152,25 @@ 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 diff --git a/open-vm-tools/services/plugins/vix/vixToolsInt.h b/open-vm-tools/services/plugins/vix/vixToolsInt.h index 5b37c5c89..1de5f74ca 100644 --- a/open-vm-tools/services/plugins/vix/vixToolsInt.h +++ b/open-vm-tools/services/plugins/vix/vixToolsInt.h @@ -33,7 +33,6 @@ #define PROCESS_CREATOR_USER_TOKEN ((void *)1) -#define VGAUTH_GENERIC_USER_TOKEN ((void *)2) #ifdef _WIN32