diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/autoconf/file_operations_fsync.c open-vm-tools-2012.05.21-724730/modules/linux/shared/autoconf/file_operations_fsync.c --- open-vm-tools-2011.12.20-562307/modules/linux/shared/autoconf/file_operations_fsync.c 1969-12-31 18:00:00.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/autoconf/file_operations_fsync.c 2012-05-22 15:12:52.000000000 -0500 @@ -0,0 +1,47 @@ +/********************************************************* + * Copyright (C) 2011 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 + * + *********************************************************/ + +/* + * Linux v3.1 added 2 params to fsync for fine-grained locking control. + * But SLES11 SP2 has backported the change to its 3.0 kernel, + * so we can't rely solely on kernel version to determine number of + * arguments. + */ + +#include "compat_version.h" +#include "compat_autoconf.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) +# error This compile test intentionally fails. +#else + +#include +#include /* loff_t */ + +static int TestFsync(struct file *file, + loff_t start, loff_t end, + int datasync) +{ + return 0; +} + +struct file_operations testFO = { + .fsync = TestFsync, +}; + +#endif diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/compat_ethtool.h open-vm-tools-2012.05.21-724730/modules/linux/shared/compat_ethtool.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/compat_ethtool.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/compat_ethtool.h 2012-05-22 15:12:52.000000000 -0500 @@ -51,4 +51,10 @@ typedef struct ethtool_value compat_etht # endif #endif +#if COMPAT_LINUX_VERSION_CHECK_LT(3, 3, 0) +# define compat_ethtool_rxfh_indir_default(i, num_queues) (i % num_queues) +#else +# define compat_ethtool_rxfh_indir_default(i, num_queues) ethtool_rxfh_indir_default(i, num_queues) +#endif + #endif /* _COMPAT_ETHTOOL_H */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/compat_fs.h open-vm-tools-2012.05.21-724730/modules/linux/shared/compat_fs.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/compat_fs.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/compat_fs.h 2012-05-22 15:12:52.000000000 -0500 @@ -248,4 +248,19 @@ #define VMW_FSYNC_OLD #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) +typedef umode_t compat_umode_t; +#else +typedef int compat_umode_t; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) +#define d_make_root(inode) ({ \ + struct dentry * ____res = d_alloc_root(inode); \ + if (!____res) { \ + iput(inode); \ + } \ + ____res; \ +}) +#endif #endif /* __COMPAT_FS_H__ */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/compat_netdevice.h open-vm-tools-2012.05.21-724730/modules/linux/shared/compat_netdevice.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/compat_netdevice.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/compat_netdevice.h 2012-05-22 15:12:52.000000000 -0500 @@ -331,4 +331,10 @@ compat_multiqueue_allowed(struct pci_dev # define compat_vlan_get_protocol(skb) (skb->protocol) #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) +typedef netdev_features_t compat_netdev_features_t; +#else +typedef u32 compat_netdev_features_t; +#endif + #endif /* __COMPAT_NETDEVICE_H__ */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/vmci_defs.h open-vm-tools-2012.05.21-724730/modules/linux/shared/vmci_defs.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/vmci_defs.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/vmci_defs.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2005-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2005-2012 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 @@ -99,8 +99,12 @@ typedef enum VMCIIntrType { * Queues with pre-mapped data pages must be small, so that we don't pin * too much kernel memory (especially on vmkernel). We limit a queuepair to * 32 KB, or 16 KB per queue for symmetrical pairs. + * + * XXX, we are raising this limit to 4MB to support high-throughput workloads + * with vioi-filter. Once we switch to rings instead of queuepairs for the + * page channel, we will drop this limit again. See PR 852983. */ -#define VMCI_MAX_PINNED_QP_MEMORY (32 * 1024) +#define VMCI_MAX_PINNED_QP_MEMORY (4 * 1024 * 1024) /* * We have a fixed set of resource IDs available in the VMX. @@ -143,10 +147,26 @@ typedef uint32 VMCI_Resource; #define VMCI_RPC_PRIVILEGED 15 #define VMCI_RPC_UNPRIVILEGED 16 #define VMCI_RESOURCE_MAX 17 +/* + * The core VMCI device functionality only requires the resource IDs of + * VMCI_QUEUEPAIR_DETACH and below. + */ +#define VMCI_CORE_DEVICE_RESOURCE_MAX VMCI_QUEUEPAIR_DETACH + +/* + * VMCI reserved host datagram resource IDs. + * vsock control channel has resource id 1. + */ +#define VMCI_DVFILTER_DATA_PATH_DATAGRAM 2 /* VMCI Ids. */ typedef uint32 VMCIId; +typedef struct VMCIIdRange { + VMCIId begin; + VMCIId end; +} VMCIIdRange; + typedef struct VMCIHandle { VMCIId context; VMCIId resource; @@ -827,5 +847,62 @@ VMCIQueueHeader_BufReady(const VMCIQueue } -#endif +/* + * Defines for the VMCI traffic filter: + * - VMCI_FP_ defines the filter protocol values + * - VMCI_FD_ defines the direction values (guest or host) + * - VMCI_FT_ are the type values (allow or deny) + */ + +#define VMCI_FP_INVALID -1 +#define VMCI_FP_HYPERVISOR 0 +#define VMCI_FP_QUEUEPAIR (VMCI_FP_HYPERVISOR + 1) +#define VMCI_FP_DOORBELL (VMCI_FP_QUEUEPAIR + 1) +#define VMCI_FP_DATAGRAM (VMCI_FP_DOORBELL + 1) +#define VMCI_FP_STREAMSOCK (VMCI_FP_DATAGRAM + 1) +#define VMCI_FP_SEQPACKET (VMCI_FP_STREAMSOCK + 1) +#define VMCI_FP_MAX (VMCI_FP_SEQPACKET + 1) +#define VMCI_FD_INVALID -1 +#define VMCI_FD_GUEST 0 +#define VMCI_FD_HOST (VMCI_FD_GUEST + 1) +#define VMCI_FD_MAX (VMCI_FD_HOST + 1) + +#define VMCI_FT_INVALID -1 +#define VMCI_FT_ALLOW 0 +#define VMCI_FT_DENY (VMCI_FT_ALLOW + 1) +#define VMCI_FT_MAX (VMCI_FT_DENY + 1) + +/* + * The filter list tracks VMCI Id ranges for a given filter. + */ + +typedef struct { + uint32 len; + VMCIIdRange *list; +} VMCIFilterList; + + +/* + * The filter info is used to communicate the filter configuration + * from the VMX to the host kernel. + */ + +typedef struct { + VA64 list; // List of VMCIIdRange + uint32 len; // Length of list + uint8 dir; // VMCI_FD_X + uint8 proto; // VMCI_FP_X + uint8 type; // VMCI_FT_X +} VMCIFilterInfo; + +/* + * In the host kernel, the ingoing and outgoing filters are + * separated. The VMCIProtoFilters type captures all filters in one + * direction. The VMCIFilters type captures all filters. + */ + +typedef VMCIFilterList VMCIProtoFilters[VMCI_FP_MAX][VMCI_FT_MAX]; +typedef VMCIProtoFilters VMCIFilters[VMCI_FD_MAX]; + +#endif diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/vmci_iocontrols.h open-vm-tools-2012.05.21-724730/modules/linux/shared/vmci_iocontrols.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/vmci_iocontrols.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/vmci_iocontrols.h 2012-05-22 15:12:52.000000000 -0500 @@ -318,7 +318,7 @@ enum IOCTLCmd_VMCI { */ #include "vmware_pack_begin.h" struct IOCTLCmd_VMCIMacOS_PrivSyms { - char data[328]; + char data[344]; } #include "vmware_pack_end.h" ; diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/vmciKernelAPI1.h open-vm-tools-2012.05.21-724730/modules/linux/shared/vmciKernelAPI1.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/vmciKernelAPI1.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/vmciKernelAPI1.h 2012-05-22 15:12:52.000000000 -0500 @@ -49,6 +49,11 @@ #define VMCI_MAJOR_VERSION(v) (((v) >> 16) & 0xffff) #define VMCI_MINOR_VERSION(v) ((v) & 0xffff) +#if defined(_WIN32) +/* Path to callback object in object manager, for Windows only. */ +#define VMCI_CALLBACK_OBJECT_PATH L"\\Callback\\VMCIDetachCB" +#endif // _WIN32 + /* VMCI Device Usage API. */ typedef void (VMCI_DeviceShutdownFn)(void *deviceRegistration, @@ -58,6 +63,11 @@ Bool VMCI_DeviceGet(uint32 *apiVersion, void *userData, void **deviceRegistration); void VMCI_DeviceRelease(void *deviceRegistration); +#if defined(_WIN32) +/* Called when the client is unloading, for Windows only. */ +void VMCI_Exit(void); +#endif // _WIN32 + /* VMCI Datagram API. */ int VMCIDatagram_CreateHnd(VMCIId resourceID, uint32 flags, diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/shared/vmci_kernel_if.h open-vm-tools-2012.05.21-724730/modules/linux/shared/vmci_kernel_if.h --- open-vm-tools-2011.12.20-562307/modules/linux/shared/vmci_kernel_if.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/shared/vmci_kernel_if.h 2012-05-22 15:12:52.000000000 -0500 @@ -186,8 +186,6 @@ typedef int (*VMCIEventReleaseCB)(void * #define VMCI_SEMA_RANK_QUEUEPAIRLIST (VMCI_SEMA_RANK_QPHEADER - 1) #define VMCI_SEMA_RANK_GUESTMEM (VMCI_SEMA_RANK_QUEUEPAIRLIST - 1) -#define VMCI_SEMA_RANK_PACKET_QP (VMCI_SEMA_RANK_QPHEADER - 1) -//#define VMCI_SEMA_RANK_PACKET_QP 0xffd /* For vVol */ /* * Host specific struct used for signalling. diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmblock/linux/filesystem.c open-vm-tools-2012.05.21-724730/modules/linux/vmblock/linux/filesystem.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmblock/linux/filesystem.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmblock/linux/filesystem.c 2012-05-22 15:12:52.000000000 -0500 @@ -28,8 +28,8 @@ #include #include #include -#include +#include "compat_fs.h" #include "compat_namei.h" #include "os.h" @@ -525,9 +525,8 @@ FsOpReadSuper(struct super_block *sb, // return -EINVAL; } - rootDentry = d_alloc_root(rootInode); + rootDentry = d_make_root(rootInode); if (!rootDentry) { - iput(rootInode); return -ENOMEM; } sb->s_root = rootDentry; diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciCommonInt.h open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciCommonInt.h --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciCommonInt.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciCommonInt.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2006-2012 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 @@ -26,7 +26,6 @@ #define _VMCI_COMMONINT_H_ #define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" @@ -38,7 +37,6 @@ #include "vmci_handle_array.h" #include "vmci_kernel_if.h" - /* * The DatagramQueueEntry is a queue header for the in-kernel VMCI * datagram queues. It is allocated in non-paged memory, as the @@ -55,6 +53,20 @@ typedef struct DatagramQueueEntry { } DatagramQueueEntry; +/* + * The VMCIFilterState captures the state of all VMCI filters in one + * direction. The ranges array contains all filter list in a single + * memory chunk, and the filter list pointers in the VMCIProtoFilters + * point into the ranges array. + */ + +typedef struct VMCIFilterState { + VMCIProtoFilters filters; + VMCIIdRange *ranges; + size_t rangesSize; +} VMCIFilterState; + + struct VMCIContext { VMCIListItem listItem; /* For global VMCI list. */ VMCIId cid; @@ -66,7 +78,11 @@ struct VMCIContext { * Version of the code that created * this context; e.g., VMX. */ - VMCILock lock; /* Locks callQueue and handleArrays. */ + VMCILock lock; /* + * Locks datagramQueue, inFilters, + * doorbellArray, pendingDoorbellArray + * and notifierArray. + */ VMCIHandleArray *queuePairArray; /* * QueuePairs attached to. The array of * handles for queue pairs is accessed @@ -75,7 +91,7 @@ struct VMCIContext { * is also accessed from the context * clean up path, which does not * require a lock. VMCILock is not - * used to protect the QP array field. + * used to protect the QP array. */ VMCIHandleArray *doorbellArray; /* Doorbells created by context. */ VMCIHandleArray *pendingDoorbellArray; /* Doorbells pending for context. */ @@ -92,6 +108,7 @@ struct VMCIContext { * registration/release during FSR. */ VMCIGuestMemID curGuestMemID; /* ID of current registered guest mem */ + VMCIFilterState *inFilters; /* Ingoing filters for VMCI traffic. */ #endif #ifndef VMX86_SERVER Bool *notify; /* Notify flag pointer - hosted only. */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciContext.c open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciContext.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciContext.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciContext.c 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2006-2012 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 @@ -49,6 +49,7 @@ static int VMCIContextFireNotification(V #if defined(VMKERNEL) static void VMCIContextReleaseGuestMemLocked(VMCIContext *context, VMCIGuestMemID gid); +static void VMCIContextInFilterCleanup(VMCIContext *context); #endif /* @@ -331,6 +332,8 @@ VMCIContext_InitContext(VMCIId cid, goto error; } context->curGuestMemID = INVALID_VMCI_GUEST_MEM_ID; + + context->inFilters = NULL; #endif /* Inititialize host-specific VMCI context. */ @@ -482,7 +485,7 @@ VMCIContextFreeContext(VMCIContext *cont } /* - * It is fine to destroy this without locking the callQueue, as + * It is fine to destroy this without locking the datagramQueue, as * this is the only thread having a reference to the context. */ @@ -501,6 +504,7 @@ VMCIContextFreeContext(VMCIContext *cont VMCIHandleArray_Destroy(context->pendingDoorbellArray); VMCI_CleanupLock(&context->lock); #if defined(VMKERNEL) + VMCIContextInFilterCleanup(context); VMCIMutex_Destroy(&context->guestMemMutex); #endif VMCIHost_ReleaseContext(&context->hostContext); @@ -606,6 +610,18 @@ VMCIContext_EnqueueDatagram(VMCIId cid, VMCIList_InitEntry(&dqEntry->listItem); VMCI_GrabLock(&context->lock, &flags); + +#if defined(VMKERNEL) + if (context->inFilters != NULL) { + if (VMCIFilterDenyDgIn(context->inFilters->filters, dg)) { + VMCI_ReleaseLock(&context->lock, flags); + VMCIContext_Release(context); + VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); + return VMCI_ERROR_NO_ACCESS; + } + } +#endif + /* * We put a higher limit on datagrams from the hypervisor. If the pending * datagram is not from hypervisor, then we check if enqueueing it would @@ -1993,6 +2009,13 @@ VMCIContext_NotifyDoorbell(VMCIId srcCID } else { VMCI_GrabLock(&dstContext->lock, &flags); +#if defined(VMKERNEL) + if (dstContext->inFilters != NULL && + VMCIFilterProtoDeny(dstContext->inFilters->filters, handle.resource, + VMCI_FP_DOORBELL)) { + result = VMCI_ERROR_NO_ACCESS; + } else +#endif // VMKERNEL if (!VMCIHandleArray_HasEntry(dstContext->doorbellArray, handle)) { result = VMCI_ERROR_NOT_FOUND; } else { @@ -2270,21 +2293,18 @@ int VMCIContext_QueuePairCreate(VMCIContext *context, // IN: Context structure VMCIHandle handle) // IN { - VMCILockFlags flags; int result; if (context == NULL || VMCI_HANDLE_INVALID(handle)) { return VMCI_ERROR_INVALID_ARGS; } - VMCI_GrabLock(&context->lock, &flags); if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) { VMCIHandleArray_AppendEntry(&context->queuePairArray, handle); result = VMCI_SUCCESS; } else { result = VMCI_ERROR_DUPLICATE_ENTRY; } - VMCI_ReleaseLock(&context->lock, flags); return result; } @@ -2311,16 +2331,13 @@ int VMCIContext_QueuePairDestroy(VMCIContext *context, // IN: Context structure VMCIHandle handle) // IN { - VMCILockFlags flags; VMCIHandle removedHandle; if (context == NULL || VMCI_HANDLE_INVALID(handle)) { return VMCI_ERROR_INVALID_ARGS; } - VMCI_GrabLock(&context->lock, &flags); removedHandle = VMCIHandleArray_RemoveEntry(context->queuePairArray, handle); - VMCI_ReleaseLock(&context->lock, flags); if (VMCI_HANDLE_INVALID(removedHandle)) { return VMCI_ERROR_NOT_FOUND; @@ -2351,16 +2368,13 @@ Bool VMCIContext_QueuePairExists(VMCIContext *context, // IN: Context structure VMCIHandle handle) // IN { - VMCILockFlags flags; Bool result; if (context == NULL || VMCI_HANDLE_INVALID(handle)) { return VMCI_ERROR_INVALID_ARGS; } - VMCI_GrabLock(&context->lock, &flags); result = VMCIHandleArray_HasEntry(context->queuePairArray, handle); - VMCI_ReleaseLock(&context->lock, flags); return result; } @@ -2540,3 +2554,87 @@ VMCIContext_ReleaseGuestMem(VMCIContext VMCIMutex_Release(&context->guestMemMutex); #endif } + +#if defined(VMKERNEL) + +/* + *---------------------------------------------------------------------- + * + * VMCIContext_FilterSet -- + * + * Sets an ingoing (host to guest) filter for the VMCI firewall of the + * given context. If a filter list already exists for the given filter + * entry, the old entry will be deleted. It is assumed that the list + * can be used as is, and that the memory backing it will be freed by the + * VMCI Context module once the filter is deleted. + * + * Results: + * VMCI_SUCCESS on success, + * VMCI_ERROR_NOT_FOUND if there is no active context linked to the cid, + * VMCI_ERROR_INVALID_ARGS if a non-VM cid is specified. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VMCIContext_FilterSet(VMCIId cid, // IN + VMCIFilterState *filters) // IN +{ + VMCIContext *context; + VMCILockFlags flags; + VMCIFilterState *oldState; + + if (!VMCI_CONTEXT_IS_VM(cid)) { + return VMCI_ERROR_INVALID_ARGS; + } + + context = VMCIContext_Get(cid); + if (!context) { + return VMCI_ERROR_NOT_FOUND; + } + + VMCI_GrabLock(&context->lock, &flags); + + oldState = context->inFilters; + context->inFilters = filters; + + VMCI_ReleaseLock(&context->lock, flags); + if (oldState) { + VMCIVMKDevFreeFilterState(oldState); + } + VMCIContext_Release(context); + + return VMCI_SUCCESS; +} + + +/* + *---------------------------------------------------------------------- + * + * VMCIContextInFilterCleanup -- + * + * When a context is destroyed, all filters will be deleted. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +VMCIContextInFilterCleanup(VMCIContext *context) +{ + if (context->inFilters != NULL) { + VMCIVMKDevFreeFilterState(context->inFilters); + context->inFilters = NULL; + } +} + +#endif + diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciContext.h open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciContext.h --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciContext.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciContext.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2006-2012 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 @@ -36,6 +36,7 @@ #include "vmci_handle_array.h" #include "vmci_infrastructure.h" #include "vmci_kernel_if.h" +#include "vmciCommonInt.h" #define MAX_QUEUED_GUESTCALLS_PER_VM 100 @@ -115,6 +116,6 @@ void VMCIContext_SignalPendingDoorbells( void VMCIContext_SignalPendingDatagrams(VMCIId contextID); int VMCIContextID2HostVmID(VMCIId contextID, void *hostVmID, size_t hostVmIDLen); +int VMCIContext_FilterSet(VMCIId cid, VMCIFilterState *filterState); #endif - #endif // _VMCI_CONTEXT_H_ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciDriver.c open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciDriver.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciDriver.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciDriver.c 2012-05-22 15:12:52.000000000 -0500 @@ -90,7 +90,7 @@ VMCI_HostInit(void) goto hostContextExit; } - VMCI_LOG((LGPFX"host components initialized.\n")); + VMCI_DEBUG_LOG(0, (LGPFX"host components initialized.\n")); return VMCI_SUCCESS; hostContextExit: @@ -365,7 +365,12 @@ VMCI_CheckHostCapabilities(void) result &= VMCIDatagram_CheckHostCapabilities(); result &= VMCIUtilCheckHostCapabilities(); - VMCI_LOG((LGPFX"Host capability check: %s.\n", result ? "PASSED" : "FAILED")); + if (!result) { + /* If it failed, then make sure this goes to the system event log. */ + VMCI_WARNING((LGPFX"Host capability checked failed.\n")); + } else { + VMCI_DEBUG_LOG(0, (LGPFX"Host capability check passed.\n")); + } return result; } @@ -635,7 +640,7 @@ VMCI_SharedInit(void) goto eventExit; } - VMCI_LOG((LGPFX"shared components initialized.\n")); + VMCI_DEBUG_LOG(0, (LGPFX"shared components initialized.\n")); return VMCI_SUCCESS; eventExit: diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciPageChannel.c open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciPageChannel.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciPageChannel.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciPageChannel.c 2012-05-22 15:12:52.000000000 -0500 @@ -43,16 +43,45 @@ #define VMCI_PACKET_RECV_THRESHOLD 150 +/* + * Maximum number of elements per DGRAM packet (for setting receive buffers). + */ + +#define VMCI_PACKET_DGRAM_MAX_ELEMS \ + ((VMCI_MAX_DG_PAYLOAD_SIZE - sizeof(VPageChannelPacket)) / \ + sizeof(VPageChannelElem)) + +/* + * Maximum number of elements in a PAGE-sized packet (as above). + */ + +#define VMCI_PACKET_PAGE_MAX_ELEMS \ + ((PAGE_SIZE - sizeof(VPageChannelPacket)) / \ + sizeof(VPageChannelElem)) + +/* + * All flags. We use this to check the validity of the flags, so put it here + * instead of in the header, otherwise people might assume we mean for them + * to use it. + */ + +#define VPAGECHANNEL_FLAGS_ALL \ + (VPAGECHANNEL_FLAGS_NOTIFY_ONLY | \ + VPAGECHANNEL_FLAGS_RECV_DELAYED | \ + VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC) + /* * Page channel. This is opaque to clients. */ struct VPageChannel { + VPageChannelState state; + VMCIHandle dgHandle; + uint32 flags; VPageChannelRecvCB recvCB; void *clientRecvData; - Bool notifyOnly; VPageChannelAllocElemFn elemAllocFn; void *allocClientData; VPageChannelFreeElemFn elemFreeFn; @@ -68,9 +97,11 @@ struct VPageChannel { uint64 consumeQSize; VMCIId attachSubId; VMCIId detachSubId; - Bool qpConnected; - VMCIMutex qpRecvMutex; - VMCIMutex qpSendMutex; + Bool useSpinLock; + spinlock_t qpRecvLock; + spinlock_t qpSendLock; + struct semaphore qpRecvMutex; + struct semaphore qpSendMutex; /* * Doorbell info. @@ -83,7 +114,7 @@ struct VPageChannel { * Receiving buffer. */ - int curRecvBufs; + Atomic_Int curRecvBufs; int recvBufsTarget; int defaultRecvBufs; int maxRecvBufs; @@ -96,11 +127,13 @@ struct VPageChannel { static int VPageChannelSendControl(VPageChannel *channel, - char *message, - int len, VPageChannelPacketType type, - int numElems, + char *message, int len, int numElems, VPageChannelElem *elems); +static int VPageChannelSignal(VPageChannel *channel); +static int VPageChannelSendPacket(VPageChannel *channel, + VPageChannelPacket *packet, + Bool needsLock, Bool signalPending); /* *----------------------------------------------------------------------------- @@ -119,10 +152,17 @@ static int VPageChannelSendControl(VPage */ static void -VPageChannelAcquireSendLock(VPageChannel *channel) // IN +VPageChannelAcquireSendLock(VPageChannel *channel, // IN + unsigned long *flags) // OUT { ASSERT(channel); - VMCIMutex_Acquire(&channel->qpSendMutex); + + *flags = 0; /* Make compiler happy about it being unused in some paths. */ + if (channel->useSpinLock) { + spin_lock_irqsave(&channel->qpSendLock, *flags); + } else { + down(&channel->qpSendMutex); + } } @@ -143,10 +183,16 @@ VPageChannelAcquireSendLock(VPageChannel */ static void -VPageChannelReleaseSendLock(VPageChannel *channel) // IN +VPageChannelReleaseSendLock(VPageChannel *channel, // IN + unsigned long flags) // IN { ASSERT(channel); - VMCIMutex_Release(&channel->qpSendMutex); + + if (channel->useSpinLock) { + spin_unlock_irqrestore(&channel->qpSendLock, flags); + } else { + up(&channel->qpSendMutex); + } } @@ -167,10 +213,18 @@ VPageChannelReleaseSendLock(VPageChannel */ static void -VPageChannelAcquireRecvLock(VPageChannel *channel) // IN +VPageChannelAcquireRecvLock(VPageChannel *channel, // IN + unsigned long *flags) // OUT { ASSERT(channel); - VMCIMutex_Acquire(&channel->qpRecvMutex); + ASSERT(flags); + + *flags = 0; /* Make compiler happy about it being unused in some paths. */ + if (channel->useSpinLock) { + spin_lock_irqsave(&channel->qpRecvLock, *flags); + } else { + down(&channel->qpRecvMutex); + } } @@ -191,22 +245,37 @@ VPageChannelAcquireRecvLock(VPageChannel */ static void -VPageChannelReleaseRecvLock(VPageChannel *channel) // IN +VPageChannelReleaseRecvLock(VPageChannel *channel, // IN + unsigned long flags) // IN { ASSERT(channel); - VMCIMutex_Release(&channel->qpRecvMutex); + + if (channel->useSpinLock) { + spin_unlock_irqrestore(&channel->qpRecvLock, flags); + } else { + up(&channel->qpRecvMutex); + } } /* *----------------------------------------------------------------------------- * - * VPageChannelSetRecvBuffers -- + * VPageChannelAddRecvBuffers -- * - * Set the receiving buffers for the channel. + * Add receiving buffers for the channel. This will ask the client to + * to allocate the required elements and then pass those to the peer. + * + * If "onInit" is TRUE (which is is during channel initialization) then + * the DGRAM control channel will be used, and multiple packets will be + * sent if necessary. Also, the packet allocation will be blocking. + * + * If "onInit" is FALSE, then the queuepair will be used, multiple + * packets may be sent, and the packet allocation may be atomic, + * depending on how the channel is configured. * * Results: - * VMCI_SUCCESS if set, negative error code otherwise. + * The number of buffers actually sent to the peer. * * Side effects: * None. @@ -215,74 +284,156 @@ VPageChannelReleaseRecvLock(VPageChannel */ static int -VPageChannelSetRecvBuffers(VPageChannel *channel, // IN +VPageChannelAddRecvBuffers(VPageChannel *channel, // IN int numElems, // IN - Bool byControl) // IN + Bool onInit) // IN { - int retval; - int allocNum; - size_t size = sizeof(VPageChannelPacket) + - numElems * sizeof(VPageChannelElem); + int n; + int sent; + int maxElems; + Bool isAtomic; + size_t size; + unsigned long flags; VPageChannelElem *elems; VPageChannelPacket *packet; ASSERT(channel); - packet = (VPageChannelPacket *)VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC); - if (packet == NULL) { - VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) " - "(size=%"FMTSZ"u).\n", - channel, - size)); - return VMCI_ERROR_NO_MEM; - } + sent = 0; + size = 0; + elems = NULL; + packet = NULL; - packet->type = VPCPacket_SetRecvBuffer; - packet->msgLen = 0; - packet->numElems = numElems; - - elems = VPAGECHANNEL_PACKET_ELEMS(packet); - allocNum = channel->elemAllocFn(channel->allocClientData, elems, numElems); - if (allocNum != numElems) { - VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) " - "(expected=%d) (actual=%d).\n", - channel, - numElems, - allocNum)); - retval = VMCI_ERROR_NO_MEM; - goto error; - } + if (onInit || (channel->flags & VPAGECHANNEL_FLAGS_RECV_DELAYED)) { + /* + * If we are initializing the channel, or we are running in a delayed + * context (recv() in this case), then we can using blocking allocation + * and we can allocate large packets. Also, no need to take the + * send lock here, we can just take it for each packet. + */ - if (byControl || !channel->qpConnected) { - retval = VPageChannelSendControl(channel, NULL, 0, - VPCPacket_SetRecvBuffer, - numElems, elems); + isAtomic = FALSE; + maxElems = VMCI_PACKET_DGRAM_MAX_ELEMS; + flags = 0; /* Silence compiler. */ } else { - retval = VPageChannel_SendPacket(channel, packet); - } - if (retval < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) " - "(err=%d).\n", - channel, - retval)); - goto error; + /* + * We're in an atomic context. We must allocate page-sized packets + * atomically and send them over the queuepair. Since this can + * cause a lot of signalling, we optimize by taking the send lock + * once for all packets, and only signalling when we are done. + */ + + isAtomic = TRUE; + maxElems = VMCI_PACKET_PAGE_MAX_ELEMS; + VPageChannelAcquireSendLock(channel, &flags); } - channel->curRecvBufs += numElems; + n = min_t(int, maxElems, numElems); + while (n > 0) { + int retval; + int allocNum; - VMCI_FreeKernelMem(packet, size); + /* + * First packet is always big enough to cover any remaining elements, + * so just allocate it once. + */ - return VMCI_SUCCESS; + if (NULL == packet) { + size = sizeof(VPageChannelPacket) + (n * sizeof(VPageChannelElem)); + packet = (VPageChannelPacket *) + VMCI_AllocKernelMem(size, + isAtomic ? VMCI_MEMORY_ATOMIC : VMCI_MEMORY_NORMAL); + if (packet == NULL) { + VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) " + "(size=%"FMTSZ"u).\n", + channel, + size)); + goto exit; + } + + packet->type = VPCPacket_SetRecvBuffer; + packet->msgLen = 0; + elems = VPAGECHANNEL_PACKET_ELEMS(packet); + } - error: - if (packet != NULL) { - if (allocNum) { + allocNum = channel->elemAllocFn(channel->allocClientData, elems, n); + if (0 == allocNum) { + /* + * If the client failed to allocate any elements at all then just + * bail out and return whatever number we managed to send so far + * (if any). + */ + + VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) " + "(expected=%d).\n", + channel, + n)); + goto exit; + } + + /* + * We wanted "n" elements, but we might only have "allocNum" because + * that's all the client could allocate. Pass down whatever we got. + */ + + packet->numElems = allocNum; + + if (onInit) { + retval = VPageChannelSendControl(channel, VPCPacket_SetRecvBuffer, + NULL, 0, allocNum, elems); + } else { + /* + * Do not ask for the lock here if we are atomic, we take care of + * that ourselves. Similarly, if we are atomic then we will do our + * own signalling, so inform the send that there is a signal already + * pending. + */ + + retval = VPageChannelSendPacket(channel, packet, + isAtomic ? FALSE : TRUE, // needsLock + isAtomic ? TRUE : FALSE); // signalPending + /* + * XXX, what if this is a non-blocking queuepair and we fail to + * send because it's full and we can't wait? Is it even worth it + * to loop? + */ + } + if (retval < VMCI_SUCCESS) { + /* + * Failure to send is fatal. Release the client's elements and + * bail out. + */ + + VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) " + "(err=%d).\n", + channel, + retval)); channel->elemFreeFn(channel->freeClientData, elems, allocNum); + goto exit; } - VMCI_FreeKernelMem(packet, size); + + Atomic_Add32(&channel->curRecvBufs, allocNum); + + sent += allocNum; + numElems -= allocNum; + n = min_t(int, maxElems, numElems); } - return retval; +exit: + if (isAtomic) { + /* + * We're done sending packets, so now we can signal. Even if we only + * sent some of the requested buffers, we must signal anyway, otherwise + * the peer won't know about the ones we did send. + */ + + (void)VPageChannelSignal(channel); + VPageChannelReleaseSendLock(channel, flags); + } + if (NULL != packet) { + VMCI_FreeKernelMem(packet, size); + } + return sent; } @@ -306,6 +457,7 @@ static int VPageChannelRecvPacket(VPageChannel *channel, // IN VPageChannelPacket *packet) // IN { + int curRecvBufs; int recvBufsTarget; ASSERT(channel); @@ -314,7 +466,8 @@ VPageChannelRecvPacket(VPageChannel *cha if (packet->type != VPCPacket_Data && packet->type != VPCPacket_Completion_Notify && packet->type != VPCPacket_RequestBuffer && - packet->type != VPCPacket_HyperConnect) { + packet->type != VPCPacket_HyperConnect && + packet->type != VPCPacket_HyperDisconnect) { VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) " "(type=%d).\n", channel, @@ -367,7 +520,7 @@ VPageChannelRecvPacket(VPageChannel *cha (LGPFX"Requested more buffers (channel=%p) " "(cur=%d) (target=%d) (max=%d).\n", channel, - channel->curRecvBufs, + Atomic_Read32(&channel->curRecvBufs), channel->recvBufsTarget, channel->maxRecvBufs)); @@ -378,13 +531,32 @@ VPageChannelRecvPacket(VPageChannel *cha case VPCPacket_Data: channel->recvCB(channel->clientRecvData, packet); - channel->curRecvBufs -= packet->numElems; + Atomic_Sub32(&channel->curRecvBufs, packet->numElems); + ASSERT(Atomic_Read32(&channel->curRecvBufs) > 0); break; case VPCPacket_Completion_Notify: channel->recvCB(channel->clientRecvData, packet); break; + case VPCPacket_HyperDisconnect: + VMCI_DEBUG_LOG(10, + (LGPFX"Hypervisor requested disconnection " + "(channel=%p) (numElems=%d).\n", + channel, + packet->numElems)); + if (packet->numElems > 0) { + channel->elemFreeFn(channel->freeClientData, + VPAGECHANNEL_PACKET_ELEMS(packet), + packet->numElems); + } + (void)VPageChannelSendControl(channel, VPCPacket_GuestDisconnect, + NULL, 0, 0, NULL); + if (channel->state < VPCState_Disconnecting) { + channel->state = VPCState_Disconnecting; + } + return VMCI_SUCCESS; + default: ASSERT_NOT_IMPLEMENTED(FALSE); break; @@ -398,14 +570,12 @@ VPageChannelRecvPacket(VPageChannel *cha * in the hope that we won't hit this again. */ - if (channel->curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) { - int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD - - channel->curRecvBufs; - - if (VPageChannelSetRecvBuffers(channel, numElems, FALSE) == - VMCI_SUCCESS) { - channel->recvBufsTarget = recvBufsTarget; - } + curRecvBufs = Atomic_Read32(&channel->curRecvBufs); + if (curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) { + int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD - curRecvBufs; + + (void)VPageChannelAddRecvBuffers(channel, numElems, FALSE); + channel->recvBufsTarget = recvBufsTarget; } return VMCI_SUCCESS; @@ -464,7 +634,7 @@ VPageChannelDgRecvFunc(void *clientData, /* *---------------------------------------------------------------------------- * - * VMCIPacketDoDoorbellCallback -- + * VPageChannelDoDoorbellCallback * * Process a doorbell notification. Will read packets from the queuepair * until empty. @@ -482,23 +652,24 @@ VPageChannelDgRecvFunc(void *clientData, */ static void -VMCIPacketDoDoorbellCallback(VPageChannel *channel) // IN/OUT +VPageChannelDoDoorbellCallback(VPageChannel *channel) // IN/OUT { Bool inUse; + unsigned long flags; VPageChannelPacket packetHeader; ASSERT(channel); - if (!channel->qpConnected) { + if (VPCState_Connected != channel->state) { VMCI_WARNING((LGPFX"Not connected (channel=%p).\n", channel)); return; } - VPageChannelAcquireRecvLock(channel); + VPageChannelAcquireRecvLock(channel, &flags); inUse = channel->inPoll; channel->inPoll = TRUE; - VPageChannelReleaseRecvLock(channel); + VPageChannelReleaseRecvLock(channel, flags); if (inUse) { return; @@ -579,7 +750,7 @@ retry: VMCI_FreeKernelMem(packet, totalSize); } - VPageChannelAcquireRecvLock(channel); + VPageChannelAcquireRecvLock(channel, &flags); /* * The doorbell may have been notified between when we we finished reading @@ -590,19 +761,19 @@ retry: */ if (VMCIQPair_ConsumeBufReady(channel->qpair) >= sizeof packetHeader) { - VPageChannelReleaseRecvLock(channel); + VPageChannelReleaseRecvLock(channel, flags); goto retry; } channel->inPoll = FALSE; - VPageChannelReleaseRecvLock(channel); + VPageChannelReleaseRecvLock(channel, flags); } /* *---------------------------------------------------------------------------- * - * VMCIPacketDoorbellCallback -- + * VPageChannelDoorbellCallback -- * * Callback for doorbell notification. Will invoke the channel's receive * function directly or process the packets in the queuepair. @@ -617,16 +788,16 @@ retry: */ static void -VMCIPacketDoorbellCallback(void *clientData) // IN/OUT +VPageChannelDoorbellCallback(void *clientData) // IN/OUT { VPageChannel *channel = (VPageChannel *)clientData; ASSERT(channel); - if (channel->notifyOnly) { + if (channel->flags & VPAGECHANNEL_FLAGS_NOTIFY_ONLY) { channel->recvCB(channel->clientRecvData, NULL); } else { - VMCIPacketDoDoorbellCallback(channel); + VPageChannelDoDoorbellCallback(channel); } } @@ -654,6 +825,8 @@ VPageChannelSendConnectionMessage(VPageC ASSERT(channel); + channel->state = VPCState_Connecting; + memset(&message, 0, sizeof message); message.dgHandle = channel->dgHandle; message.qpHandle = channel->qpHandle; @@ -668,16 +841,15 @@ VPageChannelSendConnectionMessage(VPageC channel->qpHandle.context, channel->qpHandle.resource)); - return VPageChannelSendControl(channel, - (char *)&message, sizeof message, - VPCPacket_GuestConnect, 0, NULL); + return VPageChannelSendControl(channel, VPCPacket_GuestConnect, + (char *)&message, sizeof message, 0, NULL); } /* *---------------------------------------------------------------------------- * - * VMCIPacketPeerAttachCB -- + * VPageChannelPeerAttachCB -- * * Invoked when a peer attaches to a queue pair. * @@ -711,7 +883,7 @@ VPageChannelPeerAttachCB(VMCIId subId, channel, ePayload->handle.context, ePayload->handle.resource)); - channel->qpConnected = TRUE; + channel->state = VPCState_Connected; } } @@ -719,7 +891,7 @@ VPageChannelPeerAttachCB(VMCIId subId, /* *---------------------------------------------------------------------------- * - * VMCIPacketPeerDetachCB -- + * VPageChannelPeerDetachCB -- * * Invoked when a peer detaches from a queue pair. * @@ -753,7 +925,7 @@ VPageChannelPeerDetachCB(VMCIId subId, channel, ePayload->handle.context, ePayload->handle.resource)); - channel->qpConnected = FALSE; + channel->state = VPCState_Disconnected; } } @@ -796,10 +968,7 @@ VPageChannelDestroyQueuePair(VPageChanne channel->qpair = NULL; } - VMCIMutex_Destroy(&channel->qpRecvMutex); - VMCIMutex_Destroy(&channel->qpSendMutex); - - channel->qpConnected = FALSE; + channel->state = VPCState_Disconnected; } @@ -831,21 +1000,14 @@ VPageChannelCreateQueuePair(VPageChannel ASSERT(VMCI_INVALID_ID == channel->detachSubId); ASSERT(VMCI_INVALID_ID == channel->attachSubId); - err = VMCIMutex_Init(&channel->qpSendMutex, "VMCIPacketSendMutex", - VMCI_SEMA_RANK_PACKET_QP); - if (err < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize send mutex (channel=%p).\n", - channel)); - return err; - } - - err = VMCIMutex_Init(&channel->qpRecvMutex, "VMCIPacketRecvMutex", - VMCI_SEMA_RANK_PACKET_QP); - if (err < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize revc mutex (channel=%p).\n", - channel)); - VMCIMutex_Destroy(&channel->qpSendMutex); - return err; + if (channel->flags & VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC || + !(channel->flags & VPAGECHANNEL_FLAGS_RECV_DELAYED)) { + channel->useSpinLock = TRUE; + spin_lock_init(&channel->qpSendLock); + spin_lock_init(&channel->qpRecvLock); + } else { + sema_init(&channel->qpSendMutex, 1); + sema_init(&channel->qpRecvMutex, 1); } err = VMCIEvent_Subscribe(VMCI_EVENT_QP_PEER_ATTACH, @@ -872,7 +1034,11 @@ VPageChannelCreateQueuePair(VPageChannel goto error; } - flags = 0; + if (channel->useSpinLock) { + flags = VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED; + } else { + flags = 0; + } err = VMCIQPair_Alloc(&channel->qpair, &channel->qpHandle, channel->produceQSize, channel->consumeQSize, VMCI_HOST_CONTEXT_ID, flags, VMCI_NO_PRIVILEGE_FLAGS); @@ -922,9 +1088,9 @@ VPageChannel_CreateInVM(VPageChannel **c VMCIId peerResourceId, // IN uint64 produceQSize, // IN uint64 consumeQSize, // IN + uint32 channelFlags, // IN VPageChannelRecvCB recvCB, // IN void *clientRecvData, // IN - Bool notifyOnly, // IN VPageChannelAllocElemFn elemAllocFn, // IN void *allocClientData, // IN VPageChannelFreeElemFn elemFreeFn, // IN @@ -941,9 +1107,16 @@ VPageChannel_CreateInVM(VPageChannel **c ASSERT(VMCI_INVALID_ID != peerResourceId); ASSERT(recvCB); + if (channelFlags & ~(VPAGECHANNEL_FLAGS_ALL)) { + VMCI_WARNING((LGPFX"Invalid argument (flags=0x%x).\n", + channelFlags)); + return VMCI_ERROR_INVALID_ARGS; + } + pageChannel = VMCI_AllocKernelMem(sizeof *pageChannel, VMCI_MEMORY_NONPAGED); if (!pageChannel) { + VMCI_WARNING((LGPFX"Failed to allocate channel memory.\n")); return VMCI_ERROR_NO_MEM; } @@ -952,6 +1125,7 @@ VPageChannel_CreateInVM(VPageChannel **c */ memset(pageChannel, 0, sizeof *pageChannel); + pageChannel->state = VPCState_Unconnected; pageChannel->dgHandle = VMCI_INVALID_HANDLE; pageChannel->attachSubId = VMCI_INVALID_ID; pageChannel->detachSubId = VMCI_INVALID_ID; @@ -959,10 +1133,9 @@ VPageChannel_CreateInVM(VPageChannel **c pageChannel->qpair = NULL; pageChannel->doorbellHandle = VMCI_INVALID_HANDLE; pageChannel->peerDoorbellHandle = VMCI_INVALID_HANDLE; - pageChannel->qpConnected = FALSE; + pageChannel->flags = channelFlags; pageChannel->recvCB = recvCB; pageChannel->clientRecvData = clientRecvData; - pageChannel->notifyOnly = notifyOnly; pageChannel->elemAllocFn = elemAllocFn; pageChannel->allocClientData = allocClientData; pageChannel->elemFreeFn = elemFreeFn; @@ -970,7 +1143,7 @@ VPageChannel_CreateInVM(VPageChannel **c pageChannel->resourceId = resourceId; pageChannel->peerDgHandle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID, peerResourceId); - pageChannel->curRecvBufs = 0; + Atomic_Write32(&pageChannel->curRecvBufs, 0); pageChannel->recvBufsTarget = defaultRecvBuffers; pageChannel->defaultRecvBufs = defaultRecvBuffers; pageChannel->maxRecvBufs = maxRecvBuffers + VMCI_PACKET_RECV_THRESHOLD; @@ -980,6 +1153,8 @@ VPageChannel_CreateInVM(VPageChannel **c /* * Create a datagram handle over which we will connection handshake packets * (once the queuepair is created we can send packets over that instead). + * This handle has a delayed callback regardless of the channel flags, + * because we may have to create a queuepair inside the callback. */ flags = VMCI_FLAG_DG_DELAYED_CB; @@ -1003,13 +1178,15 @@ VPageChannel_CreateInVM(VPageChannel **c /* * Create a doorbell handle. This is used by the peer to signal the - * arrival of packets in the queuepair. + * arrival of packets in the queuepair. This handle has a delayed + * callback depending on the channel flags. */ + flags = channelFlags & VPAGECHANNEL_FLAGS_RECV_DELAYED ? + VMCI_FLAG_DELAYED_CB : 0; retval = VMCIDoorbell_Create(&pageChannel->doorbellHandle, - VMCI_FLAG_DELAYED_CB, - VMCI_PRIVILEGE_FLAG_RESTRICTED, - VMCIPacketDoorbellCallback, pageChannel); + flags, VMCI_PRIVILEGE_FLAG_RESTRICTED, + VPageChannelDoorbellCallback, pageChannel); if (retval < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Failed to create doorbell " "(channel=%p) (err=%d).\n", @@ -1042,8 +1219,13 @@ VPageChannel_CreateInVM(VPageChannel **c if (defaultRecvBuffers) { int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD; - retval = VPageChannelSetRecvBuffers(pageChannel, numElems, TRUE); - if (retval < VMCI_SUCCESS) { + if (0 == VPageChannelAddRecvBuffers(pageChannel, numElems, TRUE)) { + /* + * AddRecvBuffers() returns the number of buffers actually added. If + * we failed to add any at all, then fail. + */ + + retval = VMCI_ERROR_NO_MEM; goto error; } } @@ -1101,6 +1283,7 @@ VPageChannel_Destroy(VPageChannel *chann VMCIDatagram_DestroyHnd(channel->dgHandle); } + channel->state = VPCState_Free; VMCI_FreeKernelMem(channel, sizeof *channel); VMCI_DEBUG_LOG(10, @@ -1113,7 +1296,7 @@ EXPORT_SYMBOL(VPageChannel_Destroy); /* *----------------------------------------------------------------------------- * - * VMCIPacketAllocDatagram -- + * VPageChannelAllocDatagram -- * * Allocate a datagram for the packet. This is only used until the * connection is made; after that, packets are passed over the queuepair. @@ -1200,9 +1383,9 @@ VPageChannelAllocDatagram(VPageChannel * static int VPageChannelSendControl(VPageChannel *channel, // IN + VPageChannelPacketType type, // IN char *message, // IN int len, // IN - VPageChannelPacketType type, // IN int numElems, // IN VPageChannelElem *elems) // IN { @@ -1213,7 +1396,8 @@ VPageChannelSendControl(VPageChannel *ch ASSERT(channel); ASSERT(type == VPCPacket_Data || type == VPCPacket_GuestConnect || - type == VPCPacket_SetRecvBuffer); + type == VPCPacket_SetRecvBuffer || + type == VPCPacket_GuestDisconnect); dg = NULL; retval = VPageChannelAllocDatagram(channel, len, numElems, &dg); @@ -1263,6 +1447,45 @@ VPageChannelSendControl(VPageChannel *ch /* *----------------------------------------------------------------------------- * + * VPageChannelSignal -- + * + * Signal the channel's peer via the doorbell. + * + * Results: + * VMCI_SUCCESS if signalled, negative error number otherwise. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +VPageChannelSignal(VPageChannel *channel) // IN +{ + int retval; + + ASSERT(channel); + + retval = VMCIDoorbell_Notify(channel->peerDoorbellHandle, + /* XXX, TRUSTED for VMKernel. */ + VMCI_PRIVILEGE_FLAG_RESTRICTED); + if (retval < VMCI_SUCCESS) { + VMCI_WARNING((LGPFX"Failed to notify doorbell (channel=%p) " + "(handle=0x%x:0x%x) (err=%d).\n", + channel, + channel->peerDoorbellHandle.context, + channel->peerDoorbellHandle.resource, + retval)); + } + + return retval; +} + + +/* + *----------------------------------------------------------------------------- + * * VPageChannel_SendPacket -- * * Send a VMCI packet to the hypervisor. @@ -1270,6 +1493,15 @@ VPageChannelSendControl(VPageChannel *ch * XXX, this is now identical to the function of the same name in * modules/vmkernel/vmci/vmciPacketVMK.c. We should share this code. * + * "needsLock" indicates whether this function should acquire the send + * lock. If TRUE, then it will be acquired; if FALSE, then it is the + * caller's responsibility. This is internal only. + * + * "signalPending" indicates whether the caller will take care of + * signalling/the caller knows that there is already a signal pending, + * in which case this function will not check for/send one. This is + * internal only, clients cannot specify this. + * * Results: * VMCI_SUCCESS if sent, negative error number otherwise. * @@ -1279,21 +1511,23 @@ VPageChannelSendControl(VPageChannel *ch *----------------------------------------------------------------------------- */ -int -VPageChannel_SendPacket(VPageChannel *channel, // IN - VPageChannelPacket *packet) // IN +static int +VPageChannelSendPacket(VPageChannel *channel, // IN + VPageChannelPacket *packet, // IN + Bool needsLock, // IN + Bool signalPending) // IN { int retval; - ssize_t totalSize, sentSize, curSize; + ssize_t totalSize, sentSize; ssize_t freeSpace; + unsigned long flags; ASSERT(channel); - if (!channel->qpConnected) { + if (VPCState_Connected != channel->state) { VMCI_WARNING((LGPFX"Not connected (channel=%p).\n", channel)); - retval = VMCI_ERROR_DST_UNREACHABLE; - goto error; + return VMCI_ERROR_DST_UNREACHABLE; } ASSERT(packet); @@ -1301,7 +1535,11 @@ VPageChannel_SendPacket(VPageChannel *ch totalSize = sizeof(VPageChannelPacket) + packet->msgLen + packet->numElems * sizeof(VPageChannelElem); - VPageChannelAcquireSendLock(channel); + if (needsLock) { + VPageChannelAcquireSendLock(channel, &flags); + } else { + flags = 0; /* Silence compiler. */ + } freeSpace = VMCIQPair_ProduceFreeSpace(channel->qpair); if (freeSpace < totalSize) { @@ -1311,29 +1549,20 @@ VPageChannel_SendPacket(VPageChannel *ch totalSize, freeSpace)); retval = VMCI_ERROR_NO_MEM; - goto unlock; + goto exit; } sentSize = VMCIQPair_Enqueue(channel->qpair, packet, totalSize, 0); - curSize = VMCIQPair_ProduceBufReady(channel->qpair); - if (curSize == sentSize) { - retval = VMCIDoorbell_Notify(channel->peerDoorbellHandle, - /* XXX, TRUSTED for VMKernel. */ - VMCI_PRIVILEGE_FLAG_RESTRICTED); - if (retval < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to notify doorbell (channel=%p) " - "(handle=0x%x:0x%x) (err=%d).\n", - channel, - channel->peerDoorbellHandle.context, - channel->peerDoorbellHandle.resource, - retval)); - goto unlock; + if (!signalPending) { + if (sentSize == VMCIQPair_ProduceBufReady(channel->qpair)) { + retval = VPageChannelSignal(channel); + if (retval < VMCI_SUCCESS) { + goto exit; + } } } - VPageChannelReleaseSendLock(channel); - if (sentSize < totalSize) { /* * XXX, deal with partial sending. @@ -1345,7 +1574,7 @@ VPageChannel_SendPacket(VPageChannel *ch totalSize, sentSize)); retval = VMCI_ERROR_NO_MEM; - goto error; + goto exit; } VMCI_DEBUG_LOG(10, @@ -1353,13 +1582,41 @@ VPageChannel_SendPacket(VPageChannel *ch channel, sentSize)); - return VMCI_SUCCESS; + retval = VMCI_SUCCESS; -unlock: - VPageChannelReleaseSendLock(channel); -error: +exit: + if (needsLock) { + VPageChannelReleaseSendLock(channel, flags); + } return retval; } + + +/* + *----------------------------------------------------------------------------- + * + * VPageChannel_SendPacket -- + * + * Send a VMCI packet to the hypervisor. + * + * XXX, this is now identical to the function of the same name in + * modules/vmkernel/vmci/vmciPacketVMK.c. We should share this code. + * + * Results: + * VMCI_SUCCESS if sent, negative error number otherwise. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +VPageChannel_SendPacket(VPageChannel *channel, // IN + VPageChannelPacket *packet) // IN +{ + return VPageChannelSendPacket(channel, packet, TRUE, FALSE); +} EXPORT_SYMBOL(VPageChannel_SendPacket); @@ -1397,7 +1654,7 @@ VPageChannel_Send(VPageChannel *channel, ASSERT(channel); - if (!channel->qpConnected) { + if (VPCState_Connected != channel->state) { VMCI_WARNING((LGPFX"Not connected (channel=%p).\n", channel)); return VMCI_ERROR_DST_UNREACHABLE; @@ -1412,7 +1669,9 @@ VPageChannel_Send(VPageChannel *channel, totalSize = sizeof(VPageChannelPacket) + len + numElems * sizeof(VPageChannelElem); packet = (VPageChannelPacket *) - VMCI_AllocKernelMem(totalSize, VMCI_MEMORY_NORMAL); + VMCI_AllocKernelMem(totalSize, + channel->flags & VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC ? + VMCI_MEMORY_ATOMIC : VMCI_MEMORY_NORMAL); if (!packet) { VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) " "(size=%"FMTSZ"d).", @@ -1465,8 +1724,8 @@ EXPORT_SYMBOL(VPageChannel_Send); void VPageChannel_PollRecvQ(VPageChannel *channel) // IN { - if (channel->qpConnected) { - VMCIPacketDoDoorbellCallback(channel); + if (VPCState_Connected != channel->state) { + VPageChannelDoDoorbellCallback(channel); } } EXPORT_SYMBOL(VPageChannel_PollRecvQ); diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciRoute.c open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciRoute.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/common/vmciRoute.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/common/vmciRoute.c 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2011 VMware, Inc. All rights reserved. + * Copyright (C) 2011-2012 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 @@ -114,6 +114,17 @@ VMCI_Route(VMCIHandle *src, // IN/ return VMCI_ERROR_INVALID_ARGS; } + /* + * If the client passed the ANON source handle then respect it (both + * context and resource are invalid). However, if they passed only + * an invalid context, then they probably mean ANY, in which case we + * should set the real context here before passing it down. + */ + + if (VMCI_INVALID_ID == src->context && VMCI_INVALID_ID != src->resource) { + src->context = VMCI_GetContextID(); + } + /* Send from local client down to the hypervisor. */ *route = VMCI_ROUTE_AS_GUEST; return VMCI_SUCCESS; @@ -214,6 +225,13 @@ VMCI_Route(VMCIHandle *src, // IN/ /* Pass it up to the guest. */ *route = VMCI_ROUTE_AS_HOST; return VMCI_SUCCESS; + } else if (!hasGuestDevice) { + /* + * The host is attempting to reach a CID without an active context, and + * we can't send it down, since we have no guest device. + */ + + return VMCI_ERROR_DST_UNREACHABLE; } } @@ -225,6 +243,14 @@ VMCI_Route(VMCIHandle *src, // IN/ */ if (!hasGuestDevice) { + /* + * Ending up here means we have neither guest nor host device. That + * shouldn't happen, since any VMCI client in the kernel should have done + * a successful VMCI_DeviceGet. + */ + + ASSERT(FALSE); + return VMCI_ERROR_DEVICE_NOT_FOUND; } diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/linux/driver.c open-vm-tools-2012.05.21-724730/modules/linux/vmci/linux/driver.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/linux/driver.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/linux/driver.c 2012-05-22 15:12:52.000000000 -0500 @@ -150,11 +150,22 @@ static void process_bitmap(unsigned long # define VMCI_DISABLE_MSIX 1 #endif +/* + * Linux kernel < 2.6.31 takes 'int' for 'bool' module parameters. + * Linux kernel >= 3.3.0 takes 'bool' for 'bool' module parameters. + * Kernels between the two take either. So flip switch at 3.0.0. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) +# define compat_bool bool +#else +# define compat_bool int +#endif + static vmci_device vmci_dev; -static int vmci_disable_host = 0; -static int vmci_disable_guest = 0; -static int vmci_disable_msi; -static int vmci_disable_msix = VMCI_DISABLE_MSIX; +static compat_bool vmci_disable_host = 0; +static compat_bool vmci_disable_guest = 0; +static compat_bool vmci_disable_msi; +static compat_bool vmci_disable_msix = VMCI_DISABLE_MSIX; DECLARE_TASKLET(vmci_dg_tasklet, dispatch_datagrams, (unsigned long)&vmci_dev); diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/linux/vmci_version.h open-vm-tools-2012.05.21-724730/modules/linux/vmci/linux/vmci_version.h --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/linux/vmci_version.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/linux/vmci_version.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2007-2012 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 @@ -25,8 +25,8 @@ #ifndef _VMCI_VERSION_H_ #define _VMCI_VERSION_H_ -#define VMCI_DRIVER_VERSION 9.3.20.0 -#define VMCI_DRIVER_VERSION_COMMAS 9,3,20,0 -#define VMCI_DRIVER_VERSION_STRING "9.3.20.0" +#define VMCI_DRIVER_VERSION 9.5.7.0 +#define VMCI_DRIVER_VERSION_COMMAS 9,5,7,0 +#define VMCI_DRIVER_VERSION_STRING "9.5.7.0" #endif /* _VMCI_VERSION_H_ */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmci/shared/vmci_page_channel.h open-vm-tools-2012.05.21-724730/modules/linux/vmci/shared/vmci_page_channel.h --- open-vm-tools-2011.12.20-562307/modules/linux/vmci/shared/vmci_page_channel.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmci/shared/vmci_page_channel.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2011 VMware, Inc. All rights reserved. + * Copyright (C) 2011-2012 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 @@ -33,72 +33,218 @@ #include "vmci_defs.h" #include "vmci_call_defs.h" -/* Max size of a single tx buffer. */ +/** \cond PRIVATE */ #define VPAGECHANNEL_MAX_TX_BUF_SIZE (1 << 14) #define VPAGECHANNEL_MAX_PAGES_PER_TX_BUFFER \ (VPAGECHANNEL_MAX_TX_BUF_SIZE / PAGE_SIZE + 1) +/** \endcond */ + +/** + * \brief Get a pointer to the elements in a packet. + * + * Returns a pointer to the elements at the end of a page channel packet. + * + * \see VPageChannelElem + * \see VPageChannelPacket + */ #define VPAGECHANNEL_PACKET_ELEMS(packet) \ (VPageChannelElem *)((char *)(packet) + \ sizeof(VPageChannelPacket) + \ packet->msgLen) + +/** + * \brief Get a pointer to the message in a packet. + * + * Returns a pointer to the message embedded in a page channel packet. + * + * \see VPageChannelPacket + */ + #define VPAGECHANNEL_PACKET_MESSAGE(packet) \ (char *)((char *)(packet) + sizeof(VPageChannelPacket)) +/** + * \brief Notify client directly, and do not read packets. + * + * This flag indicates that the channel should invoke the client's receive + * callback directly when any packets are available. If not specified, then + * when a notification is received, packets are read from the channel and the + * callback invoked for each one separately. + * + * \note Not applicable to VMKernel. + * + * \see VPageChannel_CreateInVM() + */ + +#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY 0x1 + +/** + * \brief Invoke client's receive callback in delayed context. + * + * This flag indicates that all callbacks run in a delayed context, and the + * caller and callback are allowed to block. If not specified, then callbacks + * run in interrupt context and the channel will not block, and the caller + * is not allowed to block. + * + * \note Not applicable to VMKernel. + * + * \see VPageChannel_CreateInVM() + */ + +#define VPAGECHANNEL_FLAGS_RECV_DELAYED 0x2 + +/** + * \brief Send from an atomic context. + * + * This flag indicates that the client wishes to call Send() from an atomic + * context and that the channel should not block. If the channel is not + * allowed to block, then the channel's pages are permanently mapped and + * pinned. Note that this will limit the total size of the channel to + * VMCI_MAX_PINNED_QP_MEMORY. + * + * \note Not applicable to VMKernel. + * + * \see VPageChannel_CreateInVM() + */ + +#define VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC 0x4 + +/** + * \brief An element describing a data range. + * + * Describes a data range, starting at a base address and for a given + * length, i.e., an element of a scatter-gather list. Indicates physical + * address for the guest and machine address for hypervisor. Can be passed + * via packets or buffers. + * + * \note Structure is packed. + * + * \see VPageChannelPacket + * \see VPageChanelBuffer + */ typedef #include "vmware_pack_begin.h" struct VPageChannelElem { union { - uint64 pa; // For guest - uint64 ma; // For hypervisor + /** \brief Physical address for guest. */ + uint64 pa; + + /** \brief Machine address for hypervisor. */ + uint64 ma; }; + + /** \brief Length of range. */ uint32 le; } #include "vmware_pack_end.h" VPageChannelElem; +/** + * \brief Page channel page types. + * + * The various types of page channel packets. + * + * \see VPageChannelPacket + */ typedef enum { + /** \brief Data packet. */ VPCPacket_Data = 1, - VPCPacket_Completion_Notify, // Hypervisor to guest only. - VPCPacket_GuestConnect, // Connect to hypervisor. Internal use only. - VPCPacket_HyperConnect, // Complete connection handshake. Internal. - VPCPacket_RequestBuffer, // Request buffers. Internal use only. - VPCPacket_SetRecvBuffer, // Set buffers. Internal use only. + + /** \brief Completion notification, from hypervisor to guest. */ + VPCPacket_Completion_Notify, + + /** \cond PRIVATE */ + /** \brief Connect to hypervisor, internal. */ + VPCPacket_GuestConnect, + + /** \brief Complete connection handshake, internal. */ + VPCPacket_HyperConnect, + + /** \brief Request buffers, internal. */ + VPCPacket_RequestBuffer, + + /** \brief Set buffers, internal. */ + VPCPacket_SetRecvBuffer, + + /** \brief Hypervisor channel disconnect, internal. */ + VPCPacket_HyperDisconnect, + + /** \brief Guest channel ACK hypervisor disconnect, internal. */ + VPCPacket_GuestDisconnect, + /** \endcond */ } VPageChannelPacketType; +/** + * \brief Page channel packet structure. + * + * A packet structure for passing control/data between guest and hypervisor. + * Can optionally contain a message and also a number of elements. + * + * \note Structure is packed. + * + * \see VPageChannelPacketType + */ typedef #include "vmware_pack_begin.h" struct VPageChannelPacket { + /** \brief Type of packet. */ VPageChannelPacketType type; + + /** \brief Length of optional message. */ uint32 msgLen; + + /** \brief Number of optional elements in packet. */ uint32 numElems; - /* - * Followed by msgLen of message and numElems of VPageChannelElem. - */ + + /** \brief Followed by msgLen of message and numElems VPageChannelElem. */ } #include "vmware_pack_end.h" VPageChannelPacket; +/** + * \brief Page channel buffer structure. + * + * A buffer of elements (a scatter-gather list). + * + * \note Structure is packed. + * + * \see VPageChannelElem + */ + typedef #include "vmware_pack_begin.h" struct VPageChannelBuffer { + /** \brief Number of elements. */ uint32 numElems; + + /** \brief First element. */ VPageChannelElem elems[1]; - /* - * Followed by numElems - 1 of VPageChannelElem. - */ + + /** \brief Followed by numElems - 1 of VPageChannelElem. */ } #include "vmware_pack_end.h" VPageChannelBuffer; +/** \cond PRIVATE */ typedef #include "vmware_pack_begin.h" struct VPageChannelGuestConnectMessage { + + /** \brief Guest channel's datagram handle for control channel. */ VMCIHandle dgHandle; + + /** \brief Guest channel's queuepair handle. */ VMCIHandle qpHandle; + + /** \brief Size of producer queue in queuepair in bytes. */ uint64 produceQSize; + + /** \brief Size of consumer queue in queuepair in bytes. */ uint64 consumeQSize; + + /** \brief Guest channel's doorbell handle. */ VMCIHandle doorbellHandle; } #include "vmware_pack_end.h" @@ -107,62 +253,284 @@ VPageChannelGuestConnectMessage; typedef #include "vmware_pack_begin.h" struct VPageChannelHyperConnectMessage { + /** \brief Hypervisor's doorbell handle. */ VMCIHandle doorbellHandle; } #include "vmware_pack_end.h" VPageChannelHyperConnectMessage; +/** \endcond PRIVATE */ + +/** \cond PRIVATE */ +typedef enum VPageChannelState { + VPCState_Free = 0, + VPCState_Unconnected, + VPCState_Connecting, + VPCState_Connected, + VPCState_Disconnecting, + VPCState_Disconnected, +} VPageChannelState; +/** \endcond PRIVATE */ + +/** + * \brief Opaque page channel type. + */ struct VPageChannel; typedef struct VPageChannel VPageChannel; +/** + * \brief Client receive callback type. + * + * Type of receive callback, invoked when there are data packets in the + * channel. The client provides a callback with this type to + * VPageChannel_CreateInVM(). If VPAGECHANNEL_FLAGS_NOTIFY_ONLY is specified + * in the channel creation flags, then \c packet is \c NULL; otherwise, + * \c packet points to a channel packet. + * + * \see VPageChannel_CreateInVM() + * \see VPageChannelPacket + */ + typedef void (*VPageChannelRecvCB)(void *clientData, VPageChannelPacket *packet); #if !defined(VMKERNEL) +/** + * \brief Client element allocation callback type. + * + * Type of element allocation callback, invoked when the channel needs + * elements. The client provides a callback of this type to + * VPageChannel_CreateInVM(). + * + * \see VPageChannel_CreateInVM() + * \see VPageChannelElem + * \see VPageChannelFreeElemFn + */ + typedef int (*VPageChannelAllocElemFn)(void *clientData, VPageChannelElem *elems, int numElems); +/** + * \brief Client element release callback type. + * + * Type of element release callback, invoked when the channel releases + * elements. The client provides a callback of this type to + * VPageChannel_CreateInVM(). + * + * \see VPageChannel_CreateInVM() + * \see VPageChannelElem + * \see VPageChannelAllocElemFn + */ + typedef void (*VPageChannelFreeElemFn)(void *clientData, VPageChannelElem *elems, int numElems); +/* + ************************************************************************ + * VPageChannel_CreateInVM */ /** + * + * \brief Create guest page channel. + * + * Creates a page channel in the guest. The channel should be released + * with VPageChannel_Destroy(). + * + * \note Only applicable in the guest. + * + * \see VPageChannel_CreateInVMK() + * \see VPageChannel_Destroy() + * + * \param[out] channel Pointer to a newly constructed page + * channel if successful. + * \param[in] resourceId Resource ID on which the channel should + * register its control channel. + * \param[in] peerResourceId Resource ID of peer's control channel. + * \param[in] produceQSize Size of producer queue in queuepair in + * bytes. + * \param[in] consumeQSize Size of consumer queue in queuepair in + * bytes. + * \param[in] flags Channel flags. + * \param[in] recvCB Client's receive callback. + * \param[in] clientRecvData Client data for client's receive + * callback. + * \param[in] elemAlloc Element allocation callback for + * allocating page ranges (scatter-gather + * elements). + * \param[in] allocClientData Client data for element allocation + * callback. + * \param[in] elemFree Element release callback for elements. + * \param[in] freeClientData Client data for element release + * callback. + * \param[in] defRecvBufs Default number of elements sent to + * hypervisor channel. + * \param[in] maxRecvBufs Maximum number of elements that can be + * sent to the hypervisor channel. + * + * \retval VMCI_SUCCESS Creation succeeded, \c *channel contains + * a pointer to a valid channel. + * \retval other Failure. + * + ************************************************************************ + */ + int VPageChannel_CreateInVM(VPageChannel **channel, VMCIId resourceId, VMCIId peerResourceId, uint64 produceQSize, uint64 consumeQSize, + uint32 flags, VPageChannelRecvCB recvCB, void *clientRecvData, - Bool notifyOnly, VPageChannelAllocElemFn elemAlloc, void *allocClientData, VPageChannelFreeElemFn elemFree, void *freeClientData, - int defaultRecvBuffers, - int maxRecvBuffers); + int defRecvBufs, + int maxRecvBufs); #else // VMKERNEL +/** + * \brief Type of VM memory access off callback. + * + * This callback is invoked when the memory of the VM containing the peer + * endpoint becomes inaccessible, for example due to a crash. When this + * occurs, the client should unmap any guest pages and cleanup any state. + * This callback runs in a blockable context. The client is not allowed to + * call VPageChannel_Destroy() from inside the callback, or it will deadlock, + * since that function will wait for the callback to complete. + * + * \note Only applicable on VMKernel. + * + * \see VPageChannel_CreateInVMK() + */ + +typedef void (*VPageChannelMemAccessOffCB)(void *clientData); + +/* + ************************************************************************ + * VPageChannel_CreateInVMK */ /** + * + * \brief Create a page channel in VMKernel. + * + * Creates a page channel. The channel should be released with + * VPageChannel_Destroy(). + * + * \note Only applicable on VMKernel. + * + * \see VPageChannel_CreateInVM() + * \see VPageChannel_Destroy() + * + * \param[out] channel Pointer to a newly constructed page + * channel if successful. + * \param[in] resourceId Resource ID on which to register + * control channel. + * \param[in] recvCB Client's receive callback. + * \param[in] clientRecvData Client data for receive callback. + * \param[in] memAccessOffCB Client's mem access off callback. + * \param[in] memAccessOffData Client data for mem access off. + * + * \retval VMCI_SUCCESS Creation succeeded, \c *channel + * contains a pointer to a valid channel. + * \retval other Failure. + * + *********************************************************************** + */ + int VPageChannel_CreateInVMK(VPageChannel **channel, VMCIId resourceId, VPageChannelRecvCB recvCB, - void *clientRecvData); + void *clientRecvData, + VPageChannelMemAccessOffCB memAccessOffCB, + void *memAccessOffData); + +/* + ************************************************************************ + * VPageChannel_ReserveBuffers */ /** + * + * \brief Reserve guest elements. + * + * Reserve sufficient guest elements to cover the given length. The + * buffers can then be posted to the guest. This allocates both the + * buffer and the elements within the buffer. + * + * \note Only applicable on VMKernel. + * + * \see VPageChannel_ReleaseBuffers() + * + * \param[in] channel Page channel. + * \param[in] dataLen Length to reserve in bytes. + * \param[out] buffer Pointer to a buffer containing elements to cover + * the given length if successful. + * + * \retval VMCI_SUCCESS Reservation succeeded, \c *buffer contains + * a pointer to a valid buffer. + * \retval other Failure. + * + ************************************************************************ + */ int VPageChannel_ReserveBuffers(VPageChannel *channel, size_t dataLen, VPageChannelBuffer **buffer); + +/* + ************************************************************************ + * VPageChannel_ReleaseBuffers */ /** + * + * \brief Release guest elements. + * + * \note Only applicable on VMKernel. + * + * \see VPageChannel_ReserveBuffers() + * + * Release guest elements previous reserved with + * VPageChannel_ReserveBuffers(). If the buffers were sent to the guest, + * then only the buffer itself should be released, i.e., + * \c returnToFreePool should be \c FALSE; the guest will release the + * buffers on completion. Otherwise, if for some reason they are not + * sent after reserving them, then \c returnToFreePool should be set to + * \c TRUE. + * + * \param[in] channel Page channel. + * \param[in] buffer Buffer to be released. + * \param[in] returnToFreePool If \c TRUE, then release the elements + * of the buffer along with the buffer + * itself. If \c FALSE, then release only + * the buffer pointer itself. + * + ************************************************************************ + */ + void VPageChannel_ReleaseBuffers(VPageChannel *channel, VPageChannelBuffer *buffer, Bool returnToFreePool); /* - * This function is called when the client is finished using the - * scatter-gather list of a packet. This will generate a notification to the - * guest to pass the ownership of buffers back to the guest. This can also be - * used to read back the data from hypervisor and send it the to guest. + ************************************************************************ + * VPageChannel_CompletionNotify */ /** + * + * \brief Notify channel of completion. + * + * This function is called when the client is finished using the elements + * (scatter-gather list) of a packet. This will generated a notification + * to the guest to pass ownership of the buffers back to the guest. This + * can also be used to read back the data from the hypervisor and send + * it to the guest. + * + * \note Only applicable on VMKernel. + * + * \see VPageChannel_ReserveBuffers + * + * \param[in] channel Channel on which I/O is complete. + * \param[in] message Optional message to send to guest. + * \param[in] len Length of optional message. + * \param[in] buffer Buffer used for I/O. + * + ************************************************************************ */ int VPageChannel_CompletionNotify(VPageChannel *channel, @@ -170,10 +538,55 @@ int VPageChannel_CompletionNotify(VPageC int len, VPageChannelBuffer *buffer); +/* + ************************************************************************ + * VPageChannel_MapToMa */ /** + * + * \brief Map guest PA in an element to a list of MAs. + * + * Map a guest physical address to a list of hypervisor machine + * addresses. + * + * \note Only applicable on VMKernel. + * + * \param[in] channel Channel on which to map. + * \param[in] paElem Guest's physical address. + * \param[out] maElems Hypervisor machine addresses. + * \param[in] numElems Max number of hypervisor elements. + * + * \retval elems Number of mapped elements. + * + ************************************************************************ + */ + int VPageChannel_MapToMa(VPageChannel *channel, VPageChannelElem paElem, VPageChannelElem *maElems, uint32 numElems); + +/* + ************************************************************************ + * VPageChannel_UnmapMa */ /** + * + * \brief Unmap MA for a buffer. + * + * Unmap hypervisor machine addresses referring to a guest physical + * addresses. + * + * \note Only applicable on VMKernel. + * + * \see VPageChannel_MapToMa + * + * \param[in] channel Channel for which to unmap. + * \param[in] buffer Buffer containing elements to unmap. + * \param[in] numElems Number of elements to unmap. + * + * \retval 0 Unmap successful. + * \retval -1 World not found for channel. + * + ************************************************************************ + */ + int VPageChannel_UnmapMa(VPageChannel *channel, VPageChannelBuffer *buffer, int numElems); @@ -181,34 +594,113 @@ int VPageChannel_UnmapMa(VPageChannel *c #endif // VMKERNEL /* - * Common functions. + ************************************************************************ + * VPageChannel_Destroy */ /** + * + * \brief Destroy the given channel. + * + * Destroy the given channel. This will disconnect from the peer + * channel (if connected) and release all resources. + * + * \see VPageChannel_CreateInVMK + * \see VPageChannel_CreateInVM + * + * \param[in] channel The channel to be destroyed. + * + ************************************************************************ */ void VPageChannel_Destroy(VPageChannel *channel); + +/* + ************************************************************************ + * VPageChannel_Send */ /** + * + * \brief Send a packet to the channel's peer. + * + * Send a packet to the channel's peer. A message and a number of + * elements may optionally be sent. If the send is successful, the + * elements are owned by the peer and only the buffer itself should + * be released, but not the elements within. If the send fails, the + * client should release the buffer and the elements. + * + * \see VPageChannel_SendPacket + * + * \param[in] channel Channel on which to send. + * \param[in] type Type of packet to send. + * \param[in] message Optional message to send. + * \param[in] len Length of optional message. + * \param[in] buffer Buffer (of elements) to send. + * + * \retval VMCI_SUCCESS Packet successfully sent, buffer elements + * owned by peer. + * \retval other Failure to send, client should release + * elements. + * + ************************************************************************ + */ + int VPageChannel_Send(VPageChannel *channel, VPageChannelPacketType type, char *message, int len, VPageChannelBuffer *buffer); + +/* + ************************************************************************ + * VPageChannel_SendPacket */ /** + * + * \brief Send the given packet to the channel's peer. + * + * Send a client-constructed packet to the channel's peer. If the + * send is successful, any elements in the packet are owned by the + * peer. Otherwise, the client retains ownership. + * + * \see VPageChannel_Send + * + * \param[in] channel Channel on which to send. + * \param[in] packet Packet to be sent. + * + * \retval VMCI_SUCCESS Packet successfully sent, buffer elements + * owned by peer. + * \retval other Failure to send, client should release + * elements. + * + ************************************************************************ + */ + int VPageChannel_SendPacket(VPageChannel *channel, VPageChannelPacket *packet); -void VPageChannel_PollRecvQ(VPageChannel *channel); +/* + ************************************************************************ + * VPageChannel_PollRecvQ */ /** + * + * \brief Poll the channel's receive queue for packets. + * + * Poll the channel's receive queue for packets from the peer. If any + * packets are available, the channel's receive callback will be invoked. + * + * \param[in] channel Channel to poll. + * + ************************************************************************ + */ + +void VPageChannel_PollRecvQ(VPageChannel *channel); /* - *----------------------------------------------------------------------------- + ************************************************************************ + * VPageChannel_BufferLen */ /** * - * VPageChannelPacket_BufferLen -- + * \brief Determine the length of a packet. * - * Calculate the length of the given packet. + * Determine the length of the given packet in bytes. * - * Results: - * The length of the given packet in bytes. + * \param[in] packet Packet for which length is to be determined. * - * Side effects: - * None. + * \retval bytes Size of the packet in bytes. * - *----------------------------------------------------------------------------- + ************************************************************************ */ static INLINE size_t @@ -228,7 +720,7 @@ VPageChannelPacket_BufferLen(VPageChanne return len; } - +/** \cond PRIVATE */ #if defined(linux) && !defined(VMKERNEL) #include "compat_pci.h" #define vmci_pci_map_page(_pg, _off, _sz, _dir) \ @@ -236,5 +728,6 @@ VPageChannelPacket_BufferLen(VPageChanne #define vmci_pci_unmap_page(_dma, _sz, _dir) \ pci_unmap_page(NULL, (_dma), (_sz), (_dir)) #endif // linux && !VMKERNEL +/** \endcond PRIVATE */ #endif // _VMCI_PACKET_H_ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/dentry.c open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/dentry.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/dentry.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/dentry.c 2012-05-22 15:12:52.000000000 -0500 @@ -27,6 +27,7 @@ #include "compat_fs.h" #include "compat_kernel.h" +#include "compat_namei.h" #include "compat_version.h" #include "inode.h" @@ -78,10 +79,22 @@ HgfsDentryRevalidate(struct dentry *dent ASSERT(dentry); +#if defined(LOOKUP_RCU) /* Introduced in 2.6.38 */ + if (nd && (nd->flags & LOOKUP_RCU)) { + return -ECHILD; + } +#endif + /* Just call HgfsRevaliate, which does the right thing. */ error = HgfsRevalidate(dentry); if (error) { LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDentryRevalidate: invalid\n")); + + if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { + shrink_dcache_parent(dentry); + } + d_drop(dentry); + return 0; } diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/file.c open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/file.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/file.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/file.c 2012-05-22 15:12:52.000000000 -0500 @@ -83,7 +83,7 @@ static loff_t HgfsSeek(struct file *file static int HgfsFsync(struct file *file, #if defined VMW_FSYNC_OLD struct dentry *dentry, -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) +#elif defined VMW_FSYNC_31 loff_t start, loff_t end, #endif @@ -992,7 +992,7 @@ static int HgfsFsync(struct file *file, // IN: File we operate on #if defined VMW_FSYNC_OLD struct dentry *dentry, // IN: Dentry for this file -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) +#elif defined VMW_FSYNC_31 loff_t start, // IN: start of range to sync loff_t end, // IN: end of range to sync #endif diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/filesystem.c open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/filesystem.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/filesystem.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/filesystem.c 2012-05-22 15:12:52.000000000 -0500 @@ -83,7 +83,7 @@ HgfsOp hgfsVersionCreateSymlink; static inline unsigned long HgfsComputeBlockBits(unsigned long blockSize); static compat_kmem_cache_ctor HgfsInodeCacheCtor; static HgfsSuperInfo *HgfsInitSuperInfo(HgfsMountInfo *mountInfo); -static struct dentry *HgfsGetRootDentry(struct super_block *sb); +static int HgfsGetRootDentry(struct super_block *sb, struct dentry **rootDentry); static int HgfsReadSuper(struct super_block *sb, void *rawData, int flags); @@ -334,7 +334,8 @@ HgfsInitSuperInfo(HgfsMountInfo *mountIn * Gets the root dentry for a given super block. * * Results: - * A valid root dentry on success, NULL otherwise. + * zero and a valid root dentry on success + * negative value on failure * * Side effects: * None. @@ -342,63 +343,83 @@ HgfsInitSuperInfo(HgfsMountInfo *mountIn *---------------------------------------------------------------------------- */ -static struct dentry * -HgfsGetRootDentry(struct super_block *sb) // IN: Super block object +static int +HgfsGetRootDentry(struct super_block *sb, // IN: Super block object + struct dentry **rootDentry) // OUT: Root dentry { - struct dentry *rootDentry = NULL; + int result = -ENOMEM; struct inode *rootInode; + struct dentry *tempRootDentry = NULL; + struct HgfsAttrInfo rootDentryAttr; + HgfsInodeInfo *iinfo; ASSERT(sb); + ASSERT(rootDentry); LOG(6, (KERN_DEBUG "VMware hgfs: %s: entered\n", __func__)); rootInode = HgfsGetInode(sb, HGFS_ROOT_INO); - if (rootInode) { - HgfsInodeInfo *iinfo; - static const HgfsAttrInfo attr = { - .type = HGFS_FILE_TYPE_DIRECTORY, - .size = 4192, - .specialPerms = 0, - .ownerPerms = HGFS_PERM_READ | HGFS_PERM_EXEC, - .groupPerms = HGFS_PERM_READ | HGFS_PERM_EXEC, - .otherPerms = HGFS_PERM_READ | HGFS_PERM_EXEC, - .mask = HGFS_ATTR_VALID_TYPE | - HGFS_ATTR_VALID_SIZE | - HGFS_ATTR_VALID_SPECIAL_PERMS | - HGFS_ATTR_VALID_OWNER_PERMS | - HGFS_ATTR_VALID_GROUP_PERMS | - HGFS_ATTR_VALID_OTHER_PERMS, - }; - - /* - * On an allocation failure in read_super, the inode will have been - * marked "bad". If it was, we certainly don't want to start playing with - * the HgfsInodeInfo. So quietly put the inode back and fail. - */ - if (is_bad_inode(rootInode)) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: encountered bad inode\n", - __func__)); - iput(rootInode); - goto exit; - } - - HgfsChangeFileAttributes(rootInode, &attr); - - iinfo = INODE_GET_II_P(rootInode); - iinfo->isFakeInodeNumber = FALSE; - iinfo->isReferencedInode = TRUE; + if (rootInode == NULL) { + LOG(6, (KERN_DEBUG "VMware hgfs: %s: Could not get the root inode\n", + __func__)); + goto exit; } - rootDentry = d_alloc_root(rootInode); - if (rootDentry == NULL) { + /* + * On an allocation failure in read_super, the inode will have been + * marked "bad". If it was, we certainly don't want to start playing with + * the HgfsInodeInfo. So quietly put the inode back and fail. + */ + if (is_bad_inode(rootInode)) { + LOG(6, (KERN_DEBUG "VMware hgfs: %s: encountered bad inode\n", + __func__)); + goto exit; + } + + tempRootDentry = d_make_root(rootInode); + /* + * d_make_root() does iput() on failure; if d_make_root() completes + * successfully then subsequent dput() will do iput() for us, so we + * should just ignore root inode from now on. + */ + rootInode = NULL; + + if (tempRootDentry == NULL) { LOG(4, (KERN_WARNING "VMware hgfs: %s: Could not get " "root dentry\n", __func__)); goto exit; } + result = HgfsPrivateGetattr(tempRootDentry, &rootDentryAttr, NULL); + if (result) { + LOG(4, (KERN_WARNING "VMware hgfs: HgfsReadSuper: Could not" + "instantiate the root dentry\n")); + goto exit; + } + + iinfo = INODE_GET_II_P(tempRootDentry->d_inode); + iinfo->isFakeInodeNumber = FALSE; + iinfo->isReferencedInode = TRUE; + + if (rootDentryAttr.mask & HGFS_ATTR_VALID_FILEID) { + iinfo->hostFileId = rootDentryAttr.hostFileId; + } + + HgfsChangeFileAttributes(tempRootDentry->d_inode, &rootDentryAttr); + HgfsDentryAgeReset(tempRootDentry); + tempRootDentry->d_op = &HgfsDentryOperations; + + *rootDentry = tempRootDentry; + result = 0; + LOG(6, (KERN_DEBUG "VMware hgfs: %s: finished\n", __func__)); exit: - return rootDentry; + if (result) { + iput(rootInode); + dput(tempRootDentry); + *rootDentry = NULL; + } + return result; } @@ -461,6 +482,10 @@ HgfsReadSuper(struct super_block *sb, // sb->s_magic = HGFS_SUPER_MAGIC; sb->s_op = &HgfsSuperOperations; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + sb->s_d_op = &HgfsDentryOperations; +#endif + /* * If s_maxbytes isn't initialized, the generic write path may fail. In * most kernels, s_maxbytes is initialized by the kernel's superblock @@ -478,13 +503,13 @@ HgfsReadSuper(struct super_block *sb, // sb->s_blocksize_bits = HgfsComputeBlockBits(HGFS_BLOCKSIZE); sb->s_blocksize = 1 << sb->s_blocksize_bits; - rootDentry = HgfsGetRootDentry(sb); - if (rootDentry == NULL) { + result = HgfsGetRootDentry(sb, &rootDentry); + if (result) { LOG(4, (KERN_WARNING "VMware hgfs: HgfsReadSuper: Could not instantiate " "root dentry\n")); - result = -ENOMEM; goto exit; } + sb->s_root = rootDentry; LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadSuper: finished %s\n", si->shareName)); diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/inode.c open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/inode.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/inode.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/inode.c 2012-05-22 15:12:52.000000000 -0500 @@ -61,7 +61,7 @@ static int HgfsPackSetattrRequest(struct HgfsReq *req, Bool *changed); static int HgfsPackCreateDirRequest(struct dentry *dentry, - int mode, + compat_umode_t mode, HgfsOp opUsed, HgfsReq *req); static int HgfsTruncatePages(struct inode *inode, @@ -74,14 +74,14 @@ static int HgfsPackSymlinkCreateRequest( /* HGFS inode operations. */ static int HgfsCreate(struct inode *dir, struct dentry *dentry, - int mode, + compat_umode_t mode, struct nameidata *nd); static struct dentry *HgfsLookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); static int HgfsMkdir(struct inode *dir, struct dentry *dentry, - int mode); + compat_umode_t mode); static int HgfsRmdir(struct inode *dir, struct dentry *dentry); static int HgfsUnlink(struct inode *dir, @@ -729,7 +729,7 @@ HgfsPackSetattrRequest(struct iattr *iat static int HgfsPackCreateDirRequest(struct dentry *dentry, // IN: Directory to create - int mode, // IN: Mode to assign dir + compat_umode_t mode, // IN: Mode to assign dir HgfsOp opUsed, // IN: Op to be used. HgfsReq *req) // IN/OUT: Packet to write into { @@ -951,7 +951,7 @@ HgfsTruncatePages(struct inode *inode, / static int HgfsCreate(struct inode *dir, // IN: Parent dir to create in struct dentry *dentry, // IN: Dentry containing name to create - int mode, // IN: Mode of file to be created + compat_umode_t mode, // IN: Mode of file to be created struct nameidata *nd) // IN: Intent, vfsmount, ... { HgfsAttrInfo attr; @@ -1107,7 +1107,7 @@ error: static int HgfsMkdir(struct inode *dir, // IN: Inode of parent directory struct dentry *dentry, // IN: Dentry with name to be created - int mode) // IN: Mode of dir to be created + compat_umode_t mode) // IN: Mode of dir to be created { HgfsReq *req; HgfsStatus replyStatus; diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/Makefile.kernel open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/Makefile.kernel --- open-vm-tools-2011.12.20-562307/modules/linux/vmhgfs/Makefile.kernel 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmhgfs/Makefile.kernel 2012-05-22 15:12:52.000000000 -0500 @@ -27,6 +27,7 @@ EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/cachector.c, -DVMW_KMEMCR_CTOR_HAS_3_ARGS, ) EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/cachector1.c, -DVMW_KMEMCR_CTOR_HAS_2_ARGS, ) +EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/file_operations_fsync.c, -DVMW_FSYNC_31, ) # Note: These tests are inverted EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/getsb1.c,, -DVMW_GETSB_2618) diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmxnet/vmxnet.c open-vm-tools-2012.05.21-724730/modules/linux/vmxnet/vmxnet.c --- open-vm-tools-2011.12.20-562307/modules/linux/vmxnet/vmxnet.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmxnet/vmxnet.c 2012-05-22 15:12:52.000000000 -0500 @@ -80,6 +80,10 @@ static int vmxnet_close(struct net_devic static void vmxnet_set_multicast_list(struct net_device *dev); static int vmxnet_set_mac_address(struct net_device *dev, void *addr); static struct net_device_stats *vmxnet_get_stats(struct net_device *dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) +static int vmxnet_set_features(struct net_device *netdev, compat_netdev_features_t + features); +#endif #if defined(HAVE_CHANGE_MTU) || defined(HAVE_NET_DEVICE_OPS) static int vmxnet_change_mtu(struct net_device *dev, int new_mtu); #endif @@ -353,6 +357,7 @@ vmxnet_get_drvinfo(struct net_device *de } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) /* *---------------------------------------------------------------------------- * @@ -482,7 +487,7 @@ vmxnet_set_rx_csum(struct net_device *ne *---------------------------------------------------------------------------- */ -#ifdef VMXNET_DO_TSO +# ifdef VMXNET_DO_TSO static int vmxnet_set_tso(struct net_device *dev, u32 data) { @@ -498,6 +503,7 @@ vmxnet_set_tso(struct net_device *dev, u } return 0; } +# endif #endif @@ -506,17 +512,19 @@ vmxnet_ethtool_ops = { .get_settings = vmxnet_get_settings, .get_drvinfo = vmxnet_get_drvinfo, .get_link = ethtool_op_get_link, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) .get_rx_csum = vmxnet_get_rx_csum, .set_rx_csum = vmxnet_set_rx_csum, .get_tx_csum = vmxnet_get_tx_csum, .set_tx_csum = vmxnet_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef VMXNET_DO_TSO +# ifdef VMXNET_DO_TSO .get_tso = ethtool_op_get_tso, .set_tso = vmxnet_set_tso, -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) .get_ufo = ethtool_op_get_ufo, +# endif # endif #endif }; @@ -989,6 +997,9 @@ vmxnet_probe_device(struct pci_dev .ndo_start_xmit = &vmxnet_start_tx, .ndo_stop = &vmxnet_close, .ndo_get_stats = &vmxnet_get_stats, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + .ndo_set_features = vmxnet_set_features, +#endif #if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) .ndo_set_multicast_list = &vmxnet_set_multicast_list, #else @@ -2949,10 +2960,11 @@ vmxnet_load_multicast (struct net_device #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34) struct netdev_hw_addr *dmi; #else + int i=0; struct dev_mc_list *dmi = dev->mc_list; #endif u8 *addrs; - int i = 0, j, bit, byte; + int j, bit, byte; u32 crc, poly = CRC_POLYNOMIAL_LE; /* clear the multicast filter */ @@ -2990,7 +3002,11 @@ vmxnet_load_multicast (struct net_device crc = crc >> 26; mcast_table [crc >> 4] |= 1 << (crc & 0xf); } - return i; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34) + return netdev_mc_count(dev); +#else + return i; +#endif } /* @@ -3103,6 +3119,20 @@ vmxnet_get_stats(struct net_device *dev) return &lp->stats; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) +static int +vmxnet_set_features(struct net_device *netdev, compat_netdev_features_t features) +{ + compat_netdev_features_t changed = features ^ netdev->features; + + if (changed & (NETIF_F_RXCSUM)) { + if (features & NETIF_F_RXCSUM) + return 0; + } + return -1; +} +#endif + module_init(vmxnet_init); module_exit(vmxnet_exit); MODULE_DEVICE_TABLE(pci, vmxnet_chips); diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vmxnet/vmxnet_version.h open-vm-tools-2012.05.21-724730/modules/linux/vmxnet/vmxnet_version.h --- open-vm-tools-2011.12.20-562307/modules/linux/vmxnet/vmxnet_version.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vmxnet/vmxnet_version.h 2012-05-22 15:12:52.000000000 -0500 @@ -25,8 +25,8 @@ #ifndef _VMXNET_VERSION_H_ #define _VMXNET_VERSION_H_ -#define VMXNET_DRIVER_VERSION 2.0.12.0 -#define VMXNET_DRIVER_VERSION_COMMAS 2,0,12,0 -#define VMXNET_DRIVER_VERSION_STRING "2.0.12.0" +#define VMXNET_DRIVER_VERSION 2.0.14.0 +#define VMXNET_DRIVER_VERSION_COMMAS 2,0,14,0 +#define VMXNET_DRIVER_VERSION_STRING "2.0.14.0" #endif /* _VMXNET_VERSION_H_ */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/af_vsock.c open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/af_vsock.c --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/af_vsock.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/af_vsock.c 2012-05-22 15:12:52.000000000 -0500 @@ -106,6 +106,11 @@ #include #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +# include +#else +# include +#endif #include #if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) # include @@ -169,6 +174,7 @@ static Bool VSockVmciProtoToNotifyStruct Bool oldPktProto); static int VSockVmciGetAFValue(void); static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg); +static int VSockVmciRecvSeqCB(void *data, VMCIDatagram *dg); static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg); static void VSockVmciPeerAttachCB(VMCIId subId, VMCI_EventData *ed, void *clientData); @@ -210,6 +216,8 @@ static int VSockVmciBind(struct socket * struct sockaddr *addr, int addrLen); static int VSockVmciDgramConnect(struct socket *sock, struct sockaddr *addr, int addrLen, int flags); +static int VSockVmciSeqConnect(struct socket *sock, + struct sockaddr *addr, int addrLen, int flags); static int VSockVmciStreamConnect(struct socket *sock, struct sockaddr *addr, int addrLen, int flags); static int VSockVmciAccept(struct socket *sock, struct socket *newsock, int flags); @@ -236,6 +244,10 @@ static int VSockVmciDgramSendmsg(struct struct socket *sock, struct msghdr *msg, size_t len); static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); +static int VSockVmciSeqSendmsg(struct kiocb *kiocb, + struct socket *sock, struct msghdr *msg, size_t len); +static int VSockVmciSeqRecvmsg(struct kiocb *kiocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags); static int VSockVmciStreamSendmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len); static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock, @@ -297,7 +309,7 @@ static struct net_proto_family vsockVmci .owner = THIS_MODULE, }; -/* Socket operations, split for DGRAM and STREAM sockets. */ +/* Socket operations, split for DGRAM, STREAM and SEQPACKET sockets. */ static struct proto_ops vsockVmciDgramOps = { .family = VSOCK_INVALID_FAMILY, .owner = THIS_MODULE, @@ -319,6 +331,27 @@ static struct proto_ops vsockVmciDgramOp .sendpage = sock_no_sendpage, }; +static struct proto_ops vsockVmciSeqOps = { + .family = VSOCK_INVALID_FAMILY, + .owner = THIS_MODULE, + .release = VSockVmciRelease, + .bind = VSockVmciBind, + .connect = VSockVmciSeqConnect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = VSockVmciGetname, + .poll = VSockVmciPoll, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = VSockVmciShutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = VSockVmciSeqSendmsg, + .recvmsg = VSockVmciSeqRecvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + static struct proto_ops vsockVmciStreamOps = { .family = VSOCK_INVALID_FAMILY, .owner = THIS_MODULE, @@ -373,13 +406,14 @@ static int vsockVmciKernClientCount = 0; static Bool vmciDevicePresent = FALSE; static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID }; static VMCIId qpResumedSubId = VMCI_INVALID_ID; +static VMCIId ctxUpdatedSubId = VMCI_INVALID_ID; static int PROTOCOL_OVERRIDE = -1; /* - * Netperf benchmarks have shown significant throughput improvements when the QP - * size is bumped from 64k to 256k. These measurements were taken during the K/L.next - * timeframe. Give users better performance by default. + * Netperf benchmarks have shown significant throughput improvements when the + * QP size is bumped from 64k to 256k. These measurements were taken during the + * K/L.next timeframe. Give users better performance by default. */ #define VSOCK_DEFAULT_QP_SIZE_MIN 128 #define VSOCK_DEFAULT_QP_SIZE 262144 @@ -391,6 +425,11 @@ static int PROTOCOL_OVERRIDE = -1; */ #define VSOCK_DEFAULT_CONNECT_TIMEOUT (2 * HZ) +#define VSOCK_SEND_SEQ_CLOSE(_vsk, _err) \ + VSockVmciSendSeqPacket((_vsk), VSOCK_SEQ_PACKET_TYPE_CLOSE, (_err)) +#define VSOCK_SEND_SEQ_SHUTDOWN(_vsk, _mode) \ + VSockVmciSendSeqPacket((_vsk), VSOCK_SEQ_PACKET_TYPE_SHUTDOWN, (_mode)) + #ifdef VMX86_DEVEL # define LOG_PACKET(_pkt) VSockVmciLogPkt(__FUNCTION__, __LINE__, _pkt) #else @@ -996,7 +1035,194 @@ VSockVmciRecvDgramCB(void *data, compat_sk_receive_skb(sk, skb, 0); } - return 0; + return VMCI_SUCCESS; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciSendSeqPacket -- + * + * Send a sequential packet. This uses a stack-allocated packet, i.e., + * it isn't meant for DATA packets, but it works fine for the other packet + * types. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciSendSeqPacket(VSockVmciSock *vsk, // IN + VSockSeqPacketType type, // IN + uint32 mode) // IN +{ + int err; + VSockSeqPacket pkt; + + ASSERT(vsk); + + VSockSeqPacket_Init(&pkt, &vsk->localAddr, &vsk->remoteAddr, type, mode); + + err = VMCIDatagram_Send(&pkt.hdr.dg); + if (err < 0) { + err = VSockVmci_ErrorToVSockError(err); + } + + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciRecvSeqCB -- + * + * VMCI Datagram receive callback. This function is used specifically for + * SOCK_SEQPACKET sockets. + * + * This is invoked as part of a tasklet that's scheduled when the VMCI + * interrupt fires. This is run in bottom-half context and if it ever needs + * to sleep it should defer that work to a work queue. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * An sk_buff is created and queued with this socket. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciRecvSeqCB(void *data, // IN + VMCIDatagram *dg) // IN +{ + struct sock *sk; + size_t size; + VSockVmciSock *vsk; + VSockSeqPacket *pkt; + + ASSERT(dg); + ASSERT(dg->payloadSize <= VMCI_MAX_DG_PAYLOAD_SIZE); + + sk = (struct sock *)data; + + ASSERT(sk); + + /* XXX, figure out why sk->sk_socket can be NULL. */ + if (!sk->sk_socket) { + return EINVAL; + } + + ASSERT(sk->sk_socket->type == SOCK_SEQPACKET); + + if (VMCI_HYPERVISOR_CONTEXT_ID != dg->src.context) { + return VMCI_ERROR_NO_ACCESS; + } + + if (VMCI_RPC_PRIVILEGED != dg->src.resource && + VMCI_RPC_UNPRIVILEGED != dg->src.resource) { + return VMCI_ERROR_NO_ACCESS; + } + + size = VMCI_DG_SIZE(dg); + if (size < sizeof *pkt) { + return VMCI_ERROR_INVALID_ARGS; + } + + vsk = vsock_sk(sk); + pkt = (VSockSeqPacket *)dg; + + /* + * After this point, if we fail to handle the packet, we need to send a + * close to the peer with an error. Otherwise it might hang, waiting for a + * response to a packet that we discarded. + */ + + if (VSOCK_SEQ_PACKET_VERSION_1 != pkt->hdr.version) { + VSOCK_SEND_SEQ_CLOSE(vsk, EINVAL); + return VMCI_ERROR_INVALID_ARGS; + } + + if (SS_CONNECTED != sk->sk_socket->state) { + VSOCK_SEND_SEQ_CLOSE(vsk, ENOTCONN); + return VMCI_ERROR_DST_UNREACHABLE; + } + + switch (pkt->hdr.type) { + case VSOCK_SEQ_PACKET_TYPE_DATA: { + struct sk_buff *skb; + /* + * Attach the packet to the socket's receive queue as an sk_buff. + */ + + size -= sizeof *pkt; + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + VSOCK_SEND_SEQ_CLOSE(vsk, ENOMEM); + return VMCI_ERROR_NO_MEM; + } + + /* compat_sk_receive_skb() will do a sock_put(), so hold here. */ + sock_hold(sk); + skb_put(skb, size); + memcpy(skb->data, VSOCK_SEQ_PACKET_PAYLOAD(pkt), size); + + /* + * XXX, this can drop the skb. We need to find an alternative that + * will return an error if that happens, so that we can send a reset + * to the peer, i.e., + * + * if (!receive_skb(sk, skb)) { + * VSOCK_SEND_SEQ_CLOSE(vsk, ENOMEM); + * return VMCI_ERROR_NO_MEM; + * } + */ + + compat_sk_receive_skb(sk, skb, 0); + break; + } + case VSOCK_SEQ_PACKET_TYPE_CLOSE: + bh_lock_sock(sk); + + sock_set_flag(sk, SOCK_DONE); + vsk->peerShutdown = SHUTDOWN_MASK; + sk->sk_state = TCP_CLOSE; + + /* + * A close packet with an error code means a forceful reset, whereas + * no error means a graceful close. + */ + if (pkt->hdr.val) { + sk->sk_socket->state = SS_UNCONNECTED; + sk->sk_err = pkt->hdr.val; + sk->sk_error_report(sk); + } else { + if (skb_queue_empty(&sk->sk_receive_queue)) { + sk->sk_socket->state = SS_DISCONNECTING; + } + sk->sk_state_change(sk); + } + + bh_unlock_sock(sk); + break; + /* + * There's no reason for us to receive a shutdown packet in this direction, + * or any other packet for that matter. Inform the peer that the packet + * is invalid. + */ + default: + VSOCK_SEND_SEQ_CLOSE(vsk, EINVAL); + return VMCI_ERROR_INVALID_ARGS; + } + + return VMCI_SUCCESS; } @@ -1386,6 +1612,55 @@ VSockVmciQPResumedCB(VMCIId subId, /* *---------------------------------------------------------------------------- * + * VSockVmciContextUpdatedCB -- + * + * Invoked when a VM is resumed (technically when the context ID changes, + * but the event is actually sent even when it does not, so this works + * well for catching resumes). We must mark all connected sequential + * sockets as detached. + * + * Results: + * None. + * + * Side effects: + * May modify socket state and signal socket. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciContextUpdatedCB(VMCIId subId, // IN + VMCI_EventData *eData, // IN + void *clientData) // IN +{ + uint32 i; + + spin_lock_bh(&vsockSeqTableLock); + + for (i = 0; i < ARRAYSIZE(vsockSeqTable); i++) { + VSockVmciSock *vsk; + + list_for_each_entry(vsk, &vsockSeqTable[i], seqTable) { + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); + vsk->peerShutdown = SHUTDOWN_MASK; + sk->sk_state = TCP_CLOSE; + + if (skb_queue_empty(&sk->sk_receive_queue)) { + sk->sk_socket->state = SS_DISCONNECTING; + } + sk->sk_state_change(sk); + } + } + + spin_unlock_bh(&vsockSeqTableLock); +} + + +/* + *---------------------------------------------------------------------------- + * * VSockVmciPendingWork -- * * Releases the resources for a pending socket if it has not reached the @@ -2680,7 +2955,8 @@ __VSockVmciBind(struct sock *sk, } break; } - case SOCK_DGRAM: { + case SOCK_DGRAM: + case SOCK_SEQPACKET: { uint32 flags = 0; /* VMCI will select a resource ID for us if we provide VMCI_INVALID_ID. */ @@ -2699,8 +2975,10 @@ __VSockVmciBind(struct sock *sk, } err = VSockVmciDatagramCreateHnd(newAddr.svm_port, flags, - VSockVmciRecvDgramCB, sk, - &vsk->dgHandle); + sk->sk_socket->type == SOCK_DGRAM ? + VSockVmciRecvDgramCB : + VSockVmciRecvSeqCB, + sk, &vsk->dgHandle); if (err < VMCI_SUCCESS) { err = VSockVmci_ErrorToVSockError(err); goto out; @@ -2838,11 +3116,12 @@ __VSockVmciCreate(struct net *net, sk->sk_destruct = VSockVmciSkDestruct; sk->sk_backlog_rcv = VSockVmciQueueRcvSkb; - sk->sk_state = SS_UNCONNECTED; + sk->sk_state = 0; sock_reset_flag(sk, SOCK_DONE); INIT_LIST_HEAD(&vsk->boundTable); INIT_LIST_HEAD(&vsk->connectedTable); + INIT_LIST_HEAD(&vsk->seqTable); vsk->dgHandle = VMCI_INVALID_HANDLE; vsk->qpHandle = VMCI_INVALID_HANDLE; vsk->qpair = NULL; @@ -2918,7 +3197,14 @@ __VSockVmciRelease(struct sock *sk) // I VSockVmciRemoveConnected(sk); } + if (VSockVmciInSeqTable(sk)) { + VSockVmciRemoveSeq(sk); + } + if (!VMCI_HANDLE_INVALID(vsk->dgHandle)) { + if (SOCK_SEQPACKET == sk->sk_type && TCP_ESTABLISHED == sk->sk_state) { + VSOCK_SEND_SEQ_CLOSE(vsk, 0); + } VMCIDatagram_DestroyHnd(vsk->dgHandle); vsk->dgHandle = VMCI_INVALID_HANDLE; } @@ -3013,9 +3299,9 @@ VSockVmciSkDestruct(struct sock *sk) // VSockVmciTestUnregister(); compat_mutex_unlock(®istrationMutex); - VSOCK_STATS_CTLPKT_DUMP_ALL(); VSOCK_STATS_HIST_DUMP_ALL(); + VSOCK_STATS_TOTALS_DUMP_ALL(); } @@ -3168,6 +3454,7 @@ VSockVmciRegisterAddressFamily(void) } else { vsockVmciDgramOps.family = i; vsockVmciStreamOps.family = i; + vsockVmciSeqOps.family = i; err = i; break; } @@ -3204,6 +3491,7 @@ VSockVmciUnregisterAddressFamily(void) vsockVmciDgramOps.family = vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY; vsockVmciStreamOps.family = vsockVmciFamilyOps.family; + vsockVmciSeqOps.family = vsockVmciFamilyOps.family; } @@ -3269,6 +3557,18 @@ VSockVmciRegisterWithVmci(void) goto out; } + err = VMCIEvent_Subscribe(VMCI_EVENT_CTX_ID_UPDATE, + VMCI_FLAG_EVENT_NONE, + VSockVmciContextUpdatedCB, + NULL, + &ctxUpdatedSubId); + if (err < VMCI_SUCCESS) { + Warning("Unable to subscribe to context updated event. (%d)\n", err); + err = VSockVmci_ErrorToVSockError(err); + ctxUpdatedSubId = VMCI_INVALID_ID; + goto out; + } + out: if (err != 0) { VSockVmciUnregisterWithVmci(); @@ -3315,6 +3615,11 @@ VSockVmciUnregisterWithVmci(void) qpResumedSubId = VMCI_INVALID_ID; } + if (ctxUpdatedSubId != VMCI_INVALID_ID) { + VMCIEvent_Unsubscribe(ctxUpdatedSubId); + ctxUpdatedSubId = VMCI_INVALID_ID; + } + VMCI_DeviceRelease(NULL); vmciDevicePresent = FALSE; } @@ -3492,6 +3797,76 @@ VSockVmciDgramConnect(struct socket *soc lock_sock(sk); + if (!VSockAddr_Bound(&vsk->localAddr)) { + struct sockaddr_vm localAddr; + + VSockAddr_Init(&localAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); + if ((err = __VSockVmciBind(sk, &localAddr))) { + goto out; + } + } + + if (!VSockAddr_SocketContextDgram(remoteAddr->svm_cid, + remoteAddr->svm_port)) { + err = -EINVAL; + goto out; + } + + memcpy(&vsk->remoteAddr, remoteAddr, sizeof vsk->remoteAddr); + sock->state = SS_CONNECTED; + +out: + release_sock(sk); + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciSeqConnect -- + * + * Connects a sequential socket. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciSeqConnect(struct socket *sock, // IN + struct sockaddr *addr, // IN + int addrLen, // IN + int flags) // IN +{ + int err; + struct sock *sk; + VSockVmciSock *vsk; + VSockSeqPacket pkt; + struct sockaddr_vm *remoteAddr; + + sk = sock->sk; + vsk = vsock_sk(sk); + + lock_sock(sk); + + if (SS_CONNECTED == sock->state) { + err = -EISCONN; + goto out; + } else if (SS_CONNECTING == sock->state || + SS_DISCONNECTING == sock->state) { + err = -EINVAL; + goto out; + } + + if (VSockAddr_Cast(addr, addrLen, &remoteAddr) != 0) { + err = -EINVAL; + goto out; + } if (!VSockAddr_Bound(&vsk->localAddr)) { struct sockaddr_vm localAddr; @@ -3502,14 +3877,54 @@ VSockVmciDgramConnect(struct socket *soc } } + if (VMCI_HYPERVISOR_CONTEXT_ID != remoteAddr->svm_cid) { + err = -EINVAL; + goto out; + } + + if (VMCI_RPC_PRIVILEGED != remoteAddr->svm_port && + VMCI_RPC_UNPRIVILEGED != remoteAddr->svm_port) { + err = -EINVAL; + goto out; + } + if (!VSockAddr_SocketContextDgram(remoteAddr->svm_cid, remoteAddr->svm_port)) { err = -EINVAL; goto out; } + VSockSeqPacket_Init(&pkt, &vsk->localAddr, remoteAddr, + VSOCK_SEQ_PACKET_TYPE_CONNECT, 0); + + err = VMCIDatagram_Send(&pkt.hdr.dg); + if (err < 0) { + err = VSockVmci_ErrorToVSockError(err); + goto out; + } + + /* + * It's not necessary to get an acknowledgement. We're sending to the + * hypervisor, which means the result of the call tells us whether the + * endpoint accepted it or not. So as long as it returns success, + * we are connected. + */ + memcpy(&vsk->remoteAddr, remoteAddr, sizeof vsk->remoteAddr); + + /* + * The skb routines actually check if this is a sequential socket, and if + * so, they require that the socket be in the TCP established state. So + * we need to use the TCP states for sk_state rather than the SS states + * (our STREAM sockets cheat and get away with it, we should fix that). + */ + sock->state = SS_CONNECTED; + sk->sk_state = TCP_ESTABLISHED; + VSockVmciInsertSeq(vsockSeqSocketsVsk(vsk), sk); + sk->sk_state_change(sk); + + err = 0; out: release_sock(sk); @@ -3966,12 +4381,8 @@ VSockVmciPoll(struct file *file, // I mask |= POLLOUT | POLLWRNORM | POLLWRBAND; } } else if (sock->type == SOCK_STREAM) { - VSockVmciSock *vsk; - lock_sock(sk); - vsk = vsock_sk(sk); - /* * Listening sockets that have connections in their accept queue can be read. */ @@ -3997,8 +4408,9 @@ VSockVmciPoll(struct file *file, // I } /* - * Sockets whose connections have been close, reset, or terminated should also - * be considered read, and we check the shutdown flag for that. + * Sockets whose connections have been closed, reset, or terminated + * should also be considered read, and we check the shutdown flag for + * that. */ if (sk->sk_shutdown & RCV_SHUTDOWN || vsk->peerShutdown & SEND_SHUTDOWN) { @@ -4036,6 +4448,36 @@ VSockVmciPoll(struct file *file, // I } release_sock(sk); + } else if (sock->type == SOCK_SEQPACKET) { + lock_sock(sk); + + /* + * If there is something in the queue then we can read. + */ + if (!skb_queue_empty(&sk->sk_receive_queue) && + !(sk->sk_shutdown & RCV_SHUTDOWN)) { + mask |= POLLIN | POLLRDNORM; + } + + /* + * Sockets whose connections have beed closed, reset or terminated + * should also be considered readable, and we check the shutdown flag + * for that. + */ + if (sk->sk_shutdown & RCV_SHUTDOWN || + vsk->peerShutdown & SEND_SHUTDOWN) { + mask |= POLLIN | POLLRDNORM; + } + + /* + * Connected sockets that can produce data can be written. + */ + if (sk->sk_state == TCP_ESTABLISHED && + !(sk->sk_shutdown & SEND_SHUTDOWN)) { + mask |= POLLOUT | POLLWRNORM; + } + + release_sock(sk); } return mask; @@ -4135,16 +4577,16 @@ VSockVmciShutdown(struct socket *sock, } /* - * If this is a STREAM socket and it is not connected then bail out - * immediately. If it is a DGRAM socket then we must first kick the socket - * so that it wakes up from any sleeping calls, for example recv(), and then - * afterwards return the error. + * If this is a STREAM/SEQPACKET socket and it is not connected then bail + * out immediately. If it is a DGRAM socket then we must first kick the + * socket so that it wakes up from any sleeping calls, for example recv(), + * and then afterwards return the error. */ sk = sock->sk; if (sock->state == SS_UNCONNECTED) { err = -ENOTCONN; - if (sk->sk_type == SOCK_STREAM) { + if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) { return err; } } else { @@ -4152,18 +4594,34 @@ VSockVmciShutdown(struct socket *sock, err = 0; } + /* + * It doesn't make any sense to try and shutdown a sequential socket to + * the hypervisor in the recv direction, only for send or for both. + */ + + if (sk->sk_type == SOCK_SEQPACKET && mode == RCV_SHUTDOWN) { + err = -EINVAL; + return err; + } + /* Receive and send shutdowns are treated alike. */ mode = mode & (RCV_SHUTDOWN | SEND_SHUTDOWN); if (mode) { lock_sock(sk); sk->sk_shutdown |= mode; + if (sk->sk_type == SOCK_SEQPACKET) { + sk->sk_state = TCP_CLOSE; + } sk->sk_state_change(sk); release_sock(sk); - } - if (sk->sk_type == SOCK_STREAM && mode) { - sock_reset_flag(sk, SOCK_DONE); - VSOCK_SEND_SHUTDOWN(sk, mode); + if (sk->sk_type == SOCK_STREAM) { + sock_reset_flag(sk, SOCK_DONE); + VSOCK_SEND_SHUTDOWN(sk, mode); + } else if (sk->sk_type == SOCK_SEQPACKET) { + sock_reset_flag(sk, SOCK_DONE); + err = VSOCK_SEND_SEQ_SHUTDOWN(vsock_sk(sk), mode); + } } return err; @@ -4293,17 +4751,111 @@ VSockVmciDgramSendmsg(struct kiocb *kioc goto out; } + err -= sizeof *dg; + +out: + release_sock(sk); + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciSeqSendmsg -- + * + * Sends a datagram. + * + * Results: + * Number of bytes sent on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciSeqSendmsg(struct kiocb *kiocb, // UNUSED + struct socket *sock, // IN: socket to send on + struct msghdr *msg, // IN: message to send + size_t len) // IN: length of message +{ + int err; + struct sock *sk; + VSockVmciSock *vsk; + VSockSeqPacket *pkt; + + sk = sock->sk; + vsk = vsock_sk(sk); + + if (msg->msg_flags & MSG_OOB) { + return -EOPNOTSUPP; + } + + if (len > VMCI_MAX_DG_PAYLOAD_SIZE) { + return -EMSGSIZE; + } + + lock_sock(sk); + + /* Callers should not provide a destination with sequential sockets. */ + if (msg->msg_namelen) { + err = sock->state == SS_CONNECTED ? -EISCONN : -EOPNOTSUPP; + goto out; + } + + /* Send data only if we're not shutdown in that direction. */ + if (sk->sk_shutdown & SEND_SHUTDOWN) { + err = -EPIPE; + goto out; + } + + if (sock->state != SS_CONNECTED) { + err = -ENOTCONN; + goto out; + } + /* - * err is the number of bytes sent on success. We need to subtract the - * VSock-specific header portions of what we've sent. + * We already managed to connect, which means we must already have the + * right privs to send to our peer. So no need for the usual datagram + * checks here, they were done by connect(). */ - err -= sizeof *dg; + + /* + * Allocate a buffer for the user's message and our packet header. + */ + pkt = kmalloc(len + sizeof *pkt, GFP_KERNEL); + if (!pkt) { + err = -ENOMEM; + goto out; + } + + VSockSeqPacket_Init(pkt, &vsk->localAddr, &vsk->remoteAddr, + VSOCK_SEQ_PACKET_TYPE_DATA, 0); + pkt->hdr.dg.payloadSize += len; + + err = memcpy_fromiovec(VSOCK_SEQ_PACKET_PAYLOAD(pkt), msg->msg_iov, len); + if (0 != err) { + kfree(pkt); + goto out; + } + + err = VMCIDatagram_Send(&pkt->hdr.dg); + kfree(pkt); + if (err < 0) { + err = VSockVmci_ErrorToVSockError(err); + goto out; + } + + err = len; out: release_sock(sk); return err; } + /* *---------------------------------------------------------------------------- * @@ -4661,6 +5213,7 @@ VSockVmciStreamSendmsg(struct kiocb *kio outWait: if (totalWritten > 0) { + VSOCK_STATS_STREAM_PRODUCE(totalWritten); err = totalWritten; } finish_wait(sk_sleep(sk), &wait); @@ -4670,6 +5223,7 @@ out: } + /* *---------------------------------------------------------------------------- * @@ -4699,19 +5253,16 @@ VSockVmciDgramRecvmsg(struct kiocb *kioc VMCIDatagram *dg; size_t payloadLen; struct sk_buff *skb; - struct sockaddr_vm *vmciAddr; - err = 0; sk = sock->sk; - payloadLen = 0; noblock = flags & MSG_DONTWAIT; - vmciAddr = (struct sockaddr_vm *)msg->msg_name; if (flags & MSG_OOB || flags & MSG_ERRQUEUE) { return -EOPNOTSUPP; } /* Retrieve the head sk_buff from the socket's receive queue. */ + err = 0; skb = skb_recv_datagram(sk, flags, noblock, &err); if (err) { return err; @@ -4746,8 +5297,11 @@ VSockVmciDgramRecvmsg(struct kiocb *kioc } msg->msg_namelen = 0; - if (vmciAddr) { + if (msg->msg_name) { + struct sockaddr_vm *vmciAddr; + /* Provide the address of the sender. */ + vmciAddr = (struct sockaddr_vm *)msg->msg_name; VSockAddr_Init(vmciAddr, VMCI_HANDLE_TO_CONTEXT_ID(dg->src), VMCI_HANDLE_TO_RESOURCE_ID(dg->src)); @@ -4764,6 +5318,99 @@ out: /* *---------------------------------------------------------------------------- * + * VSockVmciSeqRecvmsg -- + * + * Receives a datagram and places it in the caller's msg. + * + * Results: + * The size of the payload on success, negative value on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciSeqRecvmsg(struct kiocb *kiocb, // UNUSED + struct socket *sock, // IN: socket to receive from + struct msghdr *msg, // IN/OUT: message to receive into + size_t len, // IN: length of receive buffer + int flags) // IN: receive flags +{ + int err; + int noblock; + size_t payloadLen; + struct sock *sk; + struct sk_buff *skb; + + if (flags & MSG_OOB || flags & MSG_ERRQUEUE) { + return -EOPNOTSUPP; + } + + sk = sock->sk; + noblock = flags & MSG_DONTWAIT; + + /* Retrieve the head sk_buff from the socket's receive queue. */ + err = 0; + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (err) { + return err; + } + + if (!skb) { + return -EAGAIN; + } + + if (!skb->data) { + /* err is 0, meaning we read zero bytes. */ + goto out; + } + + payloadLen = skb->len; + if (payloadLen > len) { + payloadLen = len; + msg->msg_flags |= MSG_TRUNC; + /* + * XXX, we're supposed to be a reliable protocol, so while it's fine to + * return a partial packet here, we shouldn't drop the remainder. We + * should keep it around so that a subsequent recv() can read it and + * then get the end of record marker (see below). + */ + } else { + /* We managed to read the whole payload, so mark the end of record. */ + msg->msg_flags |= MSG_EOR; + } + + /* Place the datagram payload in the user's iovec. */ + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, payloadLen); + if (err) { + goto out; + } + + msg->msg_namelen = 0; + if (msg->msg_name) { + VSockVmciSock *vsk; + struct sockaddr_vm *vmciAddr; + + /* Provide the address of the sender. */ + vsk = vsock_sk(sk); + vmciAddr = (struct sockaddr_vm *)msg->msg_name; + VSockAddr_Init(vmciAddr, + vsk->remoteAddr.svm_cid, vsk->remoteAddr.svm_port); + msg->msg_namelen = sizeof *vmciAddr; + } + err = payloadLen; + +out: + skb_free_datagram(sk, skb); + return err; +} + + +/* + *---------------------------------------------------------------------------- + * * VSockVmciStreamRecvmsg -- * * Receives a datagram and places it in the caller's msg. @@ -4952,6 +5599,8 @@ VSockVmciStreamRecvmsg(struct kiocb *kio */ if (!(flags & MSG_PEEK)) { + VSOCK_STATS_STREAM_CONSUME(copied); + /* * If the other side has shutdown for sending and there is nothing more * to read, then modify the socket state. @@ -5022,6 +5671,9 @@ VSockVmciCreate( case SOCK_STREAM: sock->ops = &vsockVmciStreamOps; break; + case SOCK_SEQPACKET: + sock->ops = &vsockVmciSeqOps; + break; default: return -ESOCKTNOSUPPORT; } diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/af_vsock.h open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/af_vsock.h --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/af_vsock.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/af_vsock.h 2012-05-22 15:12:52.000000000 -0500 @@ -50,9 +50,10 @@ typedef struct VSockVmciSock { struct sock sk; struct sockaddr_vm localAddr; struct sockaddr_vm remoteAddr; - /* Links for the global tables of bound and connected sockets. */ + /* Links for the global tables of bound, connected and sequential sockets. */ struct list_head boundTable; struct list_head connectedTable; + struct list_head seqTable; /* * Accessed without the socket lock held. This means it can never be * modified outsided of socket create or destruct. diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/stats.c open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/stats.c --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/stats.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/stats.c 2012-05-22 15:12:52.000000000 -0500 @@ -34,4 +34,6 @@ uint64 vSockStatsCtlPktCount[VSOCK_PACKET_TYPE_MAX]; uint64 vSockStatsConsumeQueueHist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS]; uint64 vSockStatsProduceQueueHist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS]; +Atomic_uint64 vSockStatsConsumeTotal; +Atomic_uint64 vSockStatsProduceTotal; #endif diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/stats.h open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/stats.h --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/stats.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/stats.h 2012-05-22 15:12:52.000000000 -0500 @@ -35,10 +35,11 @@ /* * Define VSOCK_GATHER_STATISTICS to turn on statistics gathering. - * Currently this consists of 2 types of stats: + * Currently this consists of 3 types of stats: * 1. The number of control datagram messages sent. * 2. The level of queuepair fullness (in 10% buckets) whenever data is * about to be enqueued or dequeued from the queuepair. + * 3. The total number of bytes enqueued/dequeued. */ //#define VSOCK_GATHER_STATISTICS 1 @@ -49,26 +50,31 @@ extern uint64 vSockStatsCtlPktCount[VSOCK_PACKET_TYPE_MAX]; extern uint64 vSockStatsConsumeQueueHist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS]; extern uint64 vSockStatsProduceQueueHist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS]; +extern Atomic_uint64 vSockStatsConsumeTotal; +extern Atomic_uint64 vSockStatsProduceTotal; #define VSOCK_STATS_STREAM_CONSUME_HIST(vsk) \ - VSockVmciStatsUpdateQueueBucketCount((vsk)->consumeQ, \ - (vsk)->produceQ, \ + VSockVmciStatsUpdateQueueBucketCount((vsk)->qpair, \ (vsk)->consumeSize, \ + VMCIQPair_ConsumeBufReady((vsk)->qpair), \ vSockStatsConsumeQueueHist) #define VSOCK_STATS_STREAM_PRODUCE_HIST(vsk) \ - VSockVmciStatsUpdateQueueBucketCount((vsk)->produceQ, \ - (vsk)->consumeQ, \ + VSockVmciStatsUpdateQueueBucketCount((vsk)->qpair, \ (vsk)->produceSize, \ + VMCIQPair_ProduceBufReady((vsk)->qpair), \ vSockStatsProduceQueueHist) #define VSOCK_STATS_CTLPKT_LOG(pktType) \ -do { \ - ++vSockStatsCtlPktCount[pktType]; \ -} while (0) -#define VSOCK_STATS_CTLPKT_DUMP_ALL() \ - VSockVmciStatsCtlPktDumpAll() -#define VSOCK_STATS_HIST_DUMP_ALL() \ - VSockVmciStatsHistDumpAll() -#define VSOCK_STATS_RESET() VSockVmciStatsReset + do { \ + ++vSockStatsCtlPktCount[pktType]; \ + } while (0) +#define VSOCK_STATS_STREAM_CONSUME(bytes) \ + Atomic_FetchAndAdd64(&vSockStatsConsumeTotal, bytes) +#define VSOCK_STATS_STREAM_PRODUCE(bytes) \ + Atomic_FetchAndAdd64(&vSockStatsProduceTotal, bytes) +#define VSOCK_STATS_CTLPKT_DUMP_ALL() VSockVmciStatsCtlPktDumpAll() +#define VSOCK_STATS_HIST_DUMP_ALL() VSockVmciStatsHistDumpAll() +#define VSOCK_STATS_TOTALS_DUMP_ALL() VSockVmciStatsTotalsDumpAll() +#define VSOCK_STATS_RESET() VSockVmciStatsReset() /* *---------------------------------------------------------------------------- @@ -88,23 +94,25 @@ do { */ static INLINE void -VSockVmciStatsUpdateQueueBucketCount(VMCIQueue *mainQueue, // IN - VMCIQueue *otherQueue, // IN - uint64 mainQueueSize, // IN - uint64 queueHist[]) // IN +VSockVmciStatsUpdateQueueBucketCount(VMCIQPair *qpair, // IN + uint64 queueSize, // IN + uint64 dataReady, // IN + uint64 queueHist[]) // IN/OUT { uint64 bucket = 0; uint32 remainder = 0; - uint64 dataReady = VMCIQueue_BufReady(mainQueue, - otherQueue, - mainQueueSize); + + ASSERT(qpair); + ASSERT(queueHist); + /* - * We can't do 64 / 64 = 64 bit divides on linux because it requires a libgcc - * which is not linked into the kernel module. Since this code is only used by - * developers we just limit the mainQueueSize to be less than MAX_UINT for now. -v */ - ASSERT(mainQueueSize <= MAX_UINT32); - Div643264(dataReady * 10, mainQueueSize, &bucket, &remainder); + * We can't do 64 / 64 = 64 bit divides on linux because it requires a + * libgcc which is not linked into the kernel module. Since this code is + * only used by developers we just limit the queueSize to be less than + * MAX_UINT for now. + */ + ASSERT(queueSize <= MAX_UINT32); + Div643264(dataReady * 10, queueSize, &bucket, &remainder); ASSERT(bucket < VSOCK_NUM_QUEUE_LEVEL_BUCKETS); ++queueHist[bucket]; } @@ -180,6 +188,32 @@ VSockVmciStatsHistDumpAll(void) /* *---------------------------------------------------------------------------- * + * VSockVmciStatsTotalsDumpAll -- + * + * Prints the produce and consume totals. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static INLINE void +VSockVmciStatsTotalsDumpAll(void) +{ + Warning("Produced %"FMT64"u total bytes\n", + Atomic_Read64(&vSockStatsProduceTotal)); + Warning("Consumed %"FMT64"u total bytes\n", + Atomic_Read64(&vSockStatsConsumeTotal)); +} + + +/* + *---------------------------------------------------------------------------- + * * VSockVmciStatsReset -- * * Reset all VSock statistics. @@ -209,14 +243,20 @@ VSockVmciStatsReset(void) VSOCK_RESET_ARRAY(vSockStatsConsumeQueueHist); #undef VSOCK_RESET_ARRAY + + Atomic_Write64(&vSockStatsConsumeTotal, 0); + Atomic_Write64(&vSockStatsProduceTotal, 0); } #else #define VSOCK_STATS_STREAM_CONSUME_HIST(vsk) #define VSOCK_STATS_STREAM_PRODUCE_HIST(vsk) +#define VSOCK_STATS_STREAM_PRODUCE(bytes) +#define VSOCK_STATS_STREAM_CONSUME(bytes) #define VSOCK_STATS_CTLPKT_LOG(pktType) #define VSOCK_STATS_CTLPKT_DUMP_ALL() #define VSOCK_STATS_HIST_DUMP_ALL() +#define VSOCK_STATS_TOTALS_DUMP_ALL() #define VSOCK_STATS_RESET() #endif // VSOCK_GATHER_STATISTICS diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/util.c open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/util.c --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/util.c 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/util.c 2012-05-22 15:12:52.000000000 -0500 @@ -33,8 +33,10 @@ struct list_head vsockBindTable[VSOCK_HASH_SIZE + 1]; struct list_head vsockConnectedTable[VSOCK_HASH_SIZE]; +struct list_head vsockSeqTable[VSOCK_HASH_SIZE]; DEFINE_SPINLOCK(vsockTableLock); +DEFINE_SPINLOCK(vsockSeqTableLock); /* @@ -192,6 +194,10 @@ VSockVmciInitTables(void) for (i = 0; i < ARRAYSIZE(vsockConnectedTable); i++) { INIT_LIST_HEAD(&vsockConnectedTable[i]); } + + for (i = 0; i < ARRAYSIZE(vsockSeqTable); i++) { + INIT_LIST_HEAD(&vsockSeqTable[i]); + } } @@ -266,6 +272,40 @@ __VSockVmciInsertConnected(struct list_h /* *---------------------------------------------------------------------------- * + * __VSockVmciInsertSeq -- + * + * Inserts socket into the sequential table. + * + * Note that this assumes any necessary locks are held. + * + * Results: + * None. + * + * Side effects: + * The reference count for sk is incremented. + * + *---------------------------------------------------------------------------- + */ + +void +__VSockVmciInsertSeq(struct list_head *list, // IN + struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(list); + ASSERT(sk); + + vsk = vsock_sk(sk); + + sock_hold(sk); + list_add(&vsk->seqTable, list); +} + + +/* + *---------------------------------------------------------------------------- + * * __VSockVmciRemoveBound -- * * Removes socket from the bound table. @@ -332,6 +372,39 @@ __VSockVmciRemoveConnected(struct sock * /* *---------------------------------------------------------------------------- * + * __VSockVmciRemoveSeq -- + * + * Removes socket from the sequential table. + * + * Note that this assumes any necessary locks are held. + * + * Results: + * None. + * + * Side effects: + * The reference count for sk is decremented. + * + *---------------------------------------------------------------------------- + */ + +void +__VSockVmciRemoveSeq(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + ASSERT(__VSockVmciInSeqTable(sk)); + + vsk = vsock_sk(sk); + + list_del_init(&vsk->seqTable); + sock_put(sk); +} + + +/* + *---------------------------------------------------------------------------- + * * __VSockVmciFindBoundSocket -- * * Finds the socket corresponding to the provided address in the bound @@ -476,6 +549,35 @@ __VSockVmciInConnectedTable(struct sock } +/* + *---------------------------------------------------------------------------- + * + * __VSockVmciInSeqTable -- + * + * Determines whether the provided socket is in the sequential table. + * + * Results: + * TRUE is socket is in sequential table, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +Bool +__VSockVmciInSeqTable(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + + vsk = vsock_sk(sk); + + return !list_empty(&vsk->seqTable); +} + + /* *---------------------------------------------------------------------------- * diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/util.h open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/util.h --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/util.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/util.h 2012-05-22 15:12:52.000000000 -0500 @@ -47,6 +47,8 @@ * vsockBindTable[VSOCK_HASH_SIZE - 1] are for bound sockets and * vsockBindTable[VSOCK_HASH_SIZE] is for unbound sockets. The hash function * mods with VSOCK_HASH_SIZE - 1 to ensure this. + * + * Connected sequential sockets are put in the seq table. */ #define VSOCK_HASH_SIZE 251 #define LAST_RESERVED_PORT 1023 @@ -54,8 +56,10 @@ extern struct list_head vsockBindTable[VSOCK_HASH_SIZE + 1]; extern struct list_head vsockConnectedTable[VSOCK_HASH_SIZE]; +extern struct list_head vsockSeqTable[VSOCK_HASH_SIZE]; extern spinlock_t vsockTableLock; +extern spinlock_t vsockSeqTableLock; #define VSOCK_HASH(addr) ((addr)->svm_port % (VSOCK_HASH_SIZE - 1)) #define vsockBoundSockets(addr) (&vsockBindTable[VSOCK_HASH(addr)]) @@ -68,6 +72,11 @@ extern spinlock_t vsockTableLock; (&vsockConnectedTable[VSOCK_CONN_HASH(src, dst)]) #define vsockConnectedSocketsVsk(vsk) \ vsockConnectedSockets(&(vsk)->remoteAddr, &(vsk)->localAddr) +#define VSOCK_SEQ_HASH(src, dst) VSOCK_CONN_HASH(src, dst) +#define vsockSeqSockets(src, dst) \ + (&vsockSeqTable[VSOCK_SEQ_HASH(src, dst)]) +#define vsockSeqSocketsVsk(vsk) \ + vsockSeqSockets(&(vsk)->remoteAddr, &(vsk)->localAddr) /* * Prototypes. @@ -78,13 +87,16 @@ void VSockVmciLogPkt(char const *functio void VSockVmciInitTables(void); void __VSockVmciInsertBound(struct list_head *list, struct sock *sk); void __VSockVmciInsertConnected(struct list_head *list, struct sock *sk); +void __VSockVmciInsertSeq(struct list_head *list, struct sock *sk); void __VSockVmciRemoveBound(struct sock *sk); void __VSockVmciRemoveConnected(struct sock *sk); +void __VSockVmciRemoveSeq(struct sock *sk); struct sock *__VSockVmciFindBoundSocket(struct sockaddr_vm *addr); struct sock *__VSockVmciFindConnectedSocket(struct sockaddr_vm *src, struct sockaddr_vm *dst); Bool __VSockVmciInBoundTable(struct sock *sk); Bool __VSockVmciInConnectedTable(struct sock *sk); +Bool __VSockVmciInSeqTable(struct sock *sk); struct sock *VSockVmciGetPending(struct sock *listener, VSockPacket *pkt); void VSockVmciReleasePending(struct sock *pending); @@ -99,13 +111,16 @@ Bool VSockVmciIsPending(struct sock *sk) static INLINE void VSockVmciInsertBound(struct list_head *list, struct sock *sk); static INLINE void VSockVmciInsertConnected(struct list_head *list, struct sock *sk); +static INLINE void VSockVmciInsertSeq(struct list_head *list, struct sock *sk); static INLINE void VSockVmciRemoveBound(struct sock *sk); static INLINE void VSockVmciRemoveConnected(struct sock *sk); +static INLINE void VSockVmciRemoveSeq(struct sock *sk); static INLINE struct sock *VSockVmciFindBoundSocket(struct sockaddr_vm *addr); static INLINE struct sock *VSockVmciFindConnectedSocket(struct sockaddr_vm *src, struct sockaddr_vm *dst); static INLINE Bool VSockVmciInBoundTable(struct sock *sk); static INLINE Bool VSockVmciInConnectedTable(struct sock *sk); +static INLINE Bool VSockVmciInSeqTable(struct sock *sk); /* @@ -175,6 +190,38 @@ VSockVmciInsertConnected(struct list_hea /* *---------------------------------------------------------------------------- * + * VSockVmciInsertSeq -- + * + * Inserts socket into the sequential table. + * + * Note that it is important to invoke the bottom-half versions of the + * spinlock functions since these may be called from tasklets. + * + * Results: + * None. + * + * Side effects: + * vsockSeqTableLock is acquired and released. + * + *---------------------------------------------------------------------------- + */ + +static INLINE void +VSockVmciInsertSeq(struct list_head *list, // IN + struct sock *sk) // IN +{ + ASSERT(list); + ASSERT(sk); + + spin_lock_bh(&vsockSeqTableLock); + __VSockVmciInsertSeq(list, sk); + spin_unlock_bh(&vsockSeqTableLock); +} + + +/* + *---------------------------------------------------------------------------- + * * VSockVmciRemoveBound -- * * Removes socket from the bound list. @@ -235,6 +282,36 @@ VSockVmciRemoveConnected(struct sock *sk /* *---------------------------------------------------------------------------- * + * VSockVmciRemoveSeq -- + * + * Removes socket from the sequential list. + * + * Note that it is important to invoke the bottom-half versions of the + * spinlock functions since these may be called from tasklets. + * + * Results: + * None. + * + * Side effects: + * vsockSeqTableLock is acquired and released. + * + *---------------------------------------------------------------------------- + */ + +static INLINE void +VSockVmciRemoveSeq(struct sock *sk) // IN +{ + ASSERT(sk); + + spin_lock_bh(&vsockSeqTableLock); + __VSockVmciRemoveSeq(sk); + spin_unlock_bh(&vsockSeqTableLock); +} + + +/* + *---------------------------------------------------------------------------- + * * VSockVmciFindBoundSocket -- * * Finds the socket corresponding to the provided address in the bound @@ -379,4 +456,39 @@ VSockVmciInConnectedTable(struct sock *s return ret; } + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciInSeqTable -- + * + * Determines whether the provided socket is in the sequential table. + * + * Note that it is important to invoke the bottom-half versions of the + * spinlock functions since these may be called from tasklets. + * + * Results: + * TRUE is socket is in sequential table, FALSE otherwise. + * + * Side effects: + * vsockSeqTableLock is acquired and released. + * + *---------------------------------------------------------------------------- + */ + +static INLINE Bool +VSockVmciInSeqTable(struct sock *sk) // IN +{ + Bool ret; + + ASSERT(sk); + + spin_lock_bh(&vsockSeqTableLock); + ret = __VSockVmciInSeqTable(sk); + spin_unlock_bh(&vsockSeqTableLock); + + return ret; +} + + #endif /* __UTIL_H__ */ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/vmci_sockets_packet.h open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/vmci_sockets_packet.h --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/vmci_sockets_packet.h 1969-12-31 18:00:00.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/vmci_sockets_packet.h 2012-05-22 15:12:52.000000000 -0500 @@ -0,0 +1,158 @@ +/********************************************************* + * Copyright (C) 2012 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 + * + *********************************************************/ + +/* + * vmci_sockets_packet.h -- + * + * Definition of VMCI Sockets packet format, constants, and types. + */ + +#ifndef _VMCI_SOCKETS_PACKET_H_ +#define _VMCI_SOCKETS_PACKET_H_ + +#include "vmci_defs.h" +#include "vmci_call_defs.h" + +/* + * STREAM control packets. + */ + +/* If the packet format changes in a release then this should change too. */ +#define VSOCK_PACKET_VERSION 1 + +/* The resource ID on which control packets are sent. */ +#define VSOCK_PACKET_RID 1 + +/* + * Assert that the given packet is valid. + * We check that the two original reserved fields equal zero because the + * version of the common code that shipped with ESX 4.0 and WS 6.5 did so and + * will return a RST packet if they aren't set that way. For newer packet + * types added after that release we don't do this. + */ +#define VSOCK_PACKET_ASSERT(_p) \ + do { \ + ASSERT((_p)); \ + ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX); \ + if ((_p)->type < VSOCK_PACKET_TYPE_REQUEST2) { \ + ASSERT(0 == (_p)->proto); \ + ASSERT(0 == (_p)->_reserved2); \ + } \ + } while(0) + +typedef enum VSockPacketType { + VSOCK_PACKET_TYPE_INVALID = 0, // Invalid type. + VSOCK_PACKET_TYPE_REQUEST, // Connection request (WR/WW/READ/WRITE) + VSOCK_PACKET_TYPE_NEGOTIATE, // Connection negotiate. + VSOCK_PACKET_TYPE_OFFER, // Connection offer queue pair. + VSOCK_PACKET_TYPE_ATTACH, // Connection attach. + VSOCK_PACKET_TYPE_WROTE, // Wrote data to queue pair. + VSOCK_PACKET_TYPE_READ, // Read data from queue pair. + VSOCK_PACKET_TYPE_RST, // Reset. + VSOCK_PACKET_TYPE_SHUTDOWN, // Shutdown the connection. + VSOCK_PACKET_TYPE_WAITING_WRITE, // Notify peer we are waiting to write. + VSOCK_PACKET_TYPE_WAITING_READ, // Notify peer we are waiting to read. + VSOCK_PACKET_TYPE_REQUEST2, // Connection request (new proto flags) + VSOCK_PACKET_TYPE_NEGOTIATE2, // Connection request (new proto flags) + VSOCK_PACKET_TYPE_MAX // Last message. +} VSockPacketType; + +typedef uint16 VSockProtoVersion; +#define VSOCK_PROTO_INVALID 0 // Invalid protocol version. +#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0) // Queuepair inspection proto. + +#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY) + +typedef struct VSockWaitingInfo { + uint64 generation; // Generation of the queue. + uint64 offset; // Offset within the queue. +} VSockWaitingInfo; + +/* + * Control packet type for STREAM sockets. DGRAMs have no control packets + * nor special packet header for data packets, they are just raw VMCI DGRAM + * messages. For STREAMs, control packets are sent over the control channel + * while data is written and read directly from queue pairs with no packet + * format. + */ +typedef struct VSockPacket { + VMCIDatagram dg; // Datagram header. + uint8 version; // Version. + uint8 type; // Type of message. + VSockProtoVersion proto; // Supported proto versions in CONNECT2 and + // NEGOTIATE2. 0 otherwise. + uint32 srcPort; // Source port. + uint32 dstPort; // Destination port. + uint32 _reserved2; // Reserved. + union { + uint64 size; // Size of queue pair for request/negotiation. + uint64 mode; // Mode of shutdown for shutdown. + VMCIHandle handle; // Queue pair handle once size negotiated. + VSockWaitingInfo wait; // Information provided for wait notifications. + } u; +} VSockPacket; + +/* + * SEQPACKET packets. + */ + +#define VSOCK_SEQ_PACKET_VERSION_1 1 +#define VSOCK_SEQ_PACKET_VERSION VSOCK_SEQ_PACKET_VERSION_1 + +/* Get the packet's payload size in bytes. */ +#define VSOCK_SEQ_PACKET_PAYLOAD_SIZE(_pkt) \ + (VMCI_DG_SIZE(&(_pkt)->hdr.dg) - (_pkt)->hdr.offset) + +/* Get a pointer to the packet's payload. */ +#define VSOCK_SEQ_PACKET_PAYLOAD(_pkt) \ + (void *)((char *)_pkt + (_pkt)->hdr.offset) + +typedef enum VSockSeqPacketType { + VSOCK_SEQ_PACKET_TYPE_INVALID = 0, // Invalid type. + VSOCK_SEQ_PACKET_TYPE_CONNECT, // Connection request. + VSOCK_SEQ_PACKET_TYPE_DATA, // Data. + VSOCK_SEQ_PACKET_TYPE_SHUTDOWN, // Shutdown. + VSOCK_SEQ_PACKET_TYPE_CLOSE, // Close (graceful or error). +} VSockSeqPacketType; + +/* Header for all packet versions. */ +typedef struct VSockSeqPacketHdr { + VMCIDatagram dg; // Datagram header. + uint8 version; // Version. + uint8 type; // Type of message. + uint16 offset; // Offset of data from start of packet. + int32 val; // Value. +} VSockSeqPacketHdr; + +/* Combination of all versions. */ +typedef struct VSockSeqPacket { + VSockSeqPacketHdr hdr; + /* Other versions go here. */ + /* Data is at base + hdr.offset. */ +} VSockSeqPacket; + +/* + * Size assertions. + */ + +MY_ASSERTS(VSockSeqPacketAsserts, + ASSERT_ON_COMPILE(sizeof (VSockPacket) == 56); + ASSERT_ON_COMPILE(sizeof (VSockSeqPacket) == 32); +) + +#endif // _VMCI_SOCKETS_PACKET_H_ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/vsockPacket.h open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/vsockPacket.h --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/vsockPacket.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/vsockPacket.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. + * Copyright (C) 2007-2012 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 @@ -25,6 +25,8 @@ #ifndef _VSOCK_PACKET_H_ #define _VSOCK_PACKET_H_ +#include "vmci_sockets_packet.h" + #if defined(_WIN32) || defined(VMKERNEL) || defined(__APPLE__) # include "vsockOSInt.h" #else @@ -33,87 +35,6 @@ #endif -/* If the packet format changes in a release then this should change too. */ -#define VSOCK_PACKET_VERSION 1 - -/* The resource ID on which control packets are sent. */ -#define VSOCK_PACKET_RID 1 - -/* - * Assert that the given packet is valid. - * We check that the two original reserved fields equal zero because the - * version of the common code that shipped with ESX 4.0 and WS 6.5 did so and - * will return a RST packet if they aren't set that way. For newer packet - * types added after that release we don't do this. - */ -#define VSOCK_PACKET_ASSERT(_p) \ - do { \ - ASSERT((_p)); \ - ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX); \ - if ((_p)->type < VSOCK_PACKET_TYPE_REQUEST2) { \ - ASSERT(0 == (_p)->proto); \ - ASSERT(0 == (_p)->_reserved2); \ - } \ - } while(0) - -typedef enum VSockPacketType { - VSOCK_PACKET_TYPE_INVALID = 0, // Invalid type. - VSOCK_PACKET_TYPE_REQUEST, // Connection request (WR/WW/READ/WRITE) - VSOCK_PACKET_TYPE_NEGOTIATE, // Connection negotiate. - VSOCK_PACKET_TYPE_OFFER, // Connection offer queue pair. - VSOCK_PACKET_TYPE_ATTACH, // Connection attach. - VSOCK_PACKET_TYPE_WROTE, // Wrote data to queue pair. - VSOCK_PACKET_TYPE_READ, // Read data from queue pair. - VSOCK_PACKET_TYPE_RST, // Reset. - VSOCK_PACKET_TYPE_SHUTDOWN, // Shutdown the connection. - VSOCK_PACKET_TYPE_WAITING_WRITE, // Notify peer we are waiting to write. - VSOCK_PACKET_TYPE_WAITING_READ, // Notify peer we are waiting to read. - VSOCK_PACKET_TYPE_REQUEST2, // Connection request (new proto flags) - VSOCK_PACKET_TYPE_NEGOTIATE2, // Connection request (new proto flags) - VSOCK_PACKET_TYPE_MAX // Last message. -} VSockPacketType; - -typedef uint16 VSockProtoVersion; -#define VSOCK_PROTO_INVALID 0 // Invalid protocol version. -#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0) // Queuepair inspection proto. - -#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY) - -typedef struct VSockWaitingInfo { - uint64 generation; // Generation of the queue. - uint64 offset; // Offset within the queue. -} VSockWaitingInfo; - -/* - * Control packet type for STREAM sockets. DGRAMs have no control packets - * nor special packet header for data packets, they are just raw VMCI DGRAM - * messages. For STREAMs, control packets are sent over the control channel - * while data is written and read directly from queue pairs with no packet - * format. - */ -typedef struct VSockPacket { - VMCIDatagram dg; // Datagram header. - uint8 version; // Version. - uint8 type; // Type of message. - VSockProtoVersion proto; // Supported proto versions in CONNECT2 and - // NEGOTIATE2. 0 otherwise. - uint32 srcPort; // Source port. - uint32 dstPort; // Destination port. - uint32 _reserved2; // Reserved. - union { - uint64 size; // Size of queue pair for request/negotiation. - uint64 mode; // Mode of shutdown for shutdown. - VMCIHandle handle; // Queue pair handle once size negotiated. - VSockWaitingInfo wait; // Information provided for wait notifications. - } u; -} VSockPacket; - - -MY_ASSERTS(VSockPacketAsserts, - ASSERT_ON_COMPILE(sizeof (VSockPacket) == 56); -) - - /* *----------------------------------------------------------------------------- * @@ -297,7 +218,7 @@ exit: * Get the local and remote addresses from the given packet. * * Results: - * None + * None. * * Side effects: * None. @@ -318,5 +239,50 @@ VSockPacket_GetAddresses(VSockPacket *pk } -#endif // _VSOCK_PACKET_H_ +/* + * SEQPACKET packets. + */ + +/* + *----------------------------------------------------------------------------- + * + * VSockSeqPacket_Init + * + * Initialize the given packet. This will use the current version and + * set the offset to point after the current (combined) structure. The + * length will be set to include the combined structure. To add data + * after calling this function, do "pkt->hdr.dg.payloadSize += dataLen". + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +VSockSeqPacket_Init(VSockSeqPacket *pkt, // IN/OUT + struct sockaddr_vm *src, // IN + struct sockaddr_vm *dst, // IN + uint8 type, // IN + int32 val) // IN +{ + ASSERT(pkt); + VSOCK_ADDR_NOFAMILY_ASSERT(src); + VSOCK_ADDR_NOFAMILY_ASSERT(dst); + + pkt->hdr.dg.src = VMCI_MAKE_HANDLE(src->svm_cid, src->svm_port); + pkt->hdr.dg.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, + dst->svm_port); + pkt->hdr.dg.payloadSize = sizeof *pkt - sizeof pkt->hdr.dg; + pkt->hdr.version = VSOCK_SEQ_PACKET_VERSION; + pkt->hdr.type = type; + pkt->hdr.offset = sizeof *pkt; + pkt->hdr.val = val; +} + + +#endif // _VSOCK_PACKET_H_ diff -Narup open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/vsock_version.h open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/vsock_version.h --- open-vm-tools-2011.12.20-562307/modules/linux/vsock/linux/vsock_version.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/linux/vsock/linux/vsock_version.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2011 VMware, Inc. All rights reserved. + * Copyright (C) 2011-2012 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 @@ -25,8 +25,8 @@ #ifndef _VSOCK_VERSION_H_ #define _VSOCK_VERSION_H_ -#define VSOCK_DRIVER_VERSION 9.3.3.0 -#define VSOCK_DRIVER_VERSION_COMMAS 9,3,3,0 -#define VSOCK_DRIVER_VERSION_STRING "9.3.3.0" +#define VSOCK_DRIVER_VERSION 9.5.3.0 +#define VSOCK_DRIVER_VERSION_COMMAS 9,5.3,0 +#define VSOCK_DRIVER_VERSION_STRING "9.5.3.0" #endif /* _VSOCK_VERSION_H_ */ diff -Narup open-vm-tools-2011.12.20-562307/modules/Makefile.in open-vm-tools-2012.05.21-724730/modules/Makefile.in --- open-vm-tools-2011.12.20-562307/modules/Makefile.in 2011-12-21 18:56:36.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/Makefile.in 2012-05-22 15:15:25.000000000 -0500 @@ -99,6 +99,7 @@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ DNET_CPPFLAGS = @DNET_CPPFLAGS@ DNET_LIBS = @DNET_LIBS@ DOT = @DOT@ @@ -151,6 +152,7 @@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MODULES = @MODULES@ MODULES_DIR = @MODULES_DIR@ @@ -208,6 +210,7 @@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ @@ -245,7 +248,6 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ diff -Narup open-vm-tools-2011.12.20-562307/modules/shared/vmxnet/eth_public.h open-vm-tools-2012.05.21-724730/modules/shared/vmxnet/eth_public.h --- open-vm-tools-2011.12.20-562307/modules/shared/vmxnet/eth_public.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/shared/vmxnet/eth_public.h 2012-05-22 15:12:52.000000000 -0500 @@ -612,7 +612,7 @@ Eth_IsBeaconSap(const Eth_Header *eh, co { Eth_HdrType type = Eth_HeaderType(eh); - if ((type == ETH_HEADER_TYPE_802_3)) { + if (type == ETH_HEADER_TYPE_802_3) { if ((eh->e802_3.llc.dsap == sap) && (eh->e802_3.llc.ssap == sap)) { if (eh->e802_3.lenNBO != 0) { return TRUE; diff -Narup open-vm-tools-2011.12.20-562307/modules/shared/vmxnet/vmnet_def.h open-vm-tools-2012.05.21-724730/modules/shared/vmxnet/vmnet_def.h --- open-vm-tools-2011.12.20-562307/modules/shared/vmxnet/vmnet_def.h 2011-12-21 18:56:24.000000000 -0600 +++ open-vm-tools-2012.05.21-724730/modules/shared/vmxnet/vmnet_def.h 2012-05-22 15:12:52.000000000 -0500 @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2004 VMware, Inc. All rights reserved. + * Copyright (C) 2004-2011 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 @@ -49,7 +49,7 @@ #include "includeCheck.h" #define VMNET_NAME_BUFFER_LEN 128 /* Increased for i18n. */ -#define VMNET_COAL_SCHEME_NAME_LEN 16 +#define VMNET_COAL_STRING_LEN 16 /* @@ -81,7 +81,7 @@ #define VMNET_CAP_TSO256k 0x200000 /* Can do TSO segmentation offload for pkts up to 256kB. */ #define VMNET_CAP_UPT 0x400000 /* Support UPT */ #define VMNET_CAP_RDONLY_INETHDRS 0x800000 /* Modifies inet headers for TSO/CSUm */ -#define VMNET_CAP_NPA 0x1000000 /* Support NPA */ +#define VMNET_CAP_ENCAP 0x1000000 /* NPA not used, so redefining for ENCAP support */ #define VMNET_CAP_DCB 0x2000000 /* Support DCB */ #define VMNET_CAP_OFFLOAD_8OFFSET 0x4000000 /* supports 8bit parameterized offsets */ #define VMNET_CAP_OFFLOAD_16OFFSET 0x8000000 /* supports 16bit parameterized offsets */ @@ -89,4 +89,7 @@ #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 0x100000000 /* support RSS FIXME get a 32 flag */ +#endif #endif // _VMNET_DEF_H_