From: VMware, Inc <> Date: Tue, 29 Mar 2011 18:45:42 +0000 (-0700) Subject: This is part 11 of a change to support Nested VMs. X-Git-Tag: 2011.03.28-387002~92 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=55e3133345e97d05d9d5d99e6e975ab3f3567cec;p=thirdparty%2Fopen-vm-tools.git This is part 11 of a change to support Nested VMs. This unifies the doorbell code. We use the host doorbell code, with resources and contexts, for both drivers. The decision about where to deliver a doorbell is made using the routing code that was added with the datagram unification. The majority of the changes are in vmciDoorbell.c. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/modules/linux/vmci/stubs.c b/open-vm-tools/modules/linux/vmci/stubs.c index fec98ab2f..c2da3e195 100644 --- a/open-vm-tools/modules/linux/vmci/stubs.c +++ b/open-vm-tools/modules/linux/vmci/stubs.c @@ -93,48 +93,6 @@ VMCIQPBroker_Detach(VMCIHandle handle, } -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellHostContextNotify -- - * - * Stub. Not called in the guest driver (yet). - * - * Result: - * Always VMCI_ERROR_GENERIC. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDoorbellHostContextNotify(VMCIId srcCID, - VMCIHandle handle) -{ - return VMCI_ERROR_GENERIC; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellGetPrivFlags -- - * - * Stub. Not called in the guest driver (yet). - * - * Result: - * Always VMCI_ERROR_GENERIC. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDoorbellGetPrivFlags(VMCIHandle handle, - VMCIPrivilegeFlags *privFlags) -{ - return VMCI_ERROR_GENERIC; -} - - /* *------------------------------------------------------------------------------ * diff --git a/open-vm-tools/modules/linux/vmci/vmciDatagram.c b/open-vm-tools/modules/linux/vmci/vmciDatagram.c index aacf0d751..641e4476b 100644 --- a/open-vm-tools/modules/linux/vmci/vmciDatagram.c +++ b/open-vm-tools/modules/linux/vmci/vmciDatagram.c @@ -559,11 +559,11 @@ VMCIDatagramDelayedDispatchCB(void *data) // IN /* *------------------------------------------------------------------------------ * - * VMCIDatagramDispatchFromHostToSelfOrGuest -- + * VMCIDatagramDispatchAsHost -- * - * Dispatch datagram to host or other vm context. This function cannot - * dispatch to hypervisor context handlers. This should have been handled - * before we get here by VMCIDatagramDispatch. + * Dispatch datagram as a host, to the host or other vm context. This + * function cannot dispatch to hypervisor context handlers. This should + * have been handled before we get here by VMCIDatagramDispatch. * * Result: * Number of bytes sent on success, appropriate error code otherwise. @@ -575,8 +575,8 @@ VMCIDatagramDelayedDispatchCB(void *data) // IN */ static int -VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID, // IN: - VMCIDatagram *dg) // IN: +VMCIDatagramDispatchAsHost(VMCIId contextID, // IN: + VMCIDatagram *dg) // IN: { int retval; size_t dgSize; @@ -586,6 +586,7 @@ VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID, // IN: char dstDomain[VMCI_DOMAIN_NAME_MAXLEN]; /* Not used on hosted. */ ASSERT(dg); + ASSERT(VMCI_HasHostDevice()); dgSize = VMCI_DG_SIZE(dg); @@ -804,9 +805,10 @@ VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID, // IN: /* *------------------------------------------------------------------------------ * - * VMCIDatagramDispatchFromGuestToHost -- + * VMCIDatagramDispatchAsGuest -- * - * Dispatch datagram down through the VMX, and potentially to the host. + * Dispatch datagram as a guest, down through the VMX and potentially to + * the host. * * Result: * Number of bytes sent on success, appropriate error code otherwise. @@ -818,7 +820,7 @@ VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID, // IN: */ static int -VMCIDatagramDispatchFromGuestToHost(VMCIDatagram *dg) +VMCIDatagramDispatchAsGuest(VMCIDatagram *dg) { #if defined(VMKERNEL) VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); @@ -828,6 +830,8 @@ VMCIDatagramDispatchFromGuestToHost(VMCIDatagram *dg) VMCIResource *resource; extern int VMCI_SendDatagram(VMCIDatagram *); + ASSERT(VMCI_HasGuestDevice()); + resource = VMCIResource_Get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM); if (NULL == resource) { return VMCI_ERROR_NO_HANDLE; @@ -880,17 +884,15 @@ VMCIDatagram_Dispatch(VMCIId contextID, return retval; } - if (VMCI_ROUTE_HOST_TO_SELF == route || - VMCI_ROUTE_HOST_TO_GUEST == route) { + if (VMCI_ROUTE_AS_HOST == route) { if (VMCI_INVALID_ID == contextID) { contextID = VMCI_HOST_CONTEXT_ID; } - return VMCIDatagramDispatchFromHostToSelfOrGuest(contextID, dg); + return VMCIDatagramDispatchAsHost(contextID, dg); } - if (VMCI_ROUTE_GUEST_TO_HOST == route || - VMCI_ROUTE_GUEST_TO_HYPERVISOR == route) { - return VMCIDatagramDispatchFromGuestToHost(dg); + if (VMCI_ROUTE_AS_GUEST == route) { + return VMCIDatagramDispatchAsGuest(dg); } VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route)); @@ -928,6 +930,7 @@ VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN DatagramEntry *dstEntry; ASSERT(dg); + ASSERT(VMCI_HasGuestDevice()); resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM); if (NULL == resource) { diff --git a/open-vm-tools/modules/linux/vmci/vmciDatagram.h b/open-vm-tools/modules/linux/vmci/vmciDatagram.h index 2bae0d8ca..48436145e 100644 --- a/open-vm-tools/modules/linux/vmci/vmciDatagram.h +++ b/open-vm-tools/modules/linux/vmci/vmciDatagram.h @@ -43,7 +43,6 @@ int VMCIDatagram_Init(void); void VMCIDatagram_Exit(void); - /* Datagram API for non-public use. */ int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *dg, Bool fromGuest); int VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg); diff --git a/open-vm-tools/modules/linux/vmci/vmciDoorbell.c b/open-vm-tools/modules/linux/vmci/vmciDoorbell.c new file mode 100644 index 000000000..f2e2c95ba --- /dev/null +++ b/open-vm-tools/modules/linux/vmci/vmciDoorbell.c @@ -0,0 +1,1215 @@ +/********************************************************* + * Copyright (C) 2010 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vmciDoorbell.c -- + * + * This file implements the VMCI doorbell API on the host. + */ + +#if defined(__linux__) && !defined(VMKERNEL) +# include "driver-config.h" +# include "compat_kernel.h" +# include "compat_module.h" +#endif // __linux__ +#include "vmci_kernel_if.h" +#include "vm_assert.h" +#include "vmci_defs.h" +#include "vmci_infrastructure.h" +#include "vmciCommonInt.h" +#include "vmciDatagram.h" +#include "vmciDoorbell.h" +#include "vmciKernelAPI.h" +#include "vmciResource.h" +#include "vmciRoute.h" +#ifdef VMX86_TOOLS +# include "vmciInt.h" +# include "vmciUtil.h" +#elif defined(VMKERNEL) +# include "vmciVmkInt.h" +# include "vm_libc.h" +# include "helper_ext.h" +# include "vmciDriver.h" +#else +# include "vmciDriver.h" +#endif + +#define LGPFX "VMCIDoorbell: " + +#if !defined(SOLARIS) && !defined(__APPLE__) + +#if defined(VMKERNEL) + /* VMK doesn't need BH locks, so use lower ranks. */ +# define VMCIDoorbellInitLock(_l, _n) \ + VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGHER) +# define VMCIDoorbellGrabLock(_l, _f) VMCI_GrabLock(_l, _f) +# define VMCIDoorbellReleaseLock(_l, _f) VMCI_ReleaseLock(_l, _f) +#else // VMKERNEL +# define VMCIDoorbellInitLock(_l, _n) \ + VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_MIDDLE_BH) +# define VMCIDoorbellGrabLock(_l, _f) VMCI_GrabLock_BH(_l, _f) +# define VMCIDoorbellReleaseLock(_l, _f) VMCI_ReleaseLock_BH(_l, _f) +#endif // VMKERNEL + +#define VMCI_DOORBELL_INDEX_TABLE_SIZE 64 +#define VMCI_DOORBELL_HASH(_idx) \ + VMCI_HashId((_idx), VMCI_DOORBELL_INDEX_TABLE_SIZE) + + +/* + * DoorbellEntry describes the a doorbell notification handle allocated by the + * host. + */ + +typedef struct VMCIDoorbellEntry { + VMCIResource resource; + uint32 idx; + VMCIListItem idxListItem; + VMCIPrivilegeFlags privFlags; + Bool isDoorbell; + Bool runDelayed; + VMCICallback notifyCB; + void *clientData; + VMCIEvent destroyEvent; +} VMCIDoorbellEntry; + +typedef struct VMCIDoorbellIndexTable { + VMCILock lock; + VMCIList entries[VMCI_DOORBELL_INDEX_TABLE_SIZE]; +} VMCIDoorbellIndexTable; + + +/* The VMCI index table keeps track of currently registered doorbells. */ +static VMCIDoorbellIndexTable vmciDoorbellIT; + + +/* + * The maxNotifyIdx is one larger than the currently known bitmap index in + * use, and is used to determine how much of the bitmap needs to be scanned. + */ + +static uint32 maxNotifyIdx; + +/* + * The notifyIdxCount is used for determining whether there are free entries + * within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx). + */ + +static uint32 notifyIdxCount; + +/* + * The lastNotifyIdxReserved is used to track the last index handed out - in + * the case where multiple handles share a notification index, we hand out + * indexes round robin based on lastNotifyIdxReserved. + */ + +static uint32 lastNotifyIdxReserved; + +/* This is a one entry cache used to by the index allocation. */ +static uint32 lastNotifyIdxReleased = PAGE_SIZE; + + +static void VMCIDoorbellFreeCB(void *clientData); +static int VMCIDoorbellReleaseCB(void *clientData); +static void VMCIDoorbellDelayedDispatchCB(void *data); +extern int VMCI_SendDatagram(VMCIDatagram *); + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Init -- + * + * General init code. + * + * Result: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +void +VMCIDoorbell_Init(void) +{ + uint32 bucket; + + for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); ++bucket) { + VMCIList_Init(&vmciDoorbellIT.entries[bucket]); + } + + VMCIDoorbellInitLock(&vmciDoorbellIT.lock, "VMCIDoorbellIndexTableLock"); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Exit -- + * + * General init code. + * + * Result: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +void +VMCIDoorbell_Exit(void) +{ + VMCI_CleanupLock(&vmciDoorbellIT.lock); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellFreeCB -- + * + * Callback to free doorbell entry structure when resource is no longer used, + * ie. the reference count reached 0. The entry is freed in + * VMCIDoorbell_Destroy(), which is waiting on the signal that gets fired + * here. + * + * Result: + * None. + * + * Side effects: + * Signals VMCI event. + * + *------------------------------------------------------------------------------ + */ + +static void +VMCIDoorbellFreeCB(void *clientData) // IN +{ + VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData; + ASSERT(entry); + VMCI_SignalEvent(&entry->destroyEvent); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellReleaseCB -- + * + * Callback to release the resource reference. It is called by the + * VMCI_WaitOnEvent function before it blocks. + * + * Result: + * Always 0. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +static int +VMCIDoorbellReleaseCB(void *clientData) // IN: doorbell entry +{ + VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData; + ASSERT(entry); + VMCIResource_Release(&entry->resource); + return 0; +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellGetPrivFlags -- + * + * Utility function that retrieves the privilege flags associated + * with a given doorbell handle. For guest endpoints, the + * privileges are determined by the context ID, but for host + * endpoints privileges are associated with the complete + * handle. Hypervisor endpoints are not yet supported. + * + * Result: + * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +int +VMCIDoorbellGetPrivFlags(VMCIHandle handle, // IN + VMCIPrivilegeFlags *privFlags) // OUT +{ + if (privFlags == NULL || handle.context == VMCI_INVALID_ID) { + return VMCI_ERROR_INVALID_ARGS; + } + + if (handle.context == VMCI_HOST_CONTEXT_ID) { + VMCIDoorbellEntry *entry; + VMCIResource *resource; + + resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL); + if (resource == NULL) { + return VMCI_ERROR_INVALID_ARGS; + } + entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource); + *privFlags = entry->privFlags; + VMCIResource_Release(resource); + } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) { + /* Hypervisor endpoints for notifications are not supported (yet). */ + return VMCI_ERROR_INVALID_ARGS; + } else { + *privFlags = VMCIContext_GetPrivFlags(handle.context); + } + + return VMCI_SUCCESS; +} + + +/* + *----------------------------------------------------------------------------- + * + * VMCIDoorbellIndexTableFind -- + * + * Find doorbell entry by bitmap index. + * + * Results: + * Entry if found, NULL if not. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static VMCIDoorbellEntry * +VMCIDoorbellIndexTableFind(uint32 idx) // IN +{ + uint32 bucket = VMCI_DOORBELL_HASH(idx); + VMCIListItem *iter; + + ASSERT(VMCI_HasGuestDevice()); + + VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) { + VMCIDoorbellEntry *cur = + VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem); + + ASSERT(cur); + + if (idx == cur->idx) { + return cur; + } + } + + return NULL; +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellIndexTableAdd -- + * + * Add the given entry to the index table. This will hold() the entry's + * resource so that the entry is not deleted before it is removed from the + * table. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +static void +VMCIDoorbellIndexTableAdd(VMCIDoorbellEntry *entry) // IN/OUT +{ + uint32 bucket; + uint32 newNotifyIdx; + VMCILockFlags flags; + + ASSERT(entry); + ASSERT(VMCI_HasGuestDevice()); + + VMCIResource_Hold(&entry->resource); + + VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags); + + /* + * Below we try to allocate an index in the notification bitmap with "not + * too much" sharing between resources. If we use less that the full bitmap, + * we either add to the end if there are no unused flags within the + * currently used area, or we search for unused ones. If we use the full + * bitmap, we allocate the index round robin. + */ + + if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) { + if (lastNotifyIdxReleased < maxNotifyIdx && + !VMCIDoorbellIndexTableFind(lastNotifyIdxReleased)) { + newNotifyIdx = lastNotifyIdxReleased; + lastNotifyIdxReleased = PAGE_SIZE; + } else { + Bool reused = FALSE; + newNotifyIdx = lastNotifyIdxReserved; + if (notifyIdxCount + 1 < maxNotifyIdx) { + do { + if (!VMCIDoorbellIndexTableFind(newNotifyIdx)) { + reused = TRUE; + break; + } + newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx; + } while(newNotifyIdx != lastNotifyIdxReleased); + } + if (!reused) { + newNotifyIdx = maxNotifyIdx; + maxNotifyIdx++; + } + } + } else { + newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE; + } + lastNotifyIdxReserved = newNotifyIdx; + notifyIdxCount++; + + entry->idx = newNotifyIdx; + bucket = VMCI_DOORBELL_HASH(entry->idx); + VMCIList_Insert(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]); + + VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellIndexTableRemove -- + * + * Remove the given entry from the index table. This will release() the + * entry's resource. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +static void +VMCIDoorbellIndexTableRemove(VMCIDoorbellEntry *entry) // IN/OUT +{ + uint32 bucket; + VMCILockFlags flags; + + ASSERT(entry); + ASSERT(VMCI_HasGuestDevice()); + + VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags); + + bucket = VMCI_DOORBELL_HASH(entry->idx); + VMCIList_Remove(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]); + + notifyIdxCount--; + if (entry->idx == maxNotifyIdx - 1) { + /* + * If we delete an entry with the maximum known notification index, we + * take the opportunity to prune the current max. As there might be other + * unused indices immediately below, we lower the maximum until we hit an + * index in use. + */ + + while (maxNotifyIdx > 0 && + !VMCIDoorbellIndexTableFind(maxNotifyIdx - 1)) { + maxNotifyIdx--; + } + } + lastNotifyIdxReleased = entry->idx; + + VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags); + + VMCIResource_Release(&entry->resource); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellLink -- + * + * Creates a link between the given doorbell handle and the given + * index in the bitmap in the device backend. + * + * Results: + * VMCI_SUCCESS if success, appropriate error code otherwise. + * + * Side effects: + * Notification state is created in hypervisor. + * + *------------------------------------------------------------------------------ + */ + +static int +VMCIDoorbellLink(VMCIHandle handle, // IN + Bool isDoorbell, // IN + uint32 notifyIdx) // IN +{ +#if defined(VMKERNEL) + VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); + return VMCI_ERROR_DST_UNREACHABLE; +#else // VMKERNEL + VMCIId resourceID; + VMCIDoorbellLinkMsg linkMsg; + + ASSERT(!VMCI_HANDLE_INVALID(handle)); + ASSERT(VMCI_HasGuestDevice()); + + if (isDoorbell) { + resourceID = VMCI_DOORBELL_LINK; + } else { + ASSERT(FALSE); + return VMCI_ERROR_UNAVAILABLE; + } + + linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID); + linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; + linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE; + linkMsg.handle = handle; + linkMsg.notifyIdx = notifyIdx; + + return VMCI_SendDatagram((VMCIDatagram *)&linkMsg); +#endif // VMKERNEL +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellUnlink -- + * + * Unlinks the given doorbell handle from an index in the bitmap in + * the device backend. + * + * Results: + * VMCI_SUCCESS if success, appropriate error code otherwise. + * + * Side effects: + * Notification state is destroyed in hypervisor. + * + *------------------------------------------------------------------------------ + */ + +static int +VMCIDoorbellUnlink(VMCIHandle handle, // IN + Bool isDoorbell) // IN +{ +#if defined(VMKERNEL) + VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); + return VMCI_ERROR_DST_UNREACHABLE; +#else // VMKERNEL + VMCIId resourceID; + VMCIDoorbellUnlinkMsg unlinkMsg; + + ASSERT(!VMCI_HANDLE_INVALID(handle)); + ASSERT(VMCI_HasGuestDevice()); + + if (isDoorbell) { + resourceID = VMCI_DOORBELL_UNLINK; + } else { + ASSERT(FALSE); + return VMCI_ERROR_UNAVAILABLE; + } + + unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID); + unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; + unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE; + unlinkMsg.handle = handle; + + return VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg); +#endif // VMKERNEL +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Create -- + * + * Creates a doorbell with the given callback. If the handle is + * VMCI_INVALID_HANDLE, a free handle will be assigned, if + * possible. The callback can be run immediately (potentially with + * locks held - the default) or delayed (in a kernel thread) by + * specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution + * is selected, a given callback may not be run if the kernel is + * unable to allocate memory for the delayed execution (highly + * unlikely). + * + * Results: + * VMCI_SUCCESS on success, appropriate error code otherwise. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create) +int +VMCIDoorbell_Create(VMCIHandle *handle, // IN/OUT + uint32 flags, // IN + VMCIPrivilegeFlags privFlags, // IN + VMCICallback notifyCB, // IN + void *clientData) // IN +{ + VMCIDoorbellEntry *entry; + VMCIHandle newHandle; + int result; + + if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB || + privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) { + return VMCI_ERROR_INVALID_ARGS; + } + + entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED); + if (entry == NULL) { + VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n")); + return VMCI_ERROR_NO_MEM; + } + + if (!VMCI_CanScheduleDelayedWork() && (flags & VMCI_FLAG_DELAYED_CB)) { + result = VMCI_ERROR_INVALID_ARGS; + goto freeMem; + } + + if (VMCI_HANDLE_INVALID(*handle)) { + VMCIId contextID = VMCI_GetContextID(); + VMCIId resourceID = VMCIResource_GetID(contextID); + if (resourceID == VMCI_INVALID_ID) { + result = VMCI_ERROR_NO_HANDLE; + goto freeMem; + } + newHandle = VMCI_MAKE_HANDLE(contextID, resourceID); + } else { + Bool validContext; + + /* + * Validate the handle. We must do both of the checks below because we + * can be acting as both a host and a guest at the same time. + */ + + validContext = FALSE; + if (VMCI_HasHostDevice() && VMCI_HOST_CONTEXT_ID == handle->context) { + validContext = TRUE; + } + if (VMCI_HasGuestDevice() && VMCI_GetContextID() == handle->context) { + validContext = TRUE; + } + + if (!validContext || VMCI_INVALID_ID == handle->resource) { + VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument (handle=0x%x:0x%x).\n", + handle->context, handle->resource)); + result = VMCI_ERROR_INVALID_ARGS; + goto freeMem; + } + + newHandle = *handle; + } + + entry->idx = 0; + VMCIList_Init(&entry->idxListItem); + entry->privFlags = privFlags; + entry->isDoorbell = TRUE; + entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE; + entry->notifyCB = notifyCB; + entry->clientData = clientData; + VMCI_CreateEvent(&entry->destroyEvent); + + result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DOORBELL, + newHandle, VMCIDoorbellFreeCB, entry); + if (result != VMCI_SUCCESS) { + VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n", + newHandle.context, newHandle.resource)); + goto destroy; + } + + if (VMCI_HasGuestDevice()) { + result = VMCIDoorbellLink(newHandle, entry->isDoorbell, entry->idx); + if (VMCI_SUCCESS != result) { + goto destroyResource; + } + VMCIDoorbellIndexTableAdd(entry); + } + + if (VMCI_HANDLE_INVALID(*handle)) { + *handle = newHandle; + } + + return result; + +destroyResource: + VMCIResource_Remove(newHandle, VMCI_RESOURCE_TYPE_DOORBELL); +destroy: + VMCI_DestroyEvent(&entry->destroyEvent); +freeMem: + VMCI_FreeKernelMem(entry, sizeof *entry); + return result; +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Destroy -- + * + * Destroys a doorbell previously created with + * VMCIDoorbell_Create. This operation may block waiting for a + * callback to finish. + * + * Results: + * VMCI_SUCCESS on success, appropriate error code otherwise. + * + * Side effects: + * May block. + * + *------------------------------------------------------------------------------ + */ + +VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy) +int +VMCIDoorbell_Destroy(VMCIHandle handle) // IN +{ + VMCIDoorbellEntry *entry; + VMCIResource *resource; + + if (VMCI_HANDLE_INVALID(handle)) { + return VMCI_ERROR_INVALID_ARGS; + } + + resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL); + if (resource == NULL) { + VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy doorbell (handle=0x%x:0x%x).\n", + handle.context, handle.resource)); + return VMCI_ERROR_NOT_FOUND; + } + entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource); + + if (VMCI_HasGuestDevice()) { + int result; + + VMCIDoorbellIndexTableRemove(entry); + + result = VMCIDoorbellUnlink(handle, entry->isDoorbell); + if (VMCI_SUCCESS != result) { + + /* + * The only reason this should fail would be an inconsistency between + * guest and hypervisor state, where the guest believes it has an + * active registration whereas the hypervisor doesn't. One case where + * this may happen is if a doorbell is unregistered following a + * hibernation at a time where the doorbell state hasn't been restored + * on the hypervisor side yet. Since the handle has now been removed + * in the guest, we just print a warning and return success. + */ + + VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by " + "hypervisor (error=%d).\n", + entry->isDoorbell ? "doorbell" : "queuepair", + handle.context, handle.resource, result)); + } + } + + /* + * Now remove the resource from the table. It might still be in use + * after this, in a callback or still on the delayed work queue. + */ + + VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DOORBELL); + + /* + * We now wait on the destroyEvent and release the reference we got + * above. + */ + + VMCI_WaitOnEvent(&entry->destroyEvent, VMCIDoorbellReleaseCB, entry); + + /* + * We know that we are now the only reference to the above entry so + * can safely free it. + */ + + VMCI_DestroyEvent(&entry->destroyEvent); + VMCI_FreeKernelMem(entry, sizeof *entry); + + return VMCI_SUCCESS; +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellNotifyAsGuest -- + * + * Notify another guest or the host. We send a datagram down to the + * host via the hypervisor with the notification info. + * + * Results: + * VMCI_SUCCESS on success, appropriate error code otherwise. + * + * Side effects: + * May do a hypercall. + * + *------------------------------------------------------------------------------ + */ + +static int +VMCIDoorbellNotifyAsGuest(VMCIHandle handle, // IN + VMCIPrivilegeFlags privFlags) // IN +{ +#if defined(VMKERNEL) + VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); + return VMCI_ERROR_DST_UNREACHABLE; +#else // VMKERNEL + VMCIDoorbellNotifyMsg notifyMsg; + + ASSERT(VMCI_HasGuestDevice()); + + notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, + VMCI_DOORBELL_NOTIFY); + notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE; + notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE; + notifyMsg.handle = handle; + + return VMCI_SendDatagram((VMCIDatagram *)¬ifyMsg); +#endif // VMKERNEL +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Notify -- + * + * Generates a notification on the doorbell identified by the + * handle. For host side generation of notifications, the caller + * can specify what the privilege of the calling side is. + * + * Results: + * VMCI_SUCCESS on success, appropriate error code otherwise. + * + * Side effects: + * May do a hypercall. + * + *------------------------------------------------------------------------------ + */ + +VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify) +int +VMCIDoorbell_Notify(VMCIHandle dst, // IN + VMCIPrivilegeFlags privFlags) // IN +{ + int retval; + VMCIRoute route; + VMCIHandle src; + + if (VMCI_HANDLE_INVALID(dst) || (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS)) { + return VMCI_ERROR_INVALID_ARGS; + } + + src = VMCI_INVALID_HANDLE; + retval = VMCI_Route(&src, &dst, FALSE, &route); + if (retval < VMCI_SUCCESS) { + return retval; + } + + if (VMCI_ROUTE_AS_HOST == route) { + return VMCIContext_NotifyDoorbell(VMCI_HOST_CONTEXT_ID, dst, privFlags); + } + + if (VMCI_ROUTE_AS_GUEST == route) { + return VMCIDoorbellNotifyAsGuest(dst, privFlags); + } + + VMCI_WARNING((LGPFX"Unknown route (%d) for doorbell.\n", route)); + return VMCI_ERROR_DST_UNREACHABLE; +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellDelayedDispatchCB -- + * + * Calls the specified callback in a delayed context. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +static void +VMCIDoorbellDelayedDispatchCB(void *data) // IN +{ + VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)data; + + ASSERT(data); + + entry->notifyCB(entry->clientData); + + VMCIResource_Release(&entry->resource); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbellHostContextNotify -- + * + * Dispatches a doorbell notification to the host context. + * + * Results: + * VMCI_SUCCESS on success. Appropriate error code otherwise. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +int +VMCIDoorbellHostContextNotify(VMCIId srcCID, // IN + VMCIHandle handle) // IN +{ + VMCIDoorbellEntry *entry; + VMCIResource *resource; + int result; + + ASSERT(VMCI_HasHostDevice()); + + resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL); + if (resource == NULL) { + VMCI_DEBUG_LOG(4, + (LGPFX"Notifying an invalid doorbell (handle=0x%x:0x%x).\n", + handle.context, handle.resource)); + return VMCI_ERROR_INVALID_ARGS; + } + entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource); + + if (entry->runDelayed) { + result = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, entry); + if (result < VMCI_SUCCESS) { + /* + * If we failed to schedule the delayed work, we need to + * release the resource immediately. Otherwise, the resource + * will be released once the delayed callback has been + * completed. + */ + + VMCI_DEBUG_LOG(10, (LGPFX"Failed to schedule delayed doorbell " + "notification (result=%d).\n", result)); + VMCIResource_Release(resource); + } + } else { + entry->notifyCB(entry->clientData); + VMCIResource_Release(resource); + result = VMCI_SUCCESS; + } + return result; +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Hibernate -- + * + * When a guest leaves hibernation, the device driver state is out of sync + * with the device state, since the driver state has doorbells registered + * that aren't known to the device. This function takes care of + * reregistering any doorbells. In case an error occurs during + * reregistration (this is highly unlikely since 1) it succeeded the first + * time 2) the device driver is the only source of doorbell registrations), + * we simply log the error. The doorbell can still be destroyed using + * VMCIDoorbell_Destroy. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +void +VMCIDoorbell_Hibernate(Bool enterHibernate) +{ + uint32 bucket; + VMCIListItem *iter; + VMCILockFlags flags; + + if (!VMCI_HasGuestDevice() || enterHibernate) { + return; + } + + VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags); + + for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); bucket++) { + VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) { + int result; + VMCIDoorbellEntry *cur; + + cur = VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem); + result = VMCIDoorbellLink(cur->resource.handle, cur->isDoorbell, + cur->idx); + if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) { + VMCI_WARNING((LGPFX"Failed to reregister doorbell " + "(handle=0x%x:0x%x) of resource %s to index " + "(error: %d).\n", + cur->resource.handle.context, + cur->resource.handle.resource, + cur->isDoorbell ? "doorbell" : "queue pair", result)); + } + } + } + + VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCIDoorbell_Sync -- + * + * Use this as a synchronization point when setting globals, for example, + * during device shutdown. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +void +VMCIDoorbell_Sync(void) +{ + VMCILockFlags flags; + VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags); + VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags); + VMCIResource_Sync(); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCI_RegisterNotificationBitmap -- + * + * Register the notification bitmap with the host. + * + * Results: + * TRUE if the bitmap is registered successfully with the device, FALSE + * otherwise. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +Bool +VMCI_RegisterNotificationBitmap(PPN bitmapPPN) +{ + int result; + VMCINotifyBitmapSetMsg bitmapSetMsg; + + /* + * Do not ASSERT() on the guest device here. This function can get called + * during device initialization, so the ASSERT() will fail even though + * the device is (almost) up. + */ + + bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, + VMCI_SET_NOTIFY_BITMAP); + bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE; + bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE; + bitmapSetMsg.bitmapPPN = bitmapPPN; + + result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg); + if (result != VMCI_SUCCESS) { + VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as " + "notification bitmap (error=%d).\n", + bitmapPPN, result)); + return FALSE; + } + return TRUE; +} + + +/* + *------------------------------------------------------------------------- + * + * VMCIDoorbellFireEntries -- + * + * Executes or schedules the handlers for a given notify index. + * + * Result: + * Notification hash entry if found. NULL otherwise. + * + * Side effects: + * Whatever the side effects of the handlers are. + * + *------------------------------------------------------------------------- + */ + +static void +VMCIDoorbellFireEntries(uint32 notifyIdx) // IN +{ + uint32 bucket = VMCI_DOORBELL_HASH(notifyIdx); + VMCIListItem *iter; + VMCILockFlags flags; + + ASSERT(VMCI_HasGuestDevice()); + + VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags); + + VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) { + VMCIDoorbellEntry *cur = + VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem); + + ASSERT(cur); + + if (cur->idx == notifyIdx) { + ASSERT(cur->notifyCB); + if (cur->runDelayed) { + int err; + + VMCIResource_Hold(&cur->resource); + err = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, cur); + if (err != VMCI_SUCCESS) { + VMCIResource_Release(&cur->resource); + goto out; + } + } else { + cur->notifyCB(cur->clientData); + } + } + } + +out: + VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags); +} + + +/* + *------------------------------------------------------------------------------ + * + * VMCI_ScanNotificationBitmap -- + * + * Scans the notification bitmap, collects pending notifications, + * resets the bitmap and invokes appropriate callbacks. + * + * Results: + * None. + * + * Side effects: + * May schedule tasks, allocate memory and run callbacks. + * + *------------------------------------------------------------------------------ + */ + +void +VMCI_ScanNotificationBitmap(uint8 *bitmap) +{ + uint32 idx; + + ASSERT(bitmap); + ASSERT(VMCI_HasGuestDevice()); + + for (idx = 0; idx < maxNotifyIdx; idx++) { + if (bitmap[idx] & 0x1) { + bitmap[idx] &= ~1; + VMCIDoorbellFireEntries(idx); + } + } +} + + +#else // SOLARIS) || __APPLE__ + +/* + *----------------------------------------------------------------------------- + * + * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify -- + * + * The doorbell functions have yet to be implemented for Solaris + * and Mac OS X guest drivers. + * + * Results: + * VMCI_ERROR_UNAVAILABLE. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create) +int +VMCIDoorbell_Create(VMCIHandle *handle, // IN + uint32 flags, // I + VMCIPrivilegeFlags privFlags, // IN + VMCICallback notifyCB, // IN + void *clientData) // IN +{ + return VMCI_ERROR_UNAVAILABLE; +} + + +VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy) +int +VMCIDoorbell_Destroy(VMCIHandle handle) // IN +{ + return VMCI_ERROR_UNAVAILABLE; +} + + +VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify) +int +VMCIDoorbell_Notify(VMCIHandle handle, // IN + VMCIPrivilegeFlags privFlags) // IN +{ + return VMCI_ERROR_UNAVAILABLE; +} + +#endif // SOLARIS) || __APPLE__ diff --git a/open-vm-tools/modules/linux/vmci/vmciDoorbell.h b/open-vm-tools/modules/linux/vmci/vmciDoorbell.h index c9c45d5e8..73dbf9e4d 100644 --- a/open-vm-tools/modules/linux/vmci/vmciDoorbell.h +++ b/open-vm-tools/modules/linux/vmci/vmciDoorbell.h @@ -33,8 +33,15 @@ #include "vmci_kernel_if.h" #include "vmci_defs.h" +void VMCIDoorbell_Init(void); +void VMCIDoorbell_Exit(void); +void VMCIDoorbell_Hibernate(Bool enterHibernation); +void VMCIDoorbell_Sync(void); + int VMCIDoorbellHostContextNotify(VMCIId srcCID, VMCIHandle handle); int VMCIDoorbellGetPrivFlags(VMCIHandle handle, VMCIPrivilegeFlags *privFlags); -void VMCIDoorbell_Sync(void); + +Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN); +void VMCI_ScanNotificationBitmap(uint8 *bitmap); #endif // VMCI_DOORBELL_H diff --git a/open-vm-tools/modules/linux/vmci/vmciHashtable.c b/open-vm-tools/modules/linux/vmci/vmciHashtable.c index dbff18db1..cdea16b8c 100644 --- a/open-vm-tools/modules/linux/vmci/vmciHashtable.c +++ b/open-vm-tools/modules/linux/vmci/vmciHashtable.c @@ -49,6 +49,19 @@ #define LGPFX "VMCIHashTable: " +#if defined(VMKERNEL) + /* VMK doesn't need BH locks, so use lower ranks. */ +# define VMCIHashTableInitLock(_l, _n) \ + VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGHEST) +# define VMCIHashTableGrabLock(_l, _f) VMCI_GrabLock(_l, _f) +# define VMCIHashTableReleaseLock(_l, _f) VMCI_ReleaseLock(_l, _f) +#else // VMKERNEL +# define VMCIHashTableInitLock(_l, _n) \ + VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGH_BH) +# define VMCIHashTableGrabLock(_l, _f) VMCI_GrabLock_BH(_l, _f) +# define VMCIHashTableReleaseLock(_l, _f) VMCI_ReleaseLock_BH(_l, _f) +#endif // VMKERNEL + #define VMCI_HASHTABLE_HASH(_h, _sz) \ VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(_h), (_sz)) @@ -87,9 +100,7 @@ VMCIHashTable_Create(int size) } memset(table->entries, 0, sizeof *table->entries * size); table->size = size; - VMCI_InitLock(&table->lock, - "VMCIHashTableLock", - VMCI_LOCK_RANK_HIGH); + VMCIHashTableInitLock(&table->lock, "VMCIHashTableLock"); return table; } @@ -121,7 +132,7 @@ VMCIHashTable_Destroy(VMCIHashTable *table) ASSERT(table); - VMCI_GrabLock(&table->lock, &flags); + VMCIHashTableGrabLock(&table->lock, &flags); #if 0 #ifdef VMX86_DEBUG for (i = 0; i < table->size; i++) { @@ -139,8 +150,8 @@ VMCIHashTable_Destroy(VMCIHashTable *table) #endif VMCI_FreeKernelMem(table->entries, sizeof *table->entries * table->size); table->entries = NULL; - VMCI_ReleaseLock(&table->lock, flags); - VMCI_CleanupLock(&table->lock); + VMCIHashTableReleaseLock(&table->lock, flags); + VMCI_CleanupLock(&table->lock); VMCI_FreeKernelMem(table, sizeof *table); } @@ -188,18 +199,18 @@ VMCIHashTable_AddEntry(VMCIHashTable *table, // IN ASSERT(entry); ASSERT(table); - VMCI_GrabLock(&table->lock, &flags); + VMCIHashTableGrabLock(&table->lock, &flags); /* Do not allow addition of a new entry if the device is being shutdown. */ if (VMCI_DeviceShutdown()) { - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableReleaseLock(&table->lock, flags); return VMCI_ERROR_DEVICE_NOT_FOUND; } if (VMCIHashTableEntryExistsLocked(table, entry->handle)) { VMCI_DEBUG_LOG(4, (LGPFX"Entry (handle=0x%x:0x%x) already exists.\n", entry->handle.context, entry->handle.resource)); - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableReleaseLock(&table->lock, flags); return VMCI_ERROR_DUPLICATE_ENTRY; } @@ -210,7 +221,7 @@ VMCIHashTable_AddEntry(VMCIHashTable *table, // IN entry->refCount++; entry->next = table->entries[idx]; table->entries[idx] = entry; - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableReleaseLock(&table->lock, flags); return VMCI_SUCCESS; } @@ -239,8 +250,8 @@ VMCIHashTable_RemoveEntry(VMCIHashTable *table, // IN ASSERT(table); ASSERT(entry); - VMCI_GrabLock(&table->lock, &flags); - + VMCIHashTableGrabLock(&table->lock, &flags); + /* First unlink the entry. */ result = HashTableUnlinkEntry(table, entry); if (result != VMCI_SUCCESS) { @@ -254,10 +265,10 @@ VMCIHashTable_RemoveEntry(VMCIHashTable *table, // IN result = VMCI_SUCCESS_ENTRY_DEAD; goto done; } - + done: - VMCI_ReleaseLock(&table->lock, flags); - + VMCIHashTableReleaseLock(&table->lock, flags); + return result; } @@ -338,15 +349,48 @@ VMCIHashTable_GetEntry(VMCIHashTable *table, // IN } ASSERT(table); - - VMCI_GrabLock(&table->lock, &flags); + + VMCIHashTableGrabLock(&table->lock, &flags); entry = VMCIHashTableGetEntryLocked(table, handle); - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableReleaseLock(&table->lock, flags); return entry; } +/* + *------------------------------------------------------------------------------ + * + * VMCIHashTable_HoldEntry -- + * + * Hold the given entry. This will increment the entry's reference count. + * This is like a GetEntry() but without having to lookup the entry by + * handle. + * + * Result: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +void +VMCIHashTable_HoldEntry(VMCIHashTable *table, // IN + VMCIHashEntry *entry) // IN/OUT +{ + VMCILockFlags flags; + + ASSERT(table); + ASSERT(entry); + + VMCIHashTableGrabLock(&table->lock, &flags); + entry->refCount++; + VMCIHashTableReleaseLock(&table->lock, flags); +} + + /* *------------------------------------------------------------------------------ * @@ -377,7 +421,7 @@ VMCIHashTableReleaseEntryLocked(VMCIHashTable *table, // IN entry->refCount--; /* Check if this is last reference and report if so. */ - if (entry->refCount == 0) { + if (entry->refCount == 0) { /* * Remove entry from hash table if not already removed. This could have @@ -417,9 +461,9 @@ VMCIHashTable_ReleaseEntry(VMCIHashTable *table, // IN int result; ASSERT(table); - VMCI_GrabLock(&table->lock, &flags); + VMCIHashTableGrabLock(&table->lock, &flags); result = VMCIHashTableReleaseEntryLocked(table, entry); - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableReleaseLock(&table->lock, flags); return result; } @@ -450,9 +494,9 @@ VMCIHashTable_EntryExists(VMCIHashTable *table, // IN ASSERT(table); - VMCI_GrabLock(&table->lock, &flags); + VMCIHashTableGrabLock(&table->lock, &flags); exists = VMCIHashTableEntryExistsLocked(table, handle); - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableReleaseLock(&table->lock, flags); return exists; } @@ -576,6 +620,6 @@ VMCIHashTable_Sync(VMCIHashTable *table) { VMCILockFlags flags; ASSERT(table); - VMCI_GrabLock(&table->lock, &flags); - VMCI_ReleaseLock(&table->lock, flags); + VMCIHashTableGrabLock(&table->lock, &flags); + VMCIHashTableReleaseLock(&table->lock, flags); } diff --git a/open-vm-tools/modules/linux/vmci/vmciHashtable.h b/open-vm-tools/modules/linux/vmci/vmciHashtable.h index c1e062fdf..a786818ea 100644 --- a/open-vm-tools/modules/linux/vmci/vmciHashtable.h +++ b/open-vm-tools/modules/linux/vmci/vmciHashtable.h @@ -52,6 +52,7 @@ void VMCIHashTable_InitEntry(VMCIHashEntry *entry, VMCIHandle handle); int VMCIHashTable_AddEntry(VMCIHashTable *table, VMCIHashEntry *entry); int VMCIHashTable_RemoveEntry(VMCIHashTable *table, VMCIHashEntry *entry); VMCIHashEntry *VMCIHashTable_GetEntry(VMCIHashTable *table, VMCIHandle handle); +void VMCIHashTable_HoldEntry(VMCIHashTable *table, VMCIHashEntry *entry); int VMCIHashTable_ReleaseEntry(VMCIHashTable *table, VMCIHashEntry *entry); Bool VMCIHashTable_EntryExists(VMCIHashTable *table, VMCIHandle handle); void VMCIHashTable_Sync(VMCIHashTable *table); diff --git a/open-vm-tools/modules/linux/vmci/vmciNotifications.c b/open-vm-tools/modules/linux/vmci/vmciNotifications.c deleted file mode 100644 index b16a4483d..000000000 --- a/open-vm-tools/modules/linux/vmci/vmciNotifications.c +++ /dev/null @@ -1,1203 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciNotifications.c -- - * - * Implementation of the VMCI notifications registration and - * delivery, and the related doorbell API for the guest driver. - */ - -#ifdef __linux__ -# include "driver-config.h" -# include "compat_kernel.h" -# include "compat_module.h" -#endif // linux - -#include "vmci_kernel_if.h" -#include "vm_basic_types.h" -#include "vm_assert.h" -#include "vmciKernelAPI.h" -#include "vmci_defs.h" -#include "vmci_call_defs.h" -#include "vmciInt.h" -#include "vmciUtil.h" - -#define LGPFX "VMCINotifications: " - -#if !defined(SOLARIS) && !defined(__APPLE__) - -/* - * The VMCI Notify hash table provides two mappings: - * 1) one maps a given notification index in the bitmap to the - * entries, giving the set of handlers registered for that - * index. This is mainly used for firing handlers for a given - * bitmap index. - * 2) the other maps a handle and a resource (doorbell/queuepair) - * to the entry (used to check for duplicates and delete the - * entry) - */ - -#define HASH_TABLE_SIZE 64 -#define VMCI_NOTIF_HASH(val) VMCI_HashId(val, HASH_TABLE_SIZE) - -typedef struct VMCINotifyHashEntry { - uint32 idx; // Bitmap index - VMCIHandle handle; - Bool doorbell; - Bool runDelayed; - VMCICallback notifyCB; - void *callbackData; - VMCIEvent destroyEvent; - int refCount; - VMCIListItem handleListItem; - VMCIListItem idxListItem; -} VMCINotifyHashEntry; - -typedef struct VMCINotifyHashTable { - VMCILock lock; - VMCIList entriesByIdx[HASH_TABLE_SIZE]; - VMCIList entriesByHandle[HASH_TABLE_SIZE]; -} VMCINotifyHashTable; - - -static int VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry); -static void VMCINotifyHashSetEntryCallback(VMCINotifyHashEntry *entry, - VMCICallback notifyCB); -static VMCINotifyHashEntry *VMCINotifyHashRemoveEntry(VMCIHandle handle, - Bool doorbell); -static int VMCINotifyReleaseCB(void *clientData); -static void VMCINotifyHashReleaseEntry(VMCINotifyHashEntry *entry); -static VMCINotifyHashEntry *VMCINotifyHashFindByIdx(uint32 idx, - uint32 *hashBucket); -static VMCINotifyHashEntry *VMCINotifyHashFindByHandle(VMCIHandle handle, - Bool doorbell, - uint32 *hashBucket); - -static void VMCINotifyDelayedDispatchCB(void *data); -static void VMCINotifyHashFireEntries(uint32 notifyIdx); - -static int LinkNotificationHypercall(VMCIHandle handle, Bool doorbell, - uint32 notifyIdx); -static int UnlinkNotificationHypercall(VMCIHandle handle, Bool doorbell); - - -/* - * The VMCI notify hash table keeps track of currently registered - * notifications. - */ - -static VMCINotifyHashTable vmciNotifyHT; - -/* - * The maxNotifyIdx is one larger than the currently known bitmap - * index in use, and is used to determine how much of the bitmap needs - * to be scanned. - */ - -static uint32 maxNotifyIdx; - -/* - * the notifyIdxCount is used for determining whether there are free - * entries within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx). - */ - -static uint32 notifyIdxCount; - -/* - * The lastNotifyIdxReserved is used to track the last index handed - * out - in the case where multiple handles share a notification - * index, we hand out indexes round robin based on - * lastNotifyIdxReserved. - */ - -static uint32 lastNotifyIdxReserved; - -/* - * lastNotifyIdxReleased is a one entry cache used to by the index - * allocation. - */ - -static uint32 lastNotifyIdxReleased = PAGE_SIZE; - - -/* - *---------------------------------------------------------------------- - * - * VMCINotifications_Init -- - * - * General init code. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCINotifications_Init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vmciNotifyHT.entriesByIdx); i++) { - VMCIList_Init(&vmciNotifyHT.entriesByIdx[i]); - } - for (i = 0; i < ARRAY_SIZE(vmciNotifyHT.entriesByHandle); i++) { - VMCIList_Init(&vmciNotifyHT.entriesByHandle[i]); - } - - VMCI_InitLock(&vmciNotifyHT.lock, "VMCINotifyHashLock", - VMCI_LOCK_RANK_HIGHER_BH); - return; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCINotifications_Exit -- - * - * General exit code. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCINotifications_Exit(void) -{ - uint32 bucket; - VMCIListItem *iter, *iter2; - - for (bucket = 0; bucket < HASH_TABLE_SIZE; bucket++) { - VMCIList_ScanSafe(iter, iter2, &vmciNotifyHT.entriesByIdx[bucket]) { - VMCINotifyHashEntry *cur; - - /* - * We should never get here because all notifications should have been - * unregistered before we try to unload the driver module. - * Also, delayed callbacks could still be firing so this cleanup - * would not be safe. - * Still it is better to free the memory than not ... so we - * leave this code in just in case.... - * - */ - ASSERT(FALSE); - - cur = VMCIList_Entry(iter, VMCINotifyHashEntry, idxListItem); - VMCI_FreeKernelMem(cur, sizeof *cur); - } - } - VMCI_CleanupLock(&vmciNotifyHT.lock); - -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCINotifications_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * TRUE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCINotifications_Sync(void) -{ - VMCILockFlags flags; - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCINotifications_Hibernate -- - * - * When a guest leaves hibernation, the device driver state is out - * of sync with the device state, since the driver state has - * doorbells registered that aren't known to the device. This - * function takes care of reregistering any doorbells. In case an - * error occurs during reregistration (this is highly unlikely - * since 1) it succeeded the first time 2) the device driver is the - * only source of doorbell registrations), we simply log the - * error. The doorbell can still be destroyed using - * VMCIDoorbell_Destroy. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCINotifications_Hibernate(Bool enterHibernate) // IN -{ - VMCILockFlags flags; - uint32 bucket; - VMCIListItem *iter; - - if (enterHibernate) { - /* - * Nothing to do when entering hibernation. - */ - - return; - } - - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - - for (bucket = 0; bucket < HASH_TABLE_SIZE; bucket++) { - VMCIList_Scan(iter, &vmciNotifyHT.entriesByIdx[bucket]) { - VMCINotifyHashEntry *cur; - int result; - - cur = VMCIList_Entry(iter, VMCINotifyHashEntry, idxListItem); - result = LinkNotificationHypercall(cur->handle, cur->doorbell, cur->idx); - if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) { - VMCI_WARNING((LGPFX"Failed to reregister doorbell (handle=0x%x:0x%x) " - "of resource %s to index (error=%d).\n", - cur->handle.context, cur->handle.resource, - cur->doorbell ? "doorbell" : "queue pair", result)); - } - } - } - - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); -} - - -/* - *------------------------------------------------------------------------- - * - * VMCINotifyHashAddEntry -- - * - * Given a notification entry, adds it to the hashtable of - * notifications. - * - * Result: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -static int -VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry) // IN -{ - VMCILockFlags flags; - uint32 bucket; - uint32 newNotifyIdx; - int result; - static VMCIId notifyRID = 0; - - ASSERT(entry); - - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - - /* Do not allow addition of a new handle if the device is being shutdown. */ - if (VMCI_DeviceShutdown()) { - result = VMCI_ERROR_DEVICE_NOT_FOUND; - goto out; - } - - if (VMCI_HANDLE_INVALID(entry->handle)) { - VMCIHandle newHandle; - VMCIId oldRID = notifyRID; - Bool found; - - do { - newHandle = VMCI_MAKE_HANDLE(VMCI_GetContextID(), notifyRID); - notifyRID++; - found = VMCINotifyHashFindByHandle(newHandle, entry->doorbell, NULL) != NULL; - } while(found && oldRID != notifyRID); - if (UNLIKELY(found)) { - /* - * We went full circle and still didn't find a free handle. - */ - - result = VMCI_ERROR_NO_HANDLE; - goto out; - } - entry->handle = newHandle; - } else if (VMCI_GetContextID() != entry->handle.context) { - /* - * The context id passed down should either be invalid or - * the context id of the guest. - */ - - result = VMCI_ERROR_INVALID_ARGS; - goto out; - } - - if (VMCINotifyHashFindByHandle(entry->handle, entry->doorbell, &bucket)) { - result = VMCI_ERROR_ALREADY_EXISTS; - goto out; - } - VMCIList_Insert(&entry->handleListItem, - &vmciNotifyHT.entriesByHandle[bucket]); - - /* - * Below we try to allocate an index in the notification bitmap - * with "not too much" sharing between resources. If we use less - * that the full bitmap, we either add to the end if there are no - * unused flags withing the currently used area, or we search for - * unused ones. If we use the full bitmap, we allocate the index - * round robin. - */ - - if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) { - if (lastNotifyIdxReleased < maxNotifyIdx && - !VMCINotifyHashFindByIdx(lastNotifyIdxReleased, NULL)) { - newNotifyIdx = lastNotifyIdxReleased; - lastNotifyIdxReleased = PAGE_SIZE; - } else { - Bool reused = FALSE; - newNotifyIdx = lastNotifyIdxReserved; - if (notifyIdxCount + 1 < maxNotifyIdx) { - do { - if (!VMCINotifyHashFindByIdx(newNotifyIdx, NULL)) { - reused = TRUE; - break; - } - newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx; - } while(newNotifyIdx != lastNotifyIdxReleased); - } - if (!reused) { - newNotifyIdx = maxNotifyIdx; - maxNotifyIdx++; - } - } - } else { - newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE; - } - lastNotifyIdxReserved = newNotifyIdx; - notifyIdxCount++; - - bucket = VMCI_NOTIF_HASH(newNotifyIdx); - entry->refCount++; - entry->idx = newNotifyIdx; - VMCIList_Insert(&entry->idxListItem, &vmciNotifyHT.entriesByIdx[bucket]); - result = VMCI_SUCCESS; -out: - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); - return result; -} - - -/* - *------------------------------------------------------------------------- - * - * VMCINotifyHashSetEntryCallback -- - * - * Sets the notify callback of the given entry. Once the callback - * has been set, it may start firing. - * - * Result: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -static void -VMCINotifyHashSetEntryCallback(VMCINotifyHashEntry *entry, // IN - VMCICallback notifyCB) // IN -{ - VMCILockFlags flags; - - ASSERT(entry && notifyCB); - - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - entry->notifyCB = notifyCB; - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); -} - - -/* - *------------------------------------------------------------------------- - * - * VMCINotifyHashRemoveEntry -- - * - * Removes the entry identified by the handle of the given - * resource type from the hash table. - * - * Result: - * Pointer to entry if removed, NULL if not found. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -static VMCINotifyHashEntry * -VMCINotifyHashRemoveEntry(VMCIHandle handle, // IN - Bool doorbell) // IN -{ - VMCILockFlags flags; - VMCINotifyHashEntry *entry; - uint32 bucket; - - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - entry = VMCINotifyHashFindByHandle(handle, doorbell, &bucket); - if (entry) { - ASSERT(entry->refCount > 0); - VMCIList_Remove(&entry->handleListItem, - &vmciNotifyHT.entriesByHandle[bucket]); - bucket = VMCI_NOTIF_HASH(entry->idx); - VMCIList_Remove(&entry->idxListItem, &vmciNotifyHT.entriesByIdx[bucket]); - notifyIdxCount--; - if (entry->idx == maxNotifyIdx - 1) { - /* - * If we delete an entry with the maximum known notification - * index, we take the opportunity to prune the current - * max. As there might be other unused indices immediately - * below, we lower the maximum until we hit an index in use. - */ - - while (maxNotifyIdx > 0 && - !VMCINotifyHashFindByIdx(maxNotifyIdx - 1, NULL)) { - maxNotifyIdx--; - } - } - lastNotifyIdxReleased = entry->idx; - } - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); - - return entry; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCINotifyReleaseCB -- - * - * Callback to release the notification entry reference. It is - * called by the VMCI_WaitOnEvent function before it blocks. - * - * Result: - * 0. - * - * Side effects: - * Releases hash entry (see below). - * - *------------------------------------------------------------------------------ - */ - -static int -VMCINotifyReleaseCB(void *clientData) // IN -{ - VMCINotifyHashEntry *entry = (VMCINotifyHashEntry *)clientData; - ASSERT(entry); - VMCINotifyHashReleaseEntry(entry); - - return 0; -} - - -/* - *------------------------------------------------------------------------- - * - * VMCINotifyHashReleaseEntry -- - * - * Drops a reference to the current hash entry. If this is the last - * reference then the entry is freed. - * - * Result: - * None. - * - * Side effects: - * May signal event. - * - *------------------------------------------------------------------------- - */ - -static void -VMCINotifyHashReleaseEntry(VMCINotifyHashEntry *entry) // IN -{ - VMCILockFlags flags; - - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - entry->refCount--; - - /* - * Check if this is last reference and signal the destroy event if - * so. - */ - - if (entry->refCount == 0) { - VMCI_SignalEvent(&entry->destroyEvent); - } - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCINotifyHashFindByIdx -- - * - * Find hash entry by bitmap index. Assumes lock is - * held. Regardless of whether an entry was found, the bucket that - * the entry would have been in is returned in hashBucket (if - * valid). - * - * Results: - * Entry if found, NULL if not. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static VMCINotifyHashEntry * -VMCINotifyHashFindByIdx(uint32 idx, // IN - uint32 *hashBucket) // IN/OUT: hash value for idx -{ - VMCIListItem *iter; - uint32 bucket = VMCI_NOTIF_HASH(idx); - - if (hashBucket) { - *hashBucket = bucket; - } - - VMCIList_Scan(iter, &vmciNotifyHT.entriesByIdx[bucket]) { - VMCINotifyHashEntry *cur = - VMCIList_Entry(iter, VMCINotifyHashEntry, idxListItem); - if (cur->idx == idx) { - return cur; - } - } - return NULL; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCINotifyHashFindByHandle -- - * - * Find hash entry by handle and resoruce. Assumes lock is - * held. Regardless of whether an entry was found, the bucket that - * the entry would have been in is returned in hashBucket (if - * valid). - * - * Results: - * Entry if found, NULL if not. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static VMCINotifyHashEntry * -VMCINotifyHashFindByHandle(VMCIHandle handle, // IN - Bool doorbell, // IN - uint32 *hashBucket) // IN/OUT: hash value for handle -{ - VMCIListItem *iter; - uint32 bucket = VMCI_NOTIF_HASH(handle.resource); - - if (hashBucket) { - *hashBucket = bucket; - } - - VMCIList_Scan(iter, &vmciNotifyHT.entriesByHandle[bucket]) { - VMCINotifyHashEntry *cur = - VMCIList_Entry(iter, VMCINotifyHashEntry, handleListItem); - if (VMCI_HANDLE_EQUAL(cur->handle, handle) && cur->doorbell == doorbell) { - return cur; - } - } - return NULL; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCINotifyDelayedDispatchCB -- - * - * Calls the specified callback in a delayed context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCINotifyDelayedDispatchCB(void *data) // IN -{ - VMCINotifyHashEntry *entry = (VMCINotifyHashEntry *)data; - - ASSERT(data); - - entry->notifyCB(entry->callbackData); - - VMCINotifyHashReleaseEntry(entry); -} - - -/* - *------------------------------------------------------------------------- - * - * VMCINotifyHashFireEntries -- - * - * Executes or schedules the handlers for a given notify index. - * - * Result: - * Notification hash entry if found. NULL otherwise. - * - * Side effects: - * Whatever the side effects of the handlers are. - * - *------------------------------------------------------------------------- - */ - -static void -VMCINotifyHashFireEntries(uint32 notifyIdx) // IN -{ - VMCILockFlags flags; - VMCIListItem *iter; - int bucket = VMCI_NOTIF_HASH(notifyIdx); - - VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); - - VMCIList_Scan(iter, &vmciNotifyHT.entriesByIdx[bucket]) { - VMCINotifyHashEntry *cur = VMCIList_Entry(iter, VMCINotifyHashEntry, - idxListItem); - if (cur->idx == notifyIdx && cur->notifyCB) { - if (cur->runDelayed) { - int err; - - cur->refCount++; - err = VMCI_ScheduleDelayedWork(VMCINotifyDelayedDispatchCB, cur); - if (err != VMCI_SUCCESS) { - cur->refCount--; - goto out; - } - } else { - cur->notifyCB(cur->callbackData); - } - } - } -out: - VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); -} - - -/* - *---------------------------------------------------------------------- - * - * LinkNotificationHypercall -- - * - * Creates a link between the given doorbell handle and the given - * index in the bitmap in the device backend. - * - * Results: - * VMCI_SUCCESS if success, appropriate error code otherwise. - * - * Side effects: - * Notification state is created in hypervisor. - * - *---------------------------------------------------------------------- - */ - -static int -LinkNotificationHypercall(VMCIHandle handle, // IN - Bool doorbell, // IN - uint32 notifyIdx) // IN -{ - VMCIDoorbellLinkMsg linkMsg; - int result; - VMCIId resourceID; - - ASSERT(!VMCI_HANDLE_INVALID(handle)); - - if (doorbell) { - resourceID = VMCI_DOORBELL_LINK; - } else { - ASSERT(FALSE); - return VMCI_ERROR_UNAVAILABLE; - } - - linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID); - linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE; - linkMsg.handle = handle; - linkMsg.notifyIdx = notifyIdx; - - result = VMCI_SendDatagram((VMCIDatagram *)&linkMsg); - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * UnlinkNotificationHypercall -- - * - * Unlinks the given doorbell handle from an index in the bitmap in - * the device backend. - * - * Results: - * VMCI_SUCCESS if success, appropriate error code otherwise. - * - * Side effects: - * Notification state is destroyed in hypervisor. - * - *---------------------------------------------------------------------- - */ - -static int -UnlinkNotificationHypercall(VMCIHandle handle, // IN - Bool doorbell) // IN -{ - VMCIDoorbellUnlinkMsg unlinkMsg; - int result; - VMCIId resourceID; - - ASSERT(!VMCI_HANDLE_INVALID(handle)); - - if (doorbell) { - resourceID = VMCI_DOORBELL_UNLINK; - } else { - ASSERT(FALSE); - return VMCI_ERROR_UNAVAILABLE; - } - - unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID); - unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE; - unlinkMsg.handle = handle; - - result = VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCINotificationRegister -- - * - * Links a resource with an index in the notification bitmap. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Notification state is created both in guest and on host. - * - *----------------------------------------------------------------------------- - */ - -int -VMCINotificationRegister(VMCIHandle *handle, // IN - Bool doorbell, // IN - uint32 flags, // IN - VMCICallback notifyCB, // IN - void *callbackData) // IN -{ - int result; - VMCINotifyHashEntry *entry; - - if (!notifyCB || !handle) { - return VMCI_ERROR_INVALID_ARGS; - } - - entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED); - if (entry == NULL) { - return VMCI_ERROR_NO_MEM; - } - - entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE; - if (entry->runDelayed && !VMCI_CanScheduleDelayedWork()) { - VMCI_FreeKernelMem(entry, sizeof *entry); - return VMCI_ERROR_INVALID_ARGS; - } - - /* - * Reserve an index in the notification bitmap. - */ - - entry->handle = *handle; - entry->doorbell = doorbell; - entry->notifyCB = NULL; // Wait with this until link is established in hypervisor - entry->callbackData = callbackData; - entry->refCount = 0; - VMCIList_InitEntry(&entry->handleListItem); - VMCIList_InitEntry(&entry->idxListItem); - result = VMCINotifyHashAddEntry(entry); - if (result != VMCI_SUCCESS) { - VMCI_FreeKernelMem(entry, sizeof *entry); - return result; - } - - VMCI_CreateEvent(&entry->destroyEvent); - - result = LinkNotificationHypercall(entry->handle, doorbell, entry->idx); - if (result != VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to link (handle=0x%x:0x%x) of resource %s " - "to index (error=%d).\n", - entry->handle.context, entry->handle.resource, - entry->doorbell ? "doorbell" : "queue pair", result)); - VMCINotifyHashRemoveEntry(entry->handle, entry->doorbell); - VMCI_DestroyEvent(&entry->destroyEvent); - VMCI_FreeKernelMem(entry, sizeof *entry); - } else { - /* - * When the handle is set, the notification callback may start - * to fire. Since flags in the notification bitmap can be - * shared, a given callback may fire immediately. - */ - - VMCINotifyHashSetEntryCallback(entry, notifyCB); - *handle = entry->handle; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCINotificationUnregister -- - * - * Unregisters a notification previously created through - * VMCINotificationRegister. This function may block. The call - * always succeeds if the notification exists. - * - * Results: - * VMCI_SUCCESS if success, VMCI_ERROR_NOT_FOUND otherwise. - * - * Side effects: - * Notification state is destroyed both in guest and hypervisor. - * - *----------------------------------------------------------------------------- - */ - -int -VMCINotificationUnregister(VMCIHandle handle, // IN - Bool doorbell) // IN -{ - VMCINotifyHashEntry *entry; - int result; - - entry = VMCINotifyHashRemoveEntry(handle, doorbell); - if (!entry) { - return VMCI_ERROR_NOT_FOUND; - } - - VMCI_WaitOnEvent(&entry->destroyEvent, VMCINotifyReleaseCB, entry); - VMCI_DestroyEvent(&entry->destroyEvent); - VMCI_FreeKernelMem(entry, sizeof *entry); - - result = UnlinkNotificationHypercall(handle, doorbell); - if (result != VMCI_SUCCESS) { - /* - * The only reason this should fail would be an inconsistency - * between guest and hypervisor state, where the guest believes - * it has an active registration whereas the hypervisor - * doesn't. One case where this may happen is if a doorbell is - * unregistered following a hibernation at a time where the - * doorbell state hasn't been restored on the hypervisor side - * yet. Since the handle has now been removed in the guest, we - * just print a warning and return success. - */ - - VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by " - "hypervisor (error=%d).\n", - doorbell ? "doorbell" : "queuepair", - handle.context, handle.resource, result)); - } - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_RegisterNotificationBitmap -- - * - * Verify that the host supports the hypercalls we need. If it does not, - * try to find fallback hypercalls and use those instead. - * - * Results: - * TRUE if the bitmap is registered successfully with the device, FALSE - * otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCI_RegisterNotificationBitmap(PPN bitmapPPN) // IN -{ - VMCINotifyBitmapSetMsg bitmapSetMsg; - int result; - - bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_SET_NOTIFY_BITMAP); - bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE; - bitmapSetMsg.bitmapPPN = bitmapPPN; - - result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg); - if (result != VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as " - "notification bitmap (error=%d).\n", - bitmapPPN, result)); - return FALSE; - } - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_ScanNotificationBitmap -- - * - * Scans the notification bitmap, collects pending notifications, - * resets the bitmap and invokes appropriate callbacks. - * - * Results: - * None. - * - * Side effects: - * May schedule tasks, allocate memory and run callbacks. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_ScanNotificationBitmap(uint8 *bitmap) // IN -{ - size_t idx; - - for (idx = 0; idx < maxNotifyIdx; idx++) { - if (bitmap[idx] & 0x1) { - bitmap[idx] &= ~1; - VMCINotifyHashFireEntries(idx); - } - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoorbell_Create -- - * - * Creates a doorbell with the given callback. If the handle is - * VMCI_INVALID_HANDLE, a free handle will be assigned, if - * possible. The callback can be run in interrupt context (the - * default) or delayed (in a kernel thread) by specifying the - * flag VMCI_FLAG_DELAYED_CB. If delayed execution is selected, a - * given callback may not be run if the kernel is unable to - * allocate memory for the delayed execution (highly unlikely). - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create) -int -VMCIDoorbell_Create(VMCIHandle *handle, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN: Unused in guest - VMCICallback notifyCB, // IN - void *clientData) // IN -{ - if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB) { - return VMCI_ERROR_INVALID_ARGS; - } - if (privFlags & ~VMCI_LEAST_PRIVILEGE_FLAGS) { - return VMCI_ERROR_NO_ACCESS; - } - - return VMCINotificationRegister(handle, TRUE, flags, - notifyCB, clientData); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoorbell_Destroy -- - * - * Destroys a doorbell previously created with - * VMCIDoorbell_Create. This operation may block waiting for a - * callback to finish. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * May block. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy) -int -VMCIDoorbell_Destroy(VMCIHandle handle) // IN -{ - if (VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - return VMCINotificationUnregister(handle, TRUE); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoorbell_Notify -- - * - * Generates a notification on the doorbell identified by the - * handle. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * May do a hypercall. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify) -int -VMCIDoorbell_Notify(VMCIHandle handle, // IN - VMCIPrivilegeFlags privFlags) // IN: Unused in guest -{ - VMCIDoorbellNotifyMsg notifyMsg; - int result; - - if (VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (privFlags & ~VMCI_LEAST_PRIVILEGE_FLAGS) { - return VMCI_ERROR_NO_ACCESS; - } - - notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_DOORBELL_NOTIFY); - notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE; - notifyMsg.handle = handle; - - result = VMCI_SendDatagram((VMCIDatagram *)¬ifyMsg); - - return result; -} - - -#else // defined(SOLARIS) || defined(__APPLE__) - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify -- - * - * The doorbell functions have yet to be implemented for Solaris - * and Mac OS X guest drivers. - * - * Results: - * VMCI_ERROR_UNAVAILABLE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create) -int -VMCIDoorbell_Create(VMCIHandle *handle, // IN - uint32 flags, // I - VMCIPrivilegeFlags privFlags, // IN - VMCICallback notifyCB, // IN - void *clientData) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy) -int -VMCIDoorbell_Destroy(VMCIHandle handle) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify) -int -VMCIDoorbell_Notify(VMCIHandle handle, // IN - VMCIPrivilegeFlags privFlags) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - -#endif diff --git a/open-vm-tools/modules/linux/vmci/vmciNotifications.h b/open-vm-tools/modules/linux/vmci/vmciNotifications.h deleted file mode 100644 index 43bc5d610..000000000 --- a/open-vm-tools/modules/linux/vmci/vmciNotifications.h +++ /dev/null @@ -1,46 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciNotifications.h -- - * - * VMCI notifications API for OS device drivers. - */ - -#ifndef _VMCI_NOTIFICATIONS_H_ -#define _VMCI_NOTIFICATIONS_H_ - -#include "vm_basic_types.h" -#include "vmci_defs.h" -#include "vmciKernelAPI.h" - -void VMCINotifications_Init(void); -void VMCINotifications_Exit(void); -void VMCINotifications_Sync(void); - -Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN); -void VMCI_ScanNotificationBitmap(uint8 *bitmap); - -int VMCINotificationRegister(VMCIHandle *handle, Bool doorbell, uint32 flags, - VMCICallback notifyCB, void *callbackData); -int VMCINotificationUnregister(VMCIHandle handle, Bool doorbell); - -void VMCINotifications_Hibernate(Bool enterHibernation); - -#endif /* !_VMCI_NOTIFICATIONS_H_ */ - diff --git a/open-vm-tools/modules/linux/vmci/vmciResource.c b/open-vm-tools/modules/linux/vmci/vmciResource.c index f8a9b286f..2034b78cd 100644 --- a/open-vm-tools/modules/linux/vmci/vmciResource.c +++ b/open-vm-tools/modules/linux/vmci/vmciResource.c @@ -60,12 +60,13 @@ static VMCIHashTable *resourceTable = NULL; /* Public Resource Access Control API. */ /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Init -- * * Initializes the VMCI Resource Access Control API. Creates a hashtable - * to hold all resources, and registers vectors and callbacks for hypercalls. + * to hold all resources, and registers vectors and callbacks for + * hypercalls. * * Results: * None. @@ -73,7 +74,7 @@ static VMCIHashTable *resourceTable = NULL; * Side effects: * None. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ int @@ -92,7 +93,7 @@ VMCIResource_Init(void) /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Exit -- * @@ -104,7 +105,7 @@ VMCIResource_Init(void) * Side effects: * None. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ void @@ -120,7 +121,7 @@ VMCIResource_Exit(void) /* - *------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_GetID -- * @@ -134,7 +135,7 @@ VMCIResource_Exit(void) * None. * * - *------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ VMCIId @@ -178,7 +179,7 @@ VMCIResource_GetID(VMCIId contextID) /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Add -- * @@ -188,7 +189,7 @@ VMCIResource_GetID(VMCIId contextID) * Side effects: * None. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ int @@ -227,7 +228,7 @@ VMCIResource_Add(VMCIResource *resource, // IN /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Remove -- * @@ -237,7 +238,7 @@ VMCIResource_Add(VMCIResource *resource, // IN * Side effects: * None. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ void @@ -258,7 +259,7 @@ VMCIResource_Remove(VMCIHandle resourceHandle, // IN: /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Get -- * @@ -268,7 +269,7 @@ VMCIResource_Remove(VMCIHandle resourceHandle, // IN: * Side effects: * None. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ VMCIResource * @@ -281,7 +282,8 @@ VMCIResource_Get(VMCIHandle resourceHandle, // IN return NULL; } resource = RESOURCE_CONTAINER(entry, VMCIResource, hashEntry); - if ((resourceType == VMCI_RESOURCE_TYPE_ANY) || (resource->type == resourceType)) { + if (resourceType == VMCI_RESOURCE_TYPE_ANY || + resource->type == resourceType) { return resource; } VMCIHashTable_ReleaseEntry(resourceTable, entry); @@ -290,7 +292,33 @@ VMCIResource_Get(VMCIHandle resourceHandle, // IN /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ + * + * VMCIResource_Hold -- + * + * Hold the given resource. This will hold the hashtable entry. This + * is like doing a Get() but without having to lookup the resource by + * handle. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------------ + */ + +void +VMCIResource_Hold(VMCIResource *resource) +{ + ASSERT(resource); + VMCIHashTable_HoldEntry(resourceTable, &resource->hashEntry); +} + + +/* + *------------------------------------------------------------------------------ * * VMCIResourceDoRemove -- * @@ -303,7 +331,7 @@ VMCIResource_Get(VMCIHandle resourceHandle, // IN * Side effects: * May deallocate memory and invoke a callback for the removed resource. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ static void INLINE @@ -319,7 +347,7 @@ VMCIResourceDoRemove(VMCIResource *resource) /* - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Release -- * @@ -329,7 +357,7 @@ VMCIResourceDoRemove(VMCIResource *resource) * Side effects: * resource's containerFreeCB will get called if last reference. * - *----------------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ int @@ -353,7 +381,7 @@ VMCIResource_Release(VMCIResource *resource) /* - *----------------------------------------------------------------------------- + *------------------------------------------------------------------------------ * * VMCIResource_Sync -- * @@ -366,7 +394,7 @@ VMCIResource_Release(VMCIResource *resource) * Side effects: * None. * - *----------------------------------------------------------------------------- + *------------------------------------------------------------------------------ */ void diff --git a/open-vm-tools/modules/linux/vmci/vmciResource.h b/open-vm-tools/modules/linux/vmci/vmciResource.h index d23f6c677..c149d3bd0 100644 --- a/open-vm-tools/modules/linux/vmci/vmciResource.h +++ b/open-vm-tools/modules/linux/vmci/vmciResource.h @@ -72,6 +72,7 @@ void VMCIResource_Remove(VMCIHandle resourceHandle, VMCIResourceType resourceType); VMCIResource *VMCIResource_Get(VMCIHandle resourceHandle, VMCIResourceType resourceType); +void VMCIResource_Hold(VMCIResource *resource); int VMCIResource_Release(VMCIResource *resource); diff --git a/open-vm-tools/modules/linux/vmci/vmciRoute.c b/open-vm-tools/modules/linux/vmci/vmciRoute.c index 88aa2230c..112337ee7 100644 --- a/open-vm-tools/modules/linux/vmci/vmciRoute.c +++ b/open-vm-tools/modules/linux/vmci/vmciRoute.c @@ -112,7 +112,7 @@ VMCI_Route(VMCIHandle *src, // IN/OUT if (fromGuest && hasHostDevice && (VMCI_WELL_KNOWN_CONTEXT_ID == src->context || VMCI_WELL_KNOWN_CONTEXT_ID == dst->context)) { - *route = VMCI_ROUTE_HOST_TO_GUEST; + *route = VMCI_ROUTE_AS_HOST; return VMCI_SUCCESS; } @@ -138,7 +138,7 @@ VMCI_Route(VMCIHandle *src, // IN/OUT } /* Send from local client down to the hypervisor. */ - *route = VMCI_ROUTE_GUEST_TO_HYPERVISOR; + *route = VMCI_ROUTE_AS_GUEST; return VMCI_SUCCESS; } @@ -159,7 +159,7 @@ VMCI_Route(VMCIHandle *src, // IN/OUT } /* Send it from local client down to the host. */ - *route = VMCI_ROUTE_GUEST_TO_HOST; + *route = VMCI_ROUTE_AS_GUEST; return VMCI_SUCCESS; } @@ -186,7 +186,7 @@ VMCI_Route(VMCIHandle *src, // IN/OUT } /* Route to local client. */ - *route = VMCI_ROUTE_HOST_TO_SELF; + *route = VMCI_ROUTE_AS_HOST; return VMCI_SUCCESS; } @@ -207,7 +207,7 @@ VMCI_Route(VMCIHandle *src, // IN/OUT } /* Pass it up to the guest. */ - *route = VMCI_ROUTE_HOST_TO_GUEST; + *route = VMCI_ROUTE_AS_HOST; return VMCI_SUCCESS; } } @@ -231,7 +231,7 @@ VMCI_Route(VMCIHandle *src, // IN/OUT * the other guest for us. */ - *route = VMCI_ROUTE_GUEST_TO_HOST; + *route = VMCI_ROUTE_AS_GUEST; return VMCI_SUCCESS; } @@ -258,11 +258,10 @@ VMCI_RouteString(VMCIRoute route) // IN { const char *vmciRouteStrings[] = { "none", - "host to self", - "host to guest", - "guest to host/hypervisor", + "as host", + "as guest", }; - if (route >= VMCI_ROUTE_NONE && route <= VMCI_ROUTE_GUEST_TO_HYPERVISOR) { + if (route >= VMCI_ROUTE_NONE && route <= VMCI_ROUTE_AS_GUEST) { return vmciRouteStrings[route]; } return ""; diff --git a/open-vm-tools/modules/linux/vmci/vmciRoute.h b/open-vm-tools/modules/linux/vmci/vmciRoute.h index b75f78a2c..a5958622a 100644 --- a/open-vm-tools/modules/linux/vmci/vmciRoute.h +++ b/open-vm-tools/modules/linux/vmci/vmciRoute.h @@ -36,10 +36,8 @@ typedef enum { VMCI_ROUTE_NONE, - VMCI_ROUTE_HOST_TO_SELF, - VMCI_ROUTE_HOST_TO_GUEST, - VMCI_ROUTE_GUEST_TO_HOST, - VMCI_ROUTE_GUEST_TO_HYPERVISOR = VMCI_ROUTE_GUEST_TO_HOST + VMCI_ROUTE_AS_HOST, + VMCI_ROUTE_AS_GUEST, } VMCIRoute; diff --git a/open-vm-tools/modules/linux/vmci/vmci_drv.c b/open-vm-tools/modules/linux/vmci/vmci_drv.c index 681d73670..dc49eb032 100644 --- a/open-vm-tools/modules/linux/vmci/vmci_drv.c +++ b/open-vm-tools/modules/linux/vmci/vmci_drv.c @@ -47,9 +47,9 @@ #include "vmci_version.h" #include "vmciContext.h" #include "vmciDatagram.h" +#include "vmciDoorbell.h" #include "vmciEvent.h" #include "vmciInt.h" -#include "vmciNotifications.h" #include "vmciQueuePairInt.h" #include "vmciResource.h" #include "vmciUtil.h" @@ -419,7 +419,7 @@ vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device VMCIDatagram_Init(); VMCIEvent_Init(); VMCIUtil_Init(); - VMCINotifications_Init(); + VMCIDoorbell_Init(); VMCIQPGuestEndpoints_Init(); /* @@ -482,7 +482,7 @@ vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device components_exit: VMCIQPGuestEndpoints_Exit(); - VMCINotifications_Exit(); + VMCIDoorbell_Exit(); VMCIUtil_Exit(); VMCIEvent_Exit(); VMCIContext_Exit(); @@ -562,7 +562,7 @@ vmci_remove_device(struct pci_dev* pdev) release_region(dev->ioaddr, dev->ioaddr_size); dev->enabled = FALSE; - VMCINotifications_Exit(); + VMCIDoorbell_Exit(); if (notification_bitmap) { vfree(notification_bitmap); }