From: Oliver Kurth Date: Fri, 15 Sep 2017 18:23:41 +0000 (-0700) Subject: Remove Linux kernel modules X-Git-Tag: stable-10.2.0~192 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=131e4a60fa2d2db0c30920d826d23aec44d8ab09;p=thirdparty%2Fopen-vm-tools.git Remove Linux kernel modules Remove Linux kernel modules from open-vm-tools. --- diff --git a/open-vm-tools/configure.ac b/open-vm-tools/configure.ac index 22c9380e2..bfd57dfb3 100644 --- a/open-vm-tools/configure.ac +++ b/open-vm-tools/configure.ac @@ -136,7 +136,7 @@ AC_ARG_WITH([kernel-modules], [AS_HELP_STRING([--with-kernel-modules], [compile and install the kernel modules])], [], - [if test "x$os" = "xlinux" -a "$osVersion" -ge 400000; then + [if test "x$os" = "xlinux" ; then with_kernel_modules=no else with_kernel_modules=yes @@ -146,18 +146,8 @@ AC_ARG_WITH([kernel-modules], if test "$with_kernel_modules" = "yes"; then case "$os" in linux) - if test "$osVersion" -lt 206009; then - AC_MSG_ERROR([Kernels prior to 2.6.9 are not supported in this release of open-vm-tools. Configure using --without-kernel-modules to suppress building kernel drivers.]) - fi - if test ! -d "$LINUXDIR/kernel/"; then - AC_MSG_ERROR([$LINUXDIR/kernel does not exist]) - fi - LINUXINCLUDE="$LINUXDIR/build/include" - if test ! -d "$LINUXINCLUDE"; then - AC_MSG_ERROR([Cannot find include dir under $LINUXDIR]) - fi + AC_MSG_ERROR([Building kernel modules for Linux is no longer supported.]) ;; - freebsd) freebsd_sysdir=/usr/src/sys if test -n "$SYSDIR"; then diff --git a/open-vm-tools/modules/Makefile.am b/open-vm-tools/modules/Makefile.am index 39ef12050..c10f449e8 100644 --- a/open-vm-tools/modules/Makefile.am +++ b/open-vm-tools/modules/Makefile.am @@ -16,21 +16,6 @@ EXTRA_ARGS = EXTRA_ARGS += "SYSDIR=@SYSDIR@" endif -if LINUX -export LINUXINCLUDE := @LINUXINCLUDE@ -export vmblockdir := $(MODULES_DIR)/fs/vmblock -export vmcidir := $(MODULES_DIR)/drivers/misc -export vmhgfsdir := $(MODULES_DIR)/fs/vmhgfs -export vmsyncdir := $(MODULES_DIR)/drivers/misc -export vmxnetdir := $(MODULES_DIR)/drivers/net -export vsockdir := $(MODULES_DIR)/net/vsock -if WITH_ROOT_PRIVILEGES -export DEPMOD := depmod -a $(KERNEL_RELEASE) -endif WITH_ROOT_PRIVILEGES - -include_HEADERS = $(top_srcdir)/lib/include/vmci_sockets.h -endif LINUX - if SOLARIS export vmhgfsdir := $(MODULES_DIR) # Solaris does not have Kbuild-like system so we need to supply @@ -69,14 +54,6 @@ if FREEBSD $(DESTDIR)$(MODULES_DIR); \ done endif -if LINUX - for MOD in $(MODULES); do \ - $(INSTALL) -d $(DESTDIR)`eval echo '$$'$${MOD}dir`; \ - $(INSTALL) -m644 $(modulesrc)/$(MODULES_OS)/$$MOD/$$MOD.ko \ - $(DESTDIR)`eval echo '$$'$${MOD}dir`; \ - done - eval "$$DEPMOD" -endif uninstall-hook: for MOD in $(MODULES); do \ diff --git a/open-vm-tools/modules/linux/dkms.conf b/open-vm-tools/modules/linux/dkms.conf deleted file mode 100644 index 4c75c0f6b..000000000 --- a/open-vm-tools/modules/linux/dkms.conf +++ /dev/null @@ -1,39 +0,0 @@ -PACKAGE_NAME=open-vm-tools -PACKAGE_VERSION=10.0.0 -MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \ - MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build" - -# The vsock module depends on symbols exported by the vmci module, so it -# needs to be built afterwards; the MODULEBUILDDIR variable tells the makefiles -# where to store / retrive those symbol files. -MAKE[0]="$MAKE_CMD_TMPL -C vmblock; \ - $MAKE_CMD_TMPL -C vmci; \ - $MAKE_CMD_TMPL -C vmhgfs; \ - $MAKE_CMD_TMPL -C vmsync; \ - $MAKE_CMD_TMPL -C vmxnet; \ - $MAKE_CMD_TMPL -C vsock" -CLEAN[0]="$MAKE_CMD_TMPL -C vmblock clean; \ - $MAKE_CMD_TMPL -C vmci clean; \ - $MAKE_CMD_TMPL -C vmhgfs clean; \ - $MAKE_CMD_TMPL -C vmsync clean"; \ - $MAKE_CMD_TMPL -C vmxnet clean; \ - $MAKE_CMD_TMPL -C vsock clean -BUILT_MODULE_NAME[0]="vmblock" -BUILT_MODULE_NAME[1]="vmci" -BUILT_MODULE_NAME[2]="vmhgfs" -BUILT_MODULE_NAME[3]="vmsync" -BUILT_MODULE_NAME[4]="vmxnet" -BUILT_MODULE_NAME[5]="vsock" -BUILT_MODULE_LOCATION[0]="vmblock/" -BUILT_MODULE_LOCATION[1]="vmci/" -BUILT_MODULE_LOCATION[2]="vmhgfs/" -BUILT_MODULE_LOCATION[3]="vmsync/" -BUILT_MODULE_LOCATION[4]="vmxnet/" -BUILT_MODULE_LOCATION[5]="vsock/" -DEST_MODULE_LOCATION[0]="/kernel/fs/vmblock" -DEST_MODULE_LOCATION[1]="/kernel/drivers/misc" -DEST_MODULE_LOCATION[2]="/kernel/fs/vmhgfs" -DEST_MODULE_LOCATION[3]="/kernel/drivers/misc" -DEST_MODULE_LOCATION[4]="/kernel/drivers/net" -DEST_MODULE_LOCATION[5]="/kernel/net/vsock" -AUTOINSTALL="YES" diff --git a/open-vm-tools/modules/linux/dkms.sh b/open-vm-tools/modules/linux/dkms.sh deleted file mode 100644 index 3b89a8eff..000000000 --- a/open-vm-tools/modules/linux/dkms.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/sh -################################################################################ -### Copyright (C) 2009-2017 VMware, Inc. All rights reserved. -### -### Script for creating a dmks-compliant source tree from an open-vm-tools -### distribution. -### -### -### This program is free software; you can redistribute it and/or modify -### it under the terms of version 2 of the GNU General Public License as -### published by the Free Software Foundation. -### -### 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 -################################################################################ - -if test -z "$1" -o -z "$2" -then - echo "usage: $0 src dst" - echo - echo "Where:" - echo " src: root of unpacked open-vm-tools package" - echo " dst: where to create the dkms tree" - echo - echo "The script will create an 'open-vm-tools' module with version 10.0.0." - exit 1 -fi - -src=$1 -dst=$2/open-vm-tools-10.0.0 - -SHARED_HEADERS="backdoor_def.h" -SHARED_HEADERS="$SHARED_HEADERS backdoor_types.h" -SHARED_HEADERS="$SHARED_HEADERS circList.h" -SHARED_HEADERS="$SHARED_HEADERS community_source.h" -SHARED_HEADERS="$SHARED_HEADERS dbllnklst.h" -SHARED_HEADERS="$SHARED_HEADERS guest_msg_def.h" -SHARED_HEADERS="$SHARED_HEADERS includeCheck.h" -SHARED_HEADERS="$SHARED_HEADERS vm_assert.h" -SHARED_HEADERS="$SHARED_HEADERS vm_atomic.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm_x86.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm_x86_64.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm_x86_common.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_defs.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_math.h" -SHARED_HEADERS="$SHARED_HEADERS vm_basic_types.h" -SHARED_HEADERS="$SHARED_HEADERS vm_device_version.h" -SHARED_HEADERS="$SHARED_HEADERS vmci_sockets.h" -SHARED_HEADERS="$SHARED_HEADERS vmware.h" -SHARED_HEADERS="$SHARED_HEADERS vmware_pack_begin.h" -SHARED_HEADERS="$SHARED_HEADERS vmware_pack_end.h" -SHARED_HEADERS="$SHARED_HEADERS vmware_pack_init.h" -SHARED_HEADERS="$SHARED_HEADERS x86cpuid.h" -SHARED_HEADERS="$SHARED_HEADERS x86vendor.h" -SHARED_HEADERS="$SHARED_HEADERS x86cpuid_asm.h" - -rm -rf $dst -mkdir -p $dst -cp -f `dirname $0`/dkms.conf $dst - -for m in vmblock vmci vmhgfs vmsync vmxnet vsock -do - mdst="$dst/$m" - - cp -rf $src/modules/linux/$m $mdst - cp -rf $src/modules/linux/shared $mdst - for h in $SHARED_HEADERS - do - cp -f $src/lib/include/$h $mdst/shared - done - - # Shared vmblock code. - if test $m = vmblock - then - cp -f $src/lib/include/vmblock.h $mdst/linux - cp -rf $src/modules/shared/vmblock/* $mdst/linux - fi - - # Backdoor library (for vmhgfs and vmmemctl). - if test $m = vmhgfs -o $m = vmmemctl - then - cp -f $src/lib/include/backdoor.h $mdst - cp -f $src/lib/backdoor/*.c $src/lib/backdoor/*.h $mdst - fi - - # Other libraries used by vmhgfs - if test $m = vmhgfs - then - cp -f $src/lib/include/cpName*.h $mdst - cp -f $src/lib/include/escBitvector.h $mdst - cp -f $src/lib/include/hgfs*.h $mdst - cp -f $src/lib/include/message.h $mdst - cp -f $src/lib/include/rpcout.h $mdst - cp -f $src/lib/hgfs/*.c $src/lib/hgfs/*.h $mdst - cp -f $src/lib/hgfsBd/*.c $mdst - cp -f $src/lib/message/*.c $mdst - cp -f $src/lib/rpcOut/*.c $mdst - fi - - # Extra header file for vmsync. - if test $m = vmsync - then - cp -f $src/lib/include/syncDriverIoc.h $mdst - fi - - # Shared vmxnet headers. - if test $m = vmxnet - then - cp -f $src/modules/shared/vmxnet/* $mdst/shared - fi -done - diff --git a/open-vm-tools/modules/linux/shared/autoconf/cachecreate.c b/open-vm-tools/modules/linux/shared/autoconf/cachecreate.c deleted file mode 100644 index 1eaaf1e28..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/cachecreate.c +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -/* - * All kernels before 2.6.22 take 6 arguments. All kernels since - * 2.6.23-rc1 take 5 arguments. Only kernels between 2.6.22 and - * 2.6.23-rc1 are questionable - we could ignore them if we wanted, - * nobody cares about them even now. But unfortunately RedHat is - * re-releasing 2.6.X-rc kernels under 2.6.(X-1) name, so they - * are releasing 2.6.23-rc1 as 2.6.22-5055-something, so we have - * to do autodetection for them. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) -/* Success... */ -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) -#error "This test intentionally fails on 2.6.23 and newer kernels." -#else -#include - -struct kmem_cache *kmemtest(void) { - return kmem_cache_create("test", 12, 0, 0, NULL, NULL); -} - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/cachector.c b/open-vm-tools/modules/linux/shared/autoconf/cachector.c deleted file mode 100644 index 0f81ed45d..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/cachector.c +++ /dev/null @@ -1,40 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -/* - * Between 2.6.23 and 2.6.24-rc1 ctor prototype was changed from - * ctor(ptr, cache, flags) to ctor(cache, ptr). Unfortunately there - * is no typedef for ctor, so we have to redefine kmem_cache_create - * to find out ctor prototype. This assumes that kmem_cache_create - * takes 5 arguments and not 6 - that change occured between - * 2.6.22 and 2.6.23-rc1. If prototype matches, then this is old - * kernel. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -#error "This test intentionally fails on 2.6.24 and newer kernels." -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) -#include - -struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, - unsigned long, - void (*)(void *, struct kmem_cache *, unsigned long)); - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/cachector1.c b/open-vm-tools/modules/linux/shared/autoconf/cachector1.c deleted file mode 100644 index 6915e11f7..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/cachector1.c +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************* - * Copyright (C) 2008 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -/* - * Between 2.6.27-rc1 and 2.6.27-rc2 ctor prototype was changed from - * ctor(cache, ptr) to ctor(ptr). Unfortunately there - * is no typedef for ctor, so we have to redefine kmem_cache_create - * to find out ctor prototype. If prototype matches, then this is old - * kernel. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) -#error "This test intentionally fails on 2.6.28 and newer kernels." -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -#include - -struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, - unsigned long, - void (*)(struct kmem_cache *, void *)); - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/dalias.c b/open-vm-tools/modules/linux/shared/autoconf/dalias.c deleted file mode 100644 index 5c0deb601..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/dalias.c +++ /dev/null @@ -1,48 +0,0 @@ -/********************************************************* - * Copyright (C) 2015-2016 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) -#include -#include - -/* - * After 3.19.0, the dentry d_alias field was moved. Fedora - * backported this behavior into earlier kernel versions. - * The type of the d_alias field changed from 3.6 onwards - * which was a list head to being a list node. The check - * for earlier than 3.6 is done separately. - * - * This test will fail on a kernel with such a patch. - */ -void test(void) -{ - struct dentry aliasDentry; - - INIT_HLIST_NODE(&aliasDentry.d_alias); -} - -#else -/* Intentionally passes for earlier than 3.6.0 kernels as a separate test is done. */ -#endif -#else -#error "This test intentionally fails on 3.19.0 or newer kernels." -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/dalias1.c b/open-vm-tools/modules/linux/shared/autoconf/dalias1.c deleted file mode 100644 index 0b785fdc4..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/dalias1.c +++ /dev/null @@ -1,50 +0,0 @@ -/********************************************************* - * Copyright (C) 2015-2016 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) -#include -#include - -/* - * After 3.19.0, the dentry d_alias field was moved. Fedora - * backported this behavior into earlier kernels. - * The type of the d_alias field changed from 3.6 onwards - * which was a list head to being a list node. The check - * for 3.6 onwards is done separately. - * - * This test will fail on a kernel with such a patch. - */ -void test(void) -{ - struct dentry aliasDentry; - - INIT_LIST_HEAD(&aliasDentry.d_alias); -} - -#else -/* - * Intentionally passes for earlier than 3.2.0 kernels as d_alias is valid. - * - * Intentionally passes for 3.6.0 or later kernels as d_alias is a different type. - * A separate test with the different type is run for those kernel versions. - */ -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/dcount.c b/open-vm-tools/modules/linux/shared/autoconf/dcount.c deleted file mode 100644 index c78968d01..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/dcount.c +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************* - * Copyright (C) 2014 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) -#include - -/* - * After 3.11.0, the dentry d_count field was removed. Red Hat - * backported this behavior into a 3.10.0 kernel. - * - * This test will fail on a kernel with such a patch. - */ -void test(void) -{ - struct dentry dentry; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) - dentry.d_count = 1; -#else - atomic_set(&dentry.d_count, 1); -#endif -} -#else -#error "This test intentionally fails on 3.11.0 or newer kernels." -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/file_operations_flush.c b/open-vm-tools/modules/linux/shared/autoconf/file_operations_flush.c deleted file mode 100644 index f1c77b23b..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/file_operations_flush.c +++ /dev/null @@ -1,46 +0,0 @@ -/********************************************************* - * Copyright (C) 2013-2014 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 v2.6.18 added an owner parameter to flush. - * But SLES10 has backported the change to its 2.6.16.60 kernel, - * so we can't rely solely on kernel version to determine number of - * arguments. - * - * This test will fail on a kernel with such a patch. - */ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) -#error This compile test intentionally fails on 2.6.18 and newer kernels. -#else - -#include - -static int TestFlush(struct file *file); -{ - return 0; -} - -struct file_operations testFO = { - .flush = TestFlush, -}; - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/file_operations_fsync.c b/open-vm-tools/modules/linux/shared/autoconf/file_operations_fsync.c deleted file mode 100644 index 47a781549..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/file_operations_fsync.c +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************* - * 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 --git a/open-vm-tools/modules/linux/shared/autoconf/filldir1.c b/open-vm-tools/modules/linux/shared/autoconf/filldir1.c deleted file mode 100644 index 2a2ca7189..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/filldir1.c +++ /dev/null @@ -1,50 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -#include -#include /* loff_t */ -#include /* NULL */ - -/* - * After 2.6.18, filldir and statfs were changed to send 64-bit inode - * numbers to user space. Red Hat backported this behavior into a 2.6.17 - * kernel. - * - * This test will fail on a kernel with such a patch. - */ -static int LinuxDriverFilldir(void *buf, - const char *name, - int namelen, - loff_t offset, - ino_t ino, - unsigned int d_type) -{ - return 0; -} - -void test(void) -{ - vfs_readdir(NULL, LinuxDriverFilldir, NULL); -} -#else -#error "This test intentionally fails on 2.6.20 and newer kernels." -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/geninclude.c b/open-vm-tools/modules/linux/shared/autoconf/geninclude.c deleted file mode 100644 index 88d68dc55..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/geninclude.c +++ /dev/null @@ -1,41 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#ifdef CONFIG_X86_VOYAGER -APATH/mach-voyager -#endif -#ifdef CONFIG_X86_VISWS -APATH/mach-visws -#endif -#ifdef CONFIG_X86_NUMAQ -APATH/mach-numaq -#endif -#ifdef CONFIG_X86_BIGSMP -APATH/mach-bigsmp -#endif -#ifdef CONFIG_X86_SUMMIT -APATH/mach-summit -#endif -#ifdef CONFIG_X86_GENERICARCH -APATH/mach-generic -#endif -APATH/mach-default - diff --git a/open-vm-tools/modules/linux/shared/autoconf/getsb1.c b/open-vm-tools/modules/linux/shared/autoconf/getsb1.c deleted file mode 100644 index 5965416dc..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/getsb1.c +++ /dev/null @@ -1,45 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) - -#include - -/* - * Around 2.6.18, a pointer to a vfsmount was added to get_sb. Red Hat - * backported this behavior into a 2.6.17 kernel. - * - * This test will fail on a kernel with such a patch. - */ -static struct super_block * LinuxDriverGetSb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *rawData) -{ - return 0; -} - -struct file_system_type fs_type = { - .get_sb = LinuxDriverGetSb -}; -#else -#error "This test intentionally fails on 2.6.19 or newer kernels." -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/inode1.c b/open-vm-tools/modules/linux/shared/autoconf/inode1.c deleted file mode 100644 index eeec3c6b1..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/inode1.c +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -#include -#include /* NULL */ - - -/* - * After 2.6.18, inodes were "slimmed". This involved removing the union - * that encapsulates inode private data (and using i_private instead), as well - * as removing i_blksize. Red Hat backported this behavior into a 2.6.17 - * kernel. - * - * This test will fail on a kernel with such a patch. - */ -void test(void) -{ - struct inode inode; - - inode.u.generic_ip = NULL; -} -#else -#error "This test intentionally fails on 2.6.20 and newer kernels." -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/netcreate_num_params.c b/open-vm-tools/modules/linux/shared/autoconf/netcreate_num_params.c deleted file mode 100644 index 8ee6a1974..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/netcreate_num_params.c +++ /dev/null @@ -1,48 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * During 2.6.33 merge window net_proto_ops->create() method was changed - - * a new 'kern' field, signalling whether socket is being created by kernel - * or userspace application, was added to it. Unfortunately, some - * distributions, such as RHEL 6, have backported the change to earlier - * kernels, 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(2, 6, 32) -# error This compile test intentionally fails. -#else - -#include - -static int TestCreate(struct net *net, - struct socket *sock, int protocol, - int kern) -{ - return 0; -} - -struct net_proto_family testFamily = { - .create = TestCreate, -}; - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/netif_num_params.c b/open-vm-tools/modules/linux/shared/autoconf/netif_num_params.c deleted file mode 100644 index a90883b12..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/netif_num_params.c +++ /dev/null @@ -1,46 +0,0 @@ -/********************************************************* - * Copyright (C) 2009 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 - * - *********************************************************/ - -/* - * Detect whether netif_rx_complete (and netif_rx_schedule) take a single - * napi_struct argument. The foundation was laid whith introducing Generic - * Receive Offload infrastructure but dropping unneeded net_device argument - * did not happen till few commits later so we can't simply test for presence - * of NETIF_F_GRO. - * - * Test succeeds if netif_rx_complete takes dev & napi arguments, or if it - * takes dev argument only (kernels before 2.6.24). Test fails if netif_rx_complete - * takes only single napi argument. - */ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) -# error This compile test intentionally fails. -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -#include - -#ifdef NETIF_F_GRO -void test_netif_rx_complete(struct net_device *dev, struct napi_struct *napi) -{ - netif_rx_complete(dev, napi); -} -#endif - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/skblin.c b/open-vm-tools/modules/linux/shared/autoconf/skblin.c deleted file mode 100644 index e3a6ccdcc..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/skblin.c +++ /dev/null @@ -1,41 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * Detect whether skb_linearize takes one or two arguments. - */ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) -/* - * Since 2.6.18 all kernels have single-argument skb_linearize. For - * older kernels use autodetection. Not using autodetection on newer - * kernels saves us from compile failure on some post 2.6.18 kernels - * which do not have selfcontained skbuff.h. - */ - -#include - -int test_skb_linearize(struct sk_buff *skb) -{ - return skb_linearize(skb); -} - -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/statfs1.c b/open-vm-tools/modules/linux/shared/autoconf/statfs1.c deleted file mode 100644 index a753917bd..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/statfs1.c +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -#include - -/* - * Around 2.6.18, the super_block pointer in statfs was changed to a dentry - * pointer. Red Hat backported this behavior into a 2.6.17 kernel. - * - * This test will fail on a kernel with such a patch. - */ -static int LinuxDriverStatFs(struct super_block *sb, - struct kstatfs *stat) -{ - return 0; -} - -struct super_operations super_ops = { - .statfs = LinuxDriverStatFs -}; -#else -#error "This test intentionally fails on 2.6.19 and newer kernels." -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/truncate_pagecache.c b/open-vm-tools/modules/linux/shared/autoconf/truncate_pagecache.c deleted file mode 100644 index 31c933117..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/truncate_pagecache.c +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************* - * Copyright (C) 2015-2016 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) - -#include -#include -#include /* loff_t */ - -/* - * After 3.12.0, truncate_pagecache changed its interface to just use - * the new file size only. Red Hat backported this behavior into a 3.10.0 - * kernel. - * - * This test will fail on a kernel with such a patch. - */ - -void test(void) -{ - struct inode inode; - loff_t oldSize = 0; - loff_t newSize = 4096; - - truncate_pagecache(&inode, oldSize, newSize); -} -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) -#error "This test intentionally fails on 3.12.0 and newer kernels." -#else -/* - * It must be older than 2.6.32 in which case we assume success. - * So not 3.12 compatible. There is no function for these versions. - */ -#endif diff --git a/open-vm-tools/modules/linux/shared/autoconf/wait_on_bit.c b/open-vm-tools/modules/linux/shared/autoconf/wait_on_bit.c deleted file mode 100644 index a543cc13e..000000000 --- a/open-vm-tools/modules/linux/shared/autoconf/wait_on_bit.c +++ /dev/null @@ -1,53 +0,0 @@ -/********************************************************* - * Copyright (C) 2016 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 - * - *********************************************************/ - -#include "compat_version.h" -#include "compat_autoconf.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) - -#include -#include -#include - -unsigned long test_bits; - -/* - * After 3.17.0, wait_on_bit changed its interface to remove the action - * callback argument and this was backported to some Linux kernel versions - * such as 3.10 for the RHEL 7.3 version. - * - * This test will fail on a kernel with such a patch. - */ - -int test(void) -{ - - return wait_on_bit(&test_bits, - 0, - NULL, - TASK_UNINTERRUPTIBLE); -} -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) -#error "This test intentionally fails on 3.17.0 and newer kernels." -#else -/* - * It must be older than 2.6.13 in which case we don't use the function. - */ -#endif diff --git a/open-vm-tools/modules/linux/shared/compat_autoconf.h b/open-vm-tools/modules/linux/shared/compat_autoconf.h deleted file mode 100644 index 26064aa8d..000000000 --- a/open-vm-tools/modules/linux/shared/compat_autoconf.h +++ /dev/null @@ -1,41 +0,0 @@ -/********************************************************* - * Copyright (C) 2009 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 - * - *********************************************************/ - -#ifndef __COMPAT_AUTOCONF_H__ -# define __COMPAT_AUTOCONF_H__ - -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMKDRIVERS -#include "includeCheck.h" - - -#ifndef LINUX_VERSION_CODE -# error "Include compat_version.h before compat_autoconf.h" -#endif - -/* autoconf.h moved from linux/autoconf.h to generated/autoconf.h in 2.6.33-rc1. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) -# include -#else -# include -#endif - -#endif /* __COMPAT_AUTOCONF_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_cred.h b/open-vm-tools/modules/linux/shared/compat_cred.h deleted file mode 100644 index 4c6d940fc..000000000 --- a/open-vm-tools/modules/linux/shared/compat_cred.h +++ /dev/null @@ -1,51 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_CRED_H__ -# define __COMPAT_CRED_H__ - - -/* - * Include linux/cred.h via linux/sched.h - it is not nice, but - * as cpp does not have #ifexist... - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) -#include -#else -#include -#endif - -#if !defined(current_fsuid) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) -#define current_uid() (current->uid) -#define current_euid() (current->euid) -#define current_fsuid() (current->fsuid) -#define current_gid() (current->gid) -#define current_egid() (current->egid) -#define current_fsgid() (current->fsgid) -#endif - -#if !defined(cap_set_full) -/* cap_set_full was removed in kernel version 3.0-rc4. */ -#define cap_set_full(_c) do { (_c) = CAP_FULL_SET; } while (0) -#endif - -#if !defined(GLOBAL_ROOT_UID) -#define GLOBAL_ROOT_UID (0) -#endif - -#endif /* __COMPAT_CRED_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_dcache.h b/open-vm-tools/modules/linux/shared/compat_dcache.h deleted file mode 100644 index d16fd1d35..000000000 --- a/open-vm-tools/modules/linux/shared/compat_dcache.h +++ /dev/null @@ -1,51 +0,0 @@ -/********************************************************* - * Copyright (C) 2013 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 - * - *********************************************************/ - -#ifndef __COMPAT_DCACHE_H__ -# define __COMPAT_DCACHE_H__ - -#include - -/* - * per-dentry locking was born in 2.5.62. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 62) -#define compat_lock_dentry(dentry) spin_lock(&dentry->d_lock) -#define compat_unlock_dentry(dentry) spin_unlock(&dentry->d_lock) -#else -#define compat_lock_dentry(dentry) do {} while (0) -#define compat_unlock_dentry(dentry) do {} while (0) -#endif - -/* - * d_alloc_name was born in 2.6.10. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) -#define compat_d_alloc_name(parent, s) d_alloc_name(parent, s) -#else -#define compat_d_alloc_name(parent, s) \ -({ \ - struct qstr q; \ - q.name = s; \ - q.len = strlen(s); \ - q.hash = full_name_hash(q.name, q.len); \ - d_alloc(parent, &q); \ -}) -#endif - -#endif /* __COMPAT_DCACHE_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_ethtool.h b/open-vm-tools/modules/linux/shared/compat_ethtool.h deleted file mode 100644 index 3e098eea3..000000000 --- a/open-vm-tools/modules/linux/shared/compat_ethtool.h +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -#ifndef _COMPAT_ETHTOOL_H -#define _COMPAT_ETHTOOL_H - -/* - * ethtool is a userspace utility for getting and setting ethernet device - * settings. Kernel support for it was first published in 2.4.0-test11, but - * only in 2.4.15 were the ethtool_value struct and the ETHTOOL_GLINK ioctl - * added to ethtool.h (together, because the ETHTOOL_GLINK ioctl expects a - * single value response). - * - * Likewise, ioctls for getting and setting TSO were published in 2.4.22. - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -# include - -# ifndef ETHTOOL_GLINK -# define ETHTOOL_GLINK 0x0a - -typedef struct { - __u32 cmd; - __u32 data; -} compat_ethtool_value; - -# else - -typedef struct ethtool_value compat_ethtool_value; -# endif - -# ifndef ETHTOOL_GTSO -# define ETHTOOL_GTSO 0x1E -# define ETHTOOL_STSO 0x1F -# 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 --git a/open-vm-tools/modules/linux/shared/compat_fs.h b/open-vm-tools/modules/linux/shared/compat_fs.h deleted file mode 100644 index f762f6f40..000000000 --- a/open-vm-tools/modules/linux/shared/compat_fs.h +++ /dev/null @@ -1,266 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#ifndef __COMPAT_FS_H__ -# define __COMPAT_FS_H__ - -#include - -/* - * 2.6.5+ kernels define FS_BINARY_MOUNTDATA. Since it didn't exist and - * wasn't used prior, it's safe to define it to zero. - */ - -#ifndef FS_BINARY_MOUNTDATA -#define FS_BINARY_MOUNTDATA 0 -#endif - -/* - * MAX_LFS_FILESIZE wasn't defined until 2.5.4. - */ -#ifndef MAX_LFS_FILESIZE -# include -# if BITS_PER_LONG == 32 -# define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG - 1)) - 1) -# elif BITS_PER_LONG == 64 -# define MAX_LFS_FILESIZE 0x7fffffffffffffffUL -# endif -#endif - - -/* - * sendfile as a VFS op was born in 2.5.30. Unfortunately, it also changed - * signatures, first in 2.5.47, then again in 2.5.70, then again in 2.6.8. - * Luckily, the 2.6.8+ signature is the same as the 2.5.47 signature. And - * as of 2.6.23-rc1 sendfile is gone, replaced by splice_read... - * - * Let's not support sendfile from 2.5.30 to 2.5.47, because the 2.5.30 - * signature is much different and file_send_actor isn't externed. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) -#define VMW_SENDFILE_NONE -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) -#define VMW_SENDFILE_NEW -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) -#define VMW_SENDFILE_OLD -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 47) -#define VMW_SENDFILE_NEW -#else -#define VMW_SENDFILE_NONE -#endif - -/* - * splice_read is there since 2.6.17, but let's avoid 2.6.17-rcX kernels... - * After all nobody is using splice system call until 2.6.23 using it to - * implement sendfile. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) -#define VMW_SPLICE_READ 1 -#endif - -/* - * Filesystems wishing to use generic page cache read/write routines are - * supposed to implement aio_read and aio_write (calling into - * generic_file_aio_read() and generic_file_aio_write() if necessary). - * - * The VFS exports do_sync_read() and do_sync_write() as the "new" - * generic_file_read() and generic_file_write(), but filesystems need not - * actually implement read and write- the VFS will automatically call - * do_sync_write() and do_sync_read() when applications invoke the standard - * read() and write() system calls. - * - * In 2.6.19, generic_file_read() and generic_file_write() were removed, - * necessitating this change. AIO dates as far back as 2.5.42, but the API has - * changed over time, so for simplicity, we'll only enable it from 2.6.19 and - * on. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -# define VMW_USE_AIO -#endif - - -/* - * The alloc_inode and destroy_inode VFS ops didn't exist prior to 2.4.21. - * Without these functions, file systems can't embed inodes. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 21) -# define VMW_EMBED_INODE -#endif - - -/* - * iget() was removed from the VFS as of 2.6.25-rc1. The replacement for iget() - * is iget_locked() which was added in 2.5.17. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 17) -# define VMW_USE_IGET_LOCKED -#endif - -/* - * parent_ino was born in 2.5.5. For older kernels, let's use 2.5.5 - * implementation. It uses the dcache lock which is OK because per-dentry - * locking appeared after 2.5.5. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) -#define compat_parent_ino(dentry) parent_ino(dentry) -#else -#define compat_parent_ino(dentry) \ -({ \ - ino_t res; \ - spin_lock(&dcache_lock); \ - res = dentry->d_parent->d_inode->i_ino; \ - spin_unlock(&dcache_lock); \ - res; \ -}) -#endif - - -/* - * putname changed to __putname in 2.6.6. - */ -#define compat___getname() __getname() -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6) -#define compat___putname(name) putname(name) -#else -#define compat___putname(name) __putname(name) -#endif - - -/* - * inc_nlink, drop_nlink, and clear_nlink were added in 2.6.19. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -#define compat_inc_nlink(inode) ((inode)->i_nlink++) -#define compat_drop_nlink(inode) ((inode)->i_nlink--) -#define compat_clear_nlink(inode) ((inode)->i_nlink = 0) -#else -#define compat_inc_nlink(inode) inc_nlink(inode) -#define compat_drop_nlink(inode) drop_nlink(inode) -#define compat_clear_nlink(inode) clear_nlink(inode) -#endif - - -/* - * i_size_write and i_size_read were introduced in 2.6.0-test1 - * (though we'll look for them as of 2.6.1). They employ slightly different - * locking in order to guarantee atomicity, depending on the length of a long, - * whether the kernel is SMP, or whether the kernel is preemptible. Prior to - * i_size_write and i_size_read, there was no such locking, so that's the - * behavior we'll emulate. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1) -#define compat_i_size_read(inode) ((inode)->i_size) -#define compat_i_size_write(inode, size) ((inode)->i_size = size) -#else -#define compat_i_size_read(inode) i_size_read(inode) -#define compat_i_size_write(inode, size) i_size_write(inode, size) -#endif - - -/* - * filemap_fdatawrite was introduced in 2.5.12. Prior to that, modules used - * filemap_fdatasync instead. In 2.4.18, both filemap_fdatawrite and - * filemap_fdatawait began returning status codes. Prior to that, they were - * void functions, so we'll just have them return 0. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 18) -#define compat_filemap_fdatawrite(mapping) \ -({ \ - int result = 0; \ - filemap_fdatasync(mapping); \ - result; \ -}) -#define compat_filemap_fdatawait(mapping) \ -({ \ - int result = 0; \ - filemap_fdatawait(mapping); \ - result; \ -}) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) -#define compat_filemap_fdatawrite(mapping) filemap_fdatasync(mapping) -#define compat_filemap_fdatawait(mapping) filemap_fdatawait(mapping) -#else -#define compat_filemap_fdatawrite(mapping) filemap_fdatawrite(mapping) -#define compat_filemap_fdatawait(mapping) filemap_fdatawait(mapping) -#endif - - -/* - * filemap_write_and_wait was introduced in 2.6.6 and exported for module use - * in 2.6.16. It's really just a simple wrapper around filemap_fdatawrite and - * and filemap_fdatawait, which initiates a flush of all dirty pages, then - * waits for the pages to flush. The implementation here is a simplified form - * of the one found in 2.6.20-rc3. - * - * Unfortunately, it just isn't possible to implement this prior to 2.4.5, when - * neither filemap_fdatawait nor filemap_fdatasync were exported for module - * use. So we'll define it out and hope for the best. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 5) -#define compat_filemap_write_and_wait(mapping) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) -#define compat_filemap_write_and_wait(mapping) \ -({ \ - int result = 0; \ - if (mapping->nrpages) { \ - result = compat_filemap_fdatawrite(mapping); \ - if (result != -EIO) { \ - int result2 = compat_filemap_fdatawait(mapping); \ - if (!result) { \ - result = result2; \ - } \ - } \ - } \ - result; \ -}) -#else -#define compat_filemap_write_and_wait(mapping) filemap_write_and_wait(mapping) -#endif - - -/* - * invalidate_remote_inode was introduced in 2.6.0-test5. Prior to that, - * filesystems wishing to invalidate pages belonging to an inode called - * invalidate_inode_pages. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -#define compat_invalidate_remote_inode(inode) invalidate_inode_pages(inode) -#else -#define compat_invalidate_remote_inode(inode) invalidate_remote_inode(inode) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) -#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 --git a/open-vm-tools/modules/linux/shared/compat_highmem.h b/open-vm-tools/modules/linux/shared/compat_highmem.h deleted file mode 100644 index 263380d61..000000000 --- a/open-vm-tools/modules/linux/shared/compat_highmem.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * 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 - * - *********************************************************/ - -#ifndef __COMPAT_HIGHMEM_H__ -# define __COMPAT_HIGHMEM_H__ - -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) -# define compat_kmap_atomic(_page) kmap_atomic(_page) -# define compat_kunmap_atomic(_page) kunmap_atomic(_page) -#else -# define compat_kmap_atomic(_page) kmap_atomic((_page), KM_USER0) -# define compat_kunmap_atomic(_page) kunmap_atomic((_page), KM_USER0) -#endif - -#endif /* __COMPAT_HIGHMEM_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_interrupt.h b/open-vm-tools/modules/linux/shared/compat_interrupt.h deleted file mode 100644 index 1d72a4bb5..000000000 --- a/open-vm-tools/modules/linux/shared/compat_interrupt.h +++ /dev/null @@ -1,55 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -#ifndef __COMPAT_INTERRUPT_H__ -# define __COMPAT_INTERRUPT_H__ - - -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 69) -/* - * We cannot just define irqreturn_t, as some 2.4.x kernels have - * typedef void irqreturn_t; for "increasing" backward compatibility. - */ -typedef void compat_irqreturn_t; -#define COMPAT_IRQ_NONE -#define COMPAT_IRQ_HANDLED -#define COMPAT_IRQ_RETVAL(x) -#else -typedef irqreturn_t compat_irqreturn_t; -#define COMPAT_IRQ_NONE IRQ_NONE -#define COMPAT_IRQ_HANDLED IRQ_HANDLED -#define COMPAT_IRQ_RETVAL(x) IRQ_RETVAL(x) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -#define COMPAT_IRQF_DISABLED SA_INTERRUPT -#define COMPAT_IRQF_SHARED SA_SHIRQ -#else -#define COMPAT_IRQF_DISABLED IRQF_DISABLED -#define COMPAT_IRQF_SHARED IRQF_SHARED -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp, struct pt_regs *regs) -#else -#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp) -#endif - -#endif /* __COMPAT_INTERRUPT_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_ioport.h b/open-vm-tools/modules/linux/shared/compat_ioport.h deleted file mode 100644 index bacdb50b6..000000000 --- a/open-vm-tools/modules/linux/shared/compat_ioport.h +++ /dev/null @@ -1,63 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -#ifndef __COMPAT_IOPORT_H__ -# define __COMPAT_IOPORT_H__ - - -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) -static inline void * -compat_request_region(unsigned long start, unsigned long len, const char *name) -{ - if (check_region(start, len)) { - return NULL; - } - request_region(start, len, name); - return (void*)1; -} -#else -#define compat_request_region(start, len, name) request_region(start, len, name) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 7) -/* mmap io support starts from 2.3.7, fail the call for kernel prior to that */ -static inline void * -compat_request_mem_region(unsigned long start, unsigned long len, const char *name) -{ - return NULL; -} - -static inline void -compat_release_mem_region(unsigned long start, unsigned long len) -{ - return; -} -#else -#define compat_request_mem_region(start, len, name) request_mem_region(start, len, name) -#define compat_release_mem_region(start, len) release_mem_region(start, len) -#endif - -/* these two macro defs are needed by compat_pci_request_region */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15) -# define IORESOURCE_IO 0x00000100 -# define IORESOURCE_MEM 0x00000200 -#endif - -#endif /* __COMPAT_IOPORT_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_kernel.h b/open-vm-tools/modules/linux/shared/compat_kernel.h deleted file mode 100644 index 04ba2d19d..000000000 --- a/open-vm-tools/modules/linux/shared/compat_kernel.h +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************* - * Copyright (C) 2004 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 - * - *********************************************************/ - -#ifndef __COMPAT_KERNEL_H__ -# define __COMPAT_KERNEL_H__ - -#include -#include - -/* - * container_of was introduced in 2.5.28 but it's easier to check like this. - */ -#ifndef container_of -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) -#endif - -/* - * vsnprintf became available in 2.4.10. For older kernels, just fall back on - * vsprintf. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) -#define vsnprintf(str, size, fmt, args) vsprintf(str, fmt, args) -#endif - -#endif /* __COMPAT_KERNEL_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_log2.h b/open-vm-tools/modules/linux/shared/compat_log2.h deleted file mode 100644 index 318304918..000000000 --- a/open-vm-tools/modules/linux/shared/compat_log2.h +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************* - * 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 - * - *********************************************************/ - -#ifndef __COMPAT_LOG2_H__ -# define __COMPAT_LOG2_H__ - -#ifndef LINUX_VERSION_CODE -# error "Include compat_version.h before compat_log2.h" -#endif - -/* linux/log2.h was introduced in 2.6.20. */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) -# include -#endif - -/* - * is_power_of_2 was introduced in 2.6.21. This implementation is almost - * identical to the one found there. - */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) -#define compat_is_power_of_2(n) is_power_of_2(n) -#else -static inline __attribute__((const)) -int compat_is_power_of_2(unsigned long n) -{ - return (n != 0 && ((n && (n - 1)) == 0)); -} -#endif - -/* - * rounddown_power_of_two was introduced in 2.6.24. This implementation is - * similar to the one in log2.h but with input of int instead of long to - * avoid more version related checks for fls_long(). - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -#define compat_rounddown_pow_of_two(n) rounddown_pow_of_two(n) -#else -static inline __attribute__((const)) -unsigned int compat_rounddown_pow_of_two(unsigned int n) -{ - return 1U << (fls(n) -1); -} -#endif - -#endif /* __COMPAT_LOG2_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_mm.h b/open-vm-tools/modules/linux/shared/compat_mm.h deleted file mode 100644 index 4c5ac25ba..000000000 --- a/open-vm-tools/modules/linux/shared/compat_mm.h +++ /dev/null @@ -1,50 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_MM_H__ -# define __COMPAT_MM_H__ - - -#include - - -/* 2.2.x uses 0 instead of some define */ -#ifndef NOPAGE_SIGBUS -#define NOPAGE_SIGBUS (0) -#endif - - -/* 2.2.x does not have HIGHMEM support */ -#ifndef GFP_HIGHUSER -#define GFP_HIGHUSER (GFP_USER) -#endif - - -/* - * In 2.4.14, the logic behind the UnlockPage macro was moved to the - * unlock_page() function. Later (in 2.5.12), the UnlockPage macro was removed - * altogether, and nowadays everyone uses unlock_page(). - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 14) -#define compat_unlock_page(page) UnlockPage(page) -#else -#define compat_unlock_page(page) unlock_page(page) -#endif - - -#endif /* __COMPAT_MM_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_module.h b/open-vm-tools/modules/linux/shared/compat_module.h deleted file mode 100644 index 2af737223..000000000 --- a/open-vm-tools/modules/linux/shared/compat_module.h +++ /dev/null @@ -1,83 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * compat_module.h -- - */ - -#ifndef __COMPAT_MODULE_H__ -# define __COMPAT_MODULE_H__ - - -#include - - -/* - * Modules wishing to use the GPL license are required to include a - * MODULE_LICENSE definition in their module source as of 2.4.10. - */ -#ifndef MODULE_LICENSE -#define MODULE_LICENSE(license) -#endif - -/* - * To make use of our own home-brewed MODULE_INFO, we need macros to - * concatenate two expressions to "__mod_", and and to convert an - * expression into a string. I'm sure we've got these in our codebase, - * but I'd rather not introduce such a dependency in a compat header. - */ -#ifndef __module_cat -#define __module_cat_1(a, b) __mod_ ## a ## b -#define __module_cat(a, b) __module_cat_1(a, b) -#endif - -#ifndef __stringify -#define __stringify_1(x) #x -#define __stringify(x) __stringify_1(x) -#endif - -/* - * MODULE_INFO was born in 2.5.69. - */ -#ifndef MODULE_INFO -#define MODULE_INFO(tag, info) \ -static const char __module_cat(tag, __LINE__)[] \ - __attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info -#endif - -/* - * MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx" - * string to the module's version, but that was removed in 2.6.10, so we'll - * ignore it in our wrapper. - */ -#ifndef MODULE_VERSION -#define MODULE_VERSION(_version) MODULE_INFO(version, _version) -#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) - typedef bool compat_mod_param_bool; -#else - typedef int compat_mod_param_bool; -#endif - -#endif /* __COMPAT_MODULE_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_mutex.h b/open-vm-tools/modules/linux/shared/compat_mutex.h deleted file mode 100644 index 95e59a9bf..000000000 --- a/open-vm-tools/modules/linux/shared/compat_mutex.h +++ /dev/null @@ -1,51 +0,0 @@ -/********************************************************* - * Copyright (C) 2009 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 - * - *********************************************************/ - -#ifndef __COMPAT_MUTEX_H__ -# define __COMPAT_MUTEX_H__ - - -/* Blocking mutexes were introduced in 2.6.16. */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) - -#include "compat_semaphore.h" - -typedef struct semaphore compat_mutex_t; - -# define compat_define_mutex(_mx) DECLARE_MUTEX(_mx) -# define compat_mutex_init(_mx) init_MUTEX(_mx) -# define compat_mutex_lock(_mx) down(_mx) -# define compat_mutex_lock_interruptible(_mx) down_interruptible(_mx) -# define compat_mutex_unlock(_mx) up(_mx) - -#else - -#include - -typedef struct mutex compat_mutex_t; - -# define compat_define_mutex(_mx) DEFINE_MUTEX(_mx) -# define compat_mutex_init(_mx) mutex_init(_mx) -# define compat_mutex_lock(_mx) mutex_lock(_mx) -# define compat_mutex_lock_interruptible(_mx) mutex_lock_interruptible(_mx) -# define compat_mutex_unlock(_mx) mutex_unlock(_mx) - -#endif - -#endif /* __COMPAT_MUTEX_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_namei.h b/open-vm-tools/modules/linux/shared/compat_namei.h deleted file mode 100644 index f82dd49be..000000000 --- a/open-vm-tools/modules/linux/shared/compat_namei.h +++ /dev/null @@ -1,48 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#ifndef __COMPAT_NAMEI_H__ -# define __COMPAT_NAMEI_H__ - -#include - -/* - * In 2.6.25-rc2, dentry and mount objects were removed from the nameidata - * struct. They were both replaced with a struct path. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) -#define compat_vmw_nd_to_dentry(nd) (nd).path.dentry -#else -#define compat_vmw_nd_to_dentry(nd) (nd).dentry -#endif - -/* In 2.6.25-rc2, path_release(&nd) was replaced with path_put(&nd.path). */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) -#define compat_path_release(nd) path_put(&(nd)->path) -#else -#define compat_path_release(nd) path_release(nd) -#endif - -/* path_lookup was removed in 2.6.39 merge window VFS merge */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) -#define compat_path_lookup(name, flags, nd) kern_path(name, flags, &((nd)->path)) -#else -#define compat_path_lookup(name, flags, nd) path_lookup(name, flags, nd) -#endif - -#endif /* __COMPAT_NAMEI_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_netdevice.h b/open-vm-tools/modules/linux/shared/compat_netdevice.h deleted file mode 100644 index e1a3b0eef..000000000 --- a/open-vm-tools/modules/linux/shared/compat_netdevice.h +++ /dev/null @@ -1,346 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_NETDEVICE_H__ -# define __COMPAT_NETDEVICE_H__ - - -#include -#include -#include -#include -#include - -/* - * The enet_statistics structure moved from linux/if_ether.h to - * linux/netdevice.h and is renamed net_device_stats in 2.1.25 --hpreg - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 25) -# include - -# define net_device_stats enet_statistics -#endif - - -/* The netif_rx_ni() API appeared in 2.4.8 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 8) -# define netif_rx_ni netif_rx -#endif - - -/* The device struct was renamed net_device in 2.3.14 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14) -# define net_device device -#endif - - -/* - * SET_MODULE_OWNER appeared sometime during 2.3.x. It was setting - * dev->owner = THIS_MODULE until 2.5.70, where netdevice refcounting - * was completely changed. SET_MODULE_OWNER was nop for whole - * 2.6.x series, and finally disappeared in 2.6.24. - * - * MOD_xxx_USE_COUNT wrappers are here, as they must be mutually - * exclusive with SET_MODULE_OWNER call. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) -# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) -# define COMPAT_NETDEV_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -# define COMPAT_NETDEV_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -#else -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -# define COMPAT_SET_MODULE_OWNER(dev) SET_MODULE_OWNER(dev) -# else -# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) -# endif -# define COMPAT_NETDEV_MOD_INC_USE_COUNT do {} while (0) -# define COMPAT_NETDEV_MOD_DEC_USE_COUNT do {} while (0) -#endif - -/* - * SET_NETDEV_DEV appeared sometime during 2.5.x, and later was - * crossported to various 2.4.x kernels (as dummy macro). - */ -#ifdef SET_NETDEV_DEV -# define COMPAT_SET_NETDEV_DEV(dev, pdev) SET_NETDEV_DEV(dev, pdev) -#else -# define COMPAT_SET_NETDEV_DEV(dev, pdev) do {} while (0) -#endif - -/* - * Build alloc_etherdev API on the top of init_etherdev. For 2.0.x kernels - * we must provide dummy init method, otherwise register_netdev does - * nothing. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) -int -vmware_dummy_init(struct net_device *dev) -{ - return 0; -} -#endif - - -static inline struct net_device* -compat_alloc_etherdev(int priv_size) -{ - struct net_device* dev; - int size = sizeof *dev + priv_size; - - /* - * The name is dynamically allocated before 2.4.0, but - * is an embedded array in later kernels. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - size += sizeof("ethXXXXXXX"); -#endif - dev = kmalloc(size, GFP_KERNEL); - if (dev) { - memset(dev, 0, size); - if (priv_size) { - dev->priv = dev + 1; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - dev->name = (char *)(dev + 1) + priv_size; -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) - dev->init = vmware_dummy_init; -#endif - if (init_etherdev(dev, 0) != dev) { - kfree(dev); - dev = NULL; - } - } - return dev; -} -#else -#define compat_alloc_etherdev(sz) alloc_etherdev(sz) -#endif - - -/* - * alloc_netdev and free_netdev are there since 2.4.23. Their use is mandatory - * since 2.6.24. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23) -static inline struct net_device * -compat_alloc_netdev(int priv_size, - const char *mask, - void (*setup)(struct net_device *)) -{ - struct net_device *dev; - int netdev_size = sizeof *dev; - int alloc_size; - -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - netdev_size += IFNAMSIZ; -# endif - - alloc_size = netdev_size + priv_size; - dev = kmalloc(alloc_size, GFP_KERNEL); - if (dev) { - memset(dev, 0, alloc_size); - dev->priv = (char*)dev + netdev_size; - setup(dev); -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) - dev->name = (char*)(dev + 1); -# endif - strcpy(dev->name, mask); - } - return dev; -} -# define compat_free_netdev(dev) kfree(dev) -#else -# define compat_alloc_netdev(size, mask, setup) alloc_netdev(size, mask, setup) -# define compat_free_netdev(dev) free_netdev(dev) -#endif - -/* netdev_priv() appeared in 2.6.3 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) -# define compat_netdev_priv(netdev) (netdev)->priv -#else -# define compat_netdev_priv(netdev) netdev_priv(netdev) -#endif - -/* - * In 3.1 merge window feature maros were removed from mainline, - * so let's add back ones we care about. - */ -#if !defined(HAVE_NET_DEVICE_OPS) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) -# define HAVE_NET_DEVICE_OPS 1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) -# define COMPAT_NETDEV_TX_OK NETDEV_TX_OK -# define COMPAT_NETDEV_TX_BUSY NETDEV_TX_BUSY -#else -# define COMPAT_NETDEV_TX_OK 0 -# define COMPAT_NETDEV_TX_BUSY 1 -#endif - -/* unregister_netdevice_notifier was not safe prior to 2.6.17 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \ - !defined(ATOMIC_NOTIFIER_INIT) -/* pre 2.6.17 and not patched */ -static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb) { - int err; - - rtnl_lock(); - err = unregister_netdevice_notifier(nb); - rtnl_unlock(); - return err; -} -#else -/* post 2.6.17 or patched */ -#define compat_unregister_netdevice_notifier(_nb) \ - unregister_netdevice_notifier(_nb); -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || defined(__VMKLNX__) - -# define compat_netif_napi_add(dev, napi, poll, quota) \ - netif_napi_add(dev, napi, poll, quota) - -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) || \ - defined VMW_NETIF_SINGLE_NAPI_PARM -# define compat_napi_complete(dev, napi) napi_complete(napi) -# define compat_napi_schedule(dev, napi) napi_schedule(napi) -# else -# define compat_napi_complete(dev, napi) netif_rx_complete(dev, napi) -# define compat_napi_schedule(dev, napi) netif_rx_schedule(dev, napi) -# endif - -# define compat_napi_enable(dev, napi) napi_enable(napi) -# define compat_napi_disable(dev, napi) napi_disable(napi) - -#else - -# define compat_napi_complete(dev, napi) netif_rx_complete(dev) -# define compat_napi_schedule(dev, napi) netif_rx_schedule(dev) -# define compat_napi_enable(dev, napi) netif_poll_enable(dev) -# define compat_napi_disable(dev, napi) netif_poll_disable(dev) - -/* RedHat ported GRO to 2.6.18 bringing new napi_struct with it */ -# if defined NETIF_F_GRO -# define compat_netif_napi_add(netdev, napi, pollcb, quota) \ - do { \ - (netdev)->poll = (pollcb); \ - (netdev)->weight = (quota);\ - (napi)->dev = (netdev); \ - } while (0) - -# else - struct napi_struct { - int dummy; - }; -# define compat_netif_napi_add(dev, napi, pollcb, quota) \ - do { \ - (dev)->poll = (pollcb); \ - (dev)->weight = (quota);\ - } while (0) - -# endif - -#endif - -#ifdef NETIF_F_TSO6 -# define COMPAT_NETIF_F_TSO (NETIF_F_TSO6 | NETIF_F_TSO) -#else -# define COMPAT_NETIF_F_TSO (NETIF_F_TSO) -#endif - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) -# define compat_netif_tx_lock(dev) netif_tx_lock(dev) -# define compat_netif_tx_unlock(dev) netif_tx_unlock(dev) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) -# define compat_netif_tx_lock(dev) spin_lock(&dev->xmit_lock) -# define compat_netif_tx_unlock(dev) spin_unlock(&dev->xmit_lock) -#else -/* Vendor backporting (SLES 10) has muddled the tx_lock situation. Pick whichever - * of the above works for you. */ -# define compat_netif_tx_lock(dev) do {} while (0) -# define compat_netif_tx_unlock(dev) do {} while (0) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) -# define COMPAT_VLAN_GROUP_ARRAY_LEN VLAN_N_VID -# define compat_flush_scheduled_work(work) cancel_work_sync(work) -#else -# define COMPAT_VLAN_GROUP_ARRAY_LEN VLAN_GROUP_ARRAY_LEN -# define compat_flush_scheduled_work(work) flush_scheduled_work() -#endif - - - -/* - * For kernel versions older than 2.6.29, where pci_msi_enabled is not - * available, check if - * 1. CONFIG_PCI_MSI is present - * 2. kernel version is newer than 2.6.25 (because multiqueue is not - * supporter) in kernels older than that) - * 3. msi can be enabled. If it fails it means that MSI is not available. - * When all the above are true, return non-zero so that multiple queues will be - * allowed in the driver. - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -# define compat_multiqueue_allowed(dev) pci_msi_enabled() -#else -# if defined CONFIG_PCI_MSI && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) -static inline int -compat_multiqueue_allowed(struct pci_dev *dev) -{ - int ret; - - if (!pci_enable_msi(dev)) - ret = 1; - else - ret = 0; - - pci_disable_msi(dev); - return ret; -} - -# else -# define compat_multiqueue_allowed(dev) (0) -# endif -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) -# define compat_vlan_get_protocol(skb) vlan_get_protocol(skb) -#else -# 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 - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) -#define compat_netif_trans_update(d) netif_trans_update(d) -#else -#define compat_netif_trans_update(d) do { (d)->trans_start = jiffies; } while (0) -#endif - -#endif /* __COMPAT_NETDEVICE_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_page-flags.h b/open-vm-tools/modules/linux/shared/compat_page-flags.h deleted file mode 100644 index d8a1833a2..000000000 --- a/open-vm-tools/modules/linux/shared/compat_page-flags.h +++ /dev/null @@ -1,66 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -#ifndef __COMPAT_PAGE_FLAGS_H__ -# define __COMPAT_PAGE_FLAGS_H__ - -/* No page-flags.h prior to 2.5.12. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 12) -# include -#endif - -/* - * The pgoff_t type was introduced in 2.5.20, but we'll look for it by - * definition since it's more convenient. Note that we want to avoid a - * situation where, in the future, a #define is changed to a typedef, - * so if pgoff_t is not defined in some future kernel, we won't define it. - */ -#if !defined(pgoff_t) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -#define pgoff_t unsigned long -#endif - -/* - * set_page_writeback() was introduced in 2.6.6. Prior to that, callers were - * using the SetPageWriteback() macro directly, so that's what we'll use. - * Prior to 2.5.12, the writeback bit didn't exist, so we don't need to do - * anything. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) -#define compat_set_page_writeback(page) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6) -#define compat_set_page_writeback(page) SetPageWriteback(page) -#else -#define compat_set_page_writeback(page) set_page_writeback(page) -#endif - -/* - * end_page_writeback() was introduced in 2.5.12. Prior to that, it looks like - * there was no page writeback bit, and everything the function accomplished - * was done by unlock_page(), so we'll define it out. - * - * Note that we could just #define end_page_writeback to nothing and avoid - * needing the compat_ prefix, but this is more complete with respect to - * compat_set_page_writeback. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) -#define compat_end_page_writeback(page) -#else -#define compat_end_page_writeback(page) end_page_writeback(page) -#endif - -#endif /* __COMPAT_PAGE_FLAGS_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_page.h b/open-vm-tools/modules/linux/shared/compat_page.h deleted file mode 100644 index 0bf0e251e..000000000 --- a/open-vm-tools/modules/linux/shared/compat_page.h +++ /dev/null @@ -1,75 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_PAGE_H__ -# define __COMPAT_PAGE_H__ - - -#include -#include - - -/* The pfn_to_page() API appeared in 2.5.14 and changed to function during 2.6.x */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pfn_to_page) -# define pfn_to_page(_pfn) (mem_map + (_pfn)) -# define page_to_pfn(_page) ((_page) - mem_map) -#endif - - -/* The virt_to_page() API appeared in 2.4.0 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(virt_to_page) -# define virt_to_page(_kvAddr) pfn_to_page(MAP_NR(_kvAddr)) -#endif - - -/* - * The get_order() API appeared at some point in 2.3.x, and was then backported - * in 2.2.17-21mdk and in the stock 2.2.18. Because we can only detect its - * definition through makefile tricks, we provide our own for now --hpreg - */ -static inline int -compat_get_order(unsigned long size) // IN -{ - int order; - - size = (size - 1) >> (PAGE_SHIFT - 1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - - return order; -} - -/* - * BUG() was added to in 2.2.18, and was moved to - * in 2.5.58. - * - * XXX: Technically, this belongs in some sort of "compat_asm_page.h" file, but - * since our compatibility wrappers don't distinguish between and - * , putting it here is reasonable. - */ -#ifndef BUG -#define BUG() do { \ - printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - __asm__ __volatile__(".byte 0x0f,0x0b"); \ -} while (0) -#endif - -#endif /* __COMPAT_PAGE_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_pagemap.h b/open-vm-tools/modules/linux/shared/compat_pagemap.h deleted file mode 100644 index 8b37c7d7a..000000000 --- a/open-vm-tools/modules/linux/shared/compat_pagemap.h +++ /dev/null @@ -1,37 +0,0 @@ -/********************************************************* - * Copyright (C) 2009 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 - * - *********************************************************/ - -#ifndef __COMPAT_PAGEMAP_H__ -# define __COMPAT_PAGEMAP_H__ - - -#include - -/* - * AOP_FLAG_NOFS was defined in the same changeset that - * grab_cache_page_write_begin() was introduced. - */ -#ifdef AOP_FLAG_NOFS -#define compat_grab_cache_page_write_begin(mapping, index, flags) \ - grab_cache_page_write_begin((mapping), (index), (flags)) -#else -#define compat_grab_cache_page_write_begin(mapping, index, flags) \ - __grab_cache_page((mapping), (index)); -#endif - -#endif /* __COMPAT_PAGEMAP_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_pci.h b/open-vm-tools/modules/linux/shared/compat_pci.h deleted file mode 100644 index d1f897a7b..000000000 --- a/open-vm-tools/modules/linux/shared/compat_pci.h +++ /dev/null @@ -1,72 +0,0 @@ -/********************************************************* - * Copyright (C) 1999 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 - * - *********************************************************/ - -/* - * compat_pci.h: PCI compatibility wrappers. - */ - -#ifndef __COMPAT_PCI_H__ -#define __COMPAT_PCI_H__ - -#include "compat_ioport.h" -#include - -#ifndef DMA_BIT_MASK -# define DMA_BIT_MASK(n) DMA_##n##BIT_MASK -#endif - -/* - * Power Management related compat wrappers. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) -# define compat_pci_save_state(pdev) pci_save_state((pdev), NULL) -# define compat_pci_restore_state(pdev) pci_restore_state((pdev), NULL) -#else -# define compat_pci_save_state(pdev) pci_save_state((pdev)) -# define compat_pci_restore_state(pdev) pci_restore_state((pdev)) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) -# define pm_message_t u32 -# define compat_pci_choose_state(pdev, state) (state) -# define PCI_D0 0 -# define PCI_D3hot 3 -#else -# define compat_pci_choose_state(pdev, state) pci_choose_state((pdev), (state)) -#endif - -/* 2.6.14 changed the PCI shutdown callback */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) -# define COMPAT_PCI_SHUTDOWN(func) .driver = { .shutdown = (func), } -# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct device *(var)) -# define COMPAT_PCI_TO_DEV(dev) (to_pci_dev(dev)) -#else -# define COMPAT_PCI_SHUTDOWN(func) .shutdown = (func) -# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct pci_dev *(var)) -# define COMPAT_PCI_TO_DEV(dev) (dev) -#endif - -/* 2.6.26 introduced the device_set_wakeup_enable() function */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) -# define compat_device_set_wakeup_enable(dev, val) do {} while(0) -#else -# define compat_device_set_wakeup_enable(dev, val) \ - device_set_wakeup_enable(dev, val) -#endif - -#endif /* __COMPAT_PCI_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_pci_mapping.h b/open-vm-tools/modules/linux/shared/compat_pci_mapping.h deleted file mode 100644 index fd9129992..000000000 --- a/open-vm-tools/modules/linux/shared/compat_pci_mapping.h +++ /dev/null @@ -1,84 +0,0 @@ -/********************************************************* - * Copyright (C) 2008 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 - * - *********************************************************/ - -#ifndef __COMPAT_PCI_MAPPING_H__ -#define __COMPAT_PCI_MAPPING_H__ - -#include -#include -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,41) -typedef u32 dma_addr_t; - -static __inline__ int -get_order(unsigned long size) -{ - int order; - - size = (size - 1) >> (PAGE_SHIFT - 1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - -static inline void * -compat_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) -{ - void *ptr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); - if (ptr) { - memset(ptr, 0, size); - *dma_handle = virt_to_phys(ptr); - } - return ptr; -} - -static inline void -compat_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - -static inline dma_addr_t -compat_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) -{ - return virt_to_phys(ptr); -} - -static inline void -compat_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, - size_t size, int direction) -{ -} - -#else -#define compat_pci_alloc_consistent(hwdev, size, dma_handle) \ - pci_alloc_consistent(hwdev, size, dma_handle) -#define compat_pci_free_consistent(hwdev, size, vaddr, dma_handle) \ - pci_free_consistent(hwdev, size, vaddr, dma_handle) -#define compat_pci_map_single(hwdev, ptr, size, direction) \ - pci_map_single(hwdev, ptr, size, direction) -#define compat_pci_unmap_single(hwdev, dma_addr, size, direction) \ - pci_unmap_single(hwdev, dma_addr, size, direction) -#endif - -#endif diff --git a/open-vm-tools/modules/linux/shared/compat_pgtable.h b/open-vm-tools/modules/linux/shared/compat_pgtable.h deleted file mode 100644 index dedc25ad1..000000000 --- a/open-vm-tools/modules/linux/shared/compat_pgtable.h +++ /dev/null @@ -1,139 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_PGTABLE_H__ -# define __COMPAT_PGTABLE_H__ - - -#if defined(CONFIG_PARAVIRT) && defined(CONFIG_HIGHPTE) -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) -# include -# undef paravirt_map_pt_hook -# define paravirt_map_pt_hook(type, va, pfn) do {} while (0) -# endif -#endif -#include - - -/* pte_page() API modified in 2.3.23 to return a struct page * --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 23) -# define compat_pte_page pte_page -#else -# include "compat_page.h" - -# define compat_pte_page(_pte) virt_to_page(pte_page(_pte)) -#endif - - -/* Appeared in 2.5.5 --hpreg */ -#ifndef pte_offset_map -/* Appeared in SuSE 8.0's 2.4.18 --hpreg */ -# ifdef pte_offset_atomic -# define pte_offset_map pte_offset_atomic -# define pte_unmap pte_kunmap -# else -# define pte_offset_map pte_offset -# define pte_unmap(_pte) -# endif -#endif - - -/* Appeared in 2.5.74-mmX --petr */ -#ifndef pmd_offset_map -# define pmd_offset_map(pgd, address) pmd_offset(pgd, address) -# define pmd_unmap(pmd) -#endif - - -/* - * Appeared in 2.6.10-rc2-mm1. Older kernels did L4 page tables as - * part of pgd_offset, or they did not have L4 page tables at all. - * In 2.6.11 pml4 -> pgd -> pmd -> pte hierarchy was replaced by - * pgd -> pud -> pmd -> pte hierarchy. - */ -#ifdef PUD_MASK -# define compat_pgd_offset(mm, address) pgd_offset(mm, address) -# define compat_pgd_present(pgd) pgd_present(pgd) -# define compat_pud_offset(pgd, address) pud_offset(pgd, address) -# define compat_pud_present(pud) pud_present(pud) -typedef pgd_t compat_pgd_t; -typedef pud_t compat_pud_t; -#elif defined(pml4_offset) -# define compat_pgd_offset(mm, address) pml4_offset(mm, address) -# define compat_pgd_present(pml4) pml4_present(pml4) -# define compat_pud_offset(pml4, address) pml4_pgd_offset(pml4, address) -# define compat_pud_present(pgd) pgd_present(pgd) -typedef pml4_t compat_pgd_t; -typedef pgd_t compat_pud_t; -#else -# define compat_pgd_offset(mm, address) pgd_offset(mm, address) -# define compat_pgd_present(pgd) pgd_present(pgd) -# define compat_pud_offset(pgd, address) (pgd) -# define compat_pud_present(pud) (1) -typedef pgd_t compat_pgd_t; -typedef pgd_t compat_pud_t; -#endif - - -#define compat_pgd_offset_k(mm, address) pgd_offset_k(address) - - -/* Introduced somewhere in 2.6.0, + backported to some 2.4 RedHat kernels */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pte_pfn) -# define pte_pfn(pte) page_to_pfn(compat_pte_page(pte)) -#endif - - -/* A page_table_lock field is added to struct mm_struct in 2.3.10 --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 10) -# define compat_get_page_table_lock(_mm) (&(_mm)->page_table_lock) -#else -# define compat_get_page_table_lock(_mm) NULL -#endif - - -/* - * Define VM_PAGE_KERNEL_EXEC for vmapping executable pages. - * - * On ia32 PAGE_KERNEL_EXEC was introduced in 2.6.8.1. Unfortunately it accesses - * __PAGE_KERNEL_EXEC which is not exported for modules. So we use - * __PAGE_KERNEL and just cut _PAGE_NX bit from it. - * - * For ia32 kernels before 2.6.8.1 we use PAGE_KERNEL directly, these kernels - * do not have noexec support. - * - * On x86-64 situation is a bit better: they always supported noexec, but - * before 2.6.8.1 flag was named PAGE_KERNEL_EXECUTABLE, and it was renamed - * to PAGE_KERNEL_EXEC when ia32 got noexec too (see above). - */ -#ifdef CONFIG_X86 -#ifdef _PAGE_NX -#define VM_PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL & ~_PAGE_NX) -#else -#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL -#endif -#else -#ifdef PAGE_KERNEL_EXECUTABLE -#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXECUTABLE -#else -#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC -#endif -#endif - - -#endif /* __COMPAT_PGTABLE_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_sched.h b/open-vm-tools/modules/linux/shared/compat_sched.h deleted file mode 100644 index 3f3304bd7..000000000 --- a/open-vm-tools/modules/linux/shared/compat_sched.h +++ /dev/null @@ -1,293 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_SCHED_H__ -# define __COMPAT_SCHED_H__ - - -#include - -/* CLONE_KERNEL available in 2.5.35 and higher. */ -#ifndef CLONE_KERNEL -#define CLONE_KERNEL CLONE_FILES | CLONE_FS | CLONE_SIGHAND -#endif - -/* TASK_COMM_LEN become available in 2.6.11. */ -#ifndef TASK_COMM_LEN -#define TASK_COMM_LEN 16 -#endif - -/* The capable() API appeared in 2.1.92 --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 92) -# define capable(_capability) suser() -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) -# define need_resched() need_resched -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) -# define need_resched() (current->need_resched) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) -# define cond_resched() (need_resched() ? schedule() : (void) 0) -#endif - -/* Oh well. We need yield... Happy us! */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) -# ifdef __x86_64__ -# define compat_yield() there_is_nothing_like_yield() -# else -# include -# include - -/* - * Used by _syscallX macros. Note that this is global variable, so - * do not rely on its contents too much. As exit() is only function - * we use, and we never check return value from exit(), we have - * no problem... - */ -extern int errno; - -/* - * compat_exit() provides an access to the exit() function. It must - * be named compat_exit(), as exit() (with different signature) is - * provided by x86-64, arm and other (but not by i386). - */ -# define __NR_compat_yield __NR_sched_yield -static inline _syscall0(int, compat_yield); -# endif -#else -# define compat_yield() yield() -#endif - - -/* - * Since 2.5.34 there are two methods to enumerate tasks: - * for_each_process(p) { ... } which enumerates only tasks and - * do_each_thread(g,t) { ... } while_each_thread(g,t) which enumerates - * also threads even if they share same pid. - */ -#ifndef for_each_process -# define for_each_process(p) for_each_task(p) -#endif - -#ifndef do_each_thread -# define do_each_thread(g, t) for_each_task(g) { t = g; do -# define while_each_thread(g, t) while (0) } -#endif - - -/* - * Lock for signal mask is moving target... - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 40) && defined(CLONE_PID) -/* 2.4.x without NPTL patches or early 2.5.x */ -#define compat_sigmask_lock sigmask_lock -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(¤t->blocked, (siginfo_ptr)) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 60) && !defined(INIT_SIGHAND) -/* RedHat's 2.4.x with first version of NPTL support, or 2.5.40 to 2.5.59 */ -#define compat_sigmask_lock sig->siglock -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(¤t->blocked, (siginfo_ptr)) -#else -/* RedHat's 2.4.x with second version of NPTL support, or 2.5.60+. */ -#define compat_sigmask_lock sighand->siglock -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(¤t->blocked, (siginfo_ptr)) -#else -#define compat_dequeue_signal_current(siginfo_ptr) \ - dequeue_signal(current, ¤t->blocked, (siginfo_ptr)) -#endif -#endif - -/* - * recalc_sigpending() had task argument in the past - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 29) && defined(CLONE_PID) -/* 2.4.x without NPTL patches or early 2.5.x */ -#define compat_recalc_sigpending() recalc_sigpending(current) -#else -/* RedHat's 2.4.x with NPTL support, or 2.5.29+ */ -#define compat_recalc_sigpending() recalc_sigpending() -#endif - - -/* - * reparent_to_init() was introduced in 2.4.8. In 2.5.38 (or possibly - * earlier, but later than 2.5.31) a call to it was added into - * daemonize(), so compat_daemonize no longer needs to call it. - * - * In 2.4.x kernels reparent_to_init() forgets to do correct refcounting - * on current->user. It is better to count one too many than one too few... - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 38) -#define compat_reparent_to_init() do { \ - reparent_to_init(); \ - atomic_inc(¤t->user->__count); \ - } while (0) -#else -#define compat_reparent_to_init() do {} while (0) -#endif - - -/* - * daemonize appeared in 2.2.18. Except 2.2.17-4-RH7.0, which has it too. - * Fortunately 2.2.17-4-RH7.0 uses versioned symbols, so we can check - * its existence with defined(). - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) && !defined(daemonize) -static inline void daemonize(void) { - struct fs_struct *fs; - - exit_mm(current); - current->session = 1; - current->pgrp = 1; - exit_fs(current); - fs = init_task.fs; - current->fs = fs; - atomic_inc(&fs->count); -} -#endif - - -/* - * flush_signals acquires sighand->siglock since 2.5.61... Verify RH's kernels! - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) -#define compat_flush_signals(task) do { \ - spin_lock_irq(&task->compat_sigmask_lock); \ - flush_signals(task); \ - spin_unlock_irq(&task->compat_sigmask_lock); \ - } while (0) -#else -#define compat_flush_signals(task) flush_signals(task) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) -#define compat_allow_signal(signr) do { \ - spin_lock_irq(¤t->compat_sigmask_lock); \ - sigdelset(¤t->blocked, signr); \ - compat_recalc_sigpending(); \ - spin_unlock_irq(¤t->compat_sigmask_lock); \ - } while (0) -#else -#define compat_allow_signal(signr) allow_signal(signr) -#endif - -/* - * daemonize can set process name since 2.5.61. Prior to 2.5.61, daemonize - * didn't block signals on our behalf. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) -#define compat_daemonize(x...) \ -({ \ - /* Beware! No snprintf here, so verify arguments! */ \ - sprintf(current->comm, x); \ - \ - /* Block all signals. */ \ - spin_lock_irq(¤t->compat_sigmask_lock); \ - sigfillset(¤t->blocked); \ - compat_recalc_sigpending(); \ - spin_unlock_irq(¤t->compat_sigmask_lock); \ - compat_flush_signals(current); \ - \ - daemonize(); \ - compat_reparent_to_init(); \ -}) -#else -#define compat_daemonize(x...) daemonize(x) -#endif - - -/* - * try to freeze a process. For kernels 2.6.11 or newer, we know how to choose - * the interface. The problem is that the oldest interface, introduced in - * 2.5.18, was backported to 2.4.x kernels. So if we're older than 2.6.11, - * we'll decide what to do based on whether or not swsusp was configured - * for the kernel. For kernels 2.6.20 and newer, we'll also need to include - * freezer.h since the try_to_freeze definition was pulled out of sched.h. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -#include -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) || defined(VMW_TL10S64_WORKAROUND) -#define compat_try_to_freeze() try_to_freeze() -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) -#define compat_try_to_freeze() try_to_freeze(PF_FREEZE) -#elif defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SOFTWARE_SUSPEND2) -#include "compat_mm.h" -#include -#include -static inline int compat_try_to_freeze(void) { - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); - return 1; - } else { - return 0; - } -} -#else -static inline int compat_try_to_freeze(void) { return 0; } -#endif - -/* - * As of 2.6.23-rc1, kernel threads are no longer freezable by - * default. Instead, kernel threads that need to be frozen must opt-in - * by calling set_freezable() as soon as the thread is created. - */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) -#define compat_set_freezable() do { set_freezable(); } while (0) -#else -#define compat_set_freezable() do {} while (0) -#endif - -/* - * Around 2.6.27 kernel stopped sending signals to kernel - * threads being frozen, instead threads have to check - * freezing() or use wait_event_freezable(). Unfortunately - * wait_event_freezable() completely hides the fact that - * thread was frozen from calling code and sometimes we do - * want to know that. - */ -#ifdef PF_FREEZER_NOSIG -#define compat_wait_check_freezing() freezing(current) -#else -#define compat_wait_check_freezing() (0) -#endif - -/* - * Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!) - * API is available since 2.6.19. Use them from 2.6.27-rc1 up. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -typedef int compat_pid; -#define compat_find_get_pid(pid) (pid) -#define compat_put_pid(pid) do { } while (0) -#define compat_kill_pid(pid, sig, flag) kill_proc(pid, sig, flag) -#else -typedef struct pid * compat_pid; -#define compat_find_get_pid(pid) find_get_pid(pid) -#define compat_put_pid(pid) put_pid(pid) -#define compat_kill_pid(pid, sig, flag) kill_pid(pid, sig, flag) -#endif - - -#endif /* __COMPAT_SCHED_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_scsi.h b/open-vm-tools/modules/linux/shared/compat_scsi.h deleted file mode 100644 index e0a4ba707..000000000 --- a/open-vm-tools/modules/linux/shared/compat_scsi.h +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_SCSI_H__ -# define __COMPAT_SCSI_H__ - - -/* The scsi_bufflen() API appeared somewhere in time --hpreg */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) -# define scsi_bufflen(cmd) ((cmd)->request_bufflen) -# define scsi_sg_count(cmd) ((cmd)->use_sg) -# define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer) -# define scsi_set_resid(cmd, _resid) ((cmd)->resid = _resid) -#endif - -/* - * Using scsi_sglist to access the request buffer looks strange - * so instead we define this macro. What happened is later kernel - * put all SCSI data in sglists, since it simplifies passing buffers - */ -#define scsi_request_buffer(cmd) scsi_sglist(cmd) - -#endif /* __COMPAT_SCSI_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_semaphore.h b/open-vm-tools/modules/linux/shared/compat_semaphore.h deleted file mode 100644 index f5527b9cd..000000000 --- a/open-vm-tools/modules/linux/shared/compat_semaphore.h +++ /dev/null @@ -1,49 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_SEMAPHORE_H__ -# define __COMPAT_SEMAPHORE_H__ - - -/* <= 2.6.25 have asm only, 2.6.26 has both, and 2.6.27-rc2+ has linux only. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -# include -#else -# include -#endif - - -/* -* The init_MUTEX_LOCKED() API appeared in 2.2.18, and is also in -* 2.2.17-21mdk --hpreg -*/ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) - #ifndef init_MUTEX_LOCKED - #define init_MUTEX_LOCKED(_sem) *(_sem) = MUTEX_LOCKED - #endif - #ifndef DECLARE_MUTEX - #define DECLARE_MUTEX(name) struct semaphore name = MUTEX - #endif - #ifndef DECLARE_MUTEX_LOCKED - #define DECLARE_MUTEX_LOCKED(name) struct semaphore name = MUTEX_LOCKED - #endif -#endif - - -#endif /* __COMPAT_SEMAPHORE_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_skbuff.h b/open-vm-tools/modules/linux/shared/compat_skbuff.h deleted file mode 100644 index b6468855d..000000000 --- a/open-vm-tools/modules/linux/shared/compat_skbuff.h +++ /dev/null @@ -1,170 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -#ifndef __COMPAT_SKBUFF_H__ -# define __COMPAT_SKBUFF_H__ - -#include - -/* - * When transition from mac/nh/h to skb_* accessors was made, also SKB_WITH_OVERHEAD - * was introduced. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) || \ - (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 21) && defined(SKB_WITH_OVERHEAD)) -#define compat_skb_mac_header(skb) skb_mac_header(skb) -#define compat_skb_network_header(skb) skb_network_header(skb) -#define compat_skb_network_offset(skb) skb_network_offset(skb) -#define compat_skb_transport_header(skb) skb_transport_header(skb) -#define compat_skb_transport_offset(skb) skb_transport_offset(skb) -#define compat_skb_network_header_len(skb) skb_network_header_len(skb) -#define compat_skb_tail_pointer(skb) skb_tail_pointer(skb) -#define compat_skb_end_pointer(skb) skb_end_pointer(skb) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -# define compat_skb_ip_header(skb) ip_hdr(skb) -# define compat_skb_ipv6_header(skb) ipv6_hdr(skb) -# define compat_skb_tcp_header(skb) tcp_hdr(skb) -#else -# define compat_skb_ip_header(skb) ((struct iphdr *)skb_network_header(skb)) -# define compat_skb_ipv6_header(skb) ((struct ipv6hdr *)skb_network_header(skb)) -# define compat_skb_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb)) -#endif -#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb) -#define compat_skb_reset_network_header(skb) skb_reset_network_header(skb) -#define compat_skb_reset_transport_header(skb) skb_reset_transport_header(skb) -#define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off) -#define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off) -#else -#define compat_skb_mac_header(skb) (skb)->mac.raw -#define compat_skb_network_header(skb) (skb)->nh.raw -#define compat_skb_network_offset(skb) ((skb)->nh.raw - (skb)->data) -#define compat_skb_transport_header(skb) (skb)->h.raw -#define compat_skb_transport_offset(skb) ((skb)->h.raw - (skb)->data) -#define compat_skb_network_header_len(skb) ((skb)->h.raw - (skb)->nh.raw) -#define compat_skb_tail_pointer(skb) (skb)->tail -#define compat_skb_end_pointer(skb) (skb)->end -#define compat_skb_ip_header(skb) (skb)->nh.iph -#define compat_skb_ipv6_header(skb) (skb)->nh.ipv6h -#define compat_skb_tcp_header(skb) (skb)->h.th -#define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data) -#define compat_skb_reset_network_header(skb) ((skb)->nh.raw = (skb)->data) -#define compat_skb_reset_transport_header(skb) ((skb)->h.raw = (skb)->data) -#define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off)) -#define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off)) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) || defined(VMW_SKB_LINEARIZE_2618) -# define compat_skb_linearize(skb) skb_linearize((skb)) -#else - -# if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0) -# define compat_skb_linearize(skb) __skb_linearize((skb), GFP_ATOMIC) -# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) -# define compat_skb_linearize(skb) skb_linearize((skb), GFP_ATOMIC) -# else -static inline int -compat_skb_linearize(struct sk_buff *skb) -{ - return 0; -} -# endif - -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -#define compat_skb_csum_offset(skb) (skb)->csum_offset -#else -#define compat_skb_csum_offset(skb) (skb)->csum -#endif - -/* - * Note that compat_skb_csum_start() has semantic different from kernel's csum_start: - * kernel's skb->csum_start is offset between start of checksummed area and start of - * complete skb buffer, while our compat_skb_csum_start(skb) is offset from start - * of packet itself. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -#define compat_skb_csum_start(skb) ((skb)->csum_start - skb_headroom(skb)) -#else -#define compat_skb_csum_start(skb) compat_skb_transport_offset(skb) -#endif - -#if defined(NETIF_F_GSO) /* 2.6.18 and upwards */ -#define compat_skb_mss(skb) (skb_shinfo(skb)->gso_size) -#else -#define compat_skb_mss(skb) (skb_shinfo(skb)->tso_size) -#endif - -/* used by both received pkts and outgoing ones */ -#define VM_CHECKSUM_UNNECESSARY CHECKSUM_UNNECESSARY - -/* csum status of received pkts */ -#if defined(CHECKSUM_COMPLETE) -# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_COMPLETE -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) -# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_HW -#else -# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL -#endif - -/* csum status of outgoing pkts */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) -# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_HW -#else -# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)) -# define compat_kfree_skb(skb, type) kfree_skb(skb, type) -# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb, type) -# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb, type) -# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb, type) -#else -# define compat_kfree_skb(skb, type) kfree_skb(skb) -# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb) -# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) -# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb) -# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb) -# else -# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb_any(skb) -# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb_irq(skb) -# endif -#endif - -#ifndef NET_IP_ALIGN -# define COMPAT_NET_IP_ALIGN 2 -#else -# define COMPAT_NET_IP_ALIGN NET_IP_ALIGN -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) -# define compat_skb_headlen(skb) skb_headlen(skb) -# define compat_pskb_may_pull(skb, len) pskb_may_pull(skb, len) -# define compat_skb_is_nonlinear(skb) skb_is_nonlinear(skb) -#else -# define compat_skb_headlen(skb) (skb)->len -# define compat_pskb_may_pull(skb, len) 1 -# define compat_skb_is_nonlinear(skb) 0 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) -# define compat_skb_header_cloned(skb) skb_header_cloned(skb) -#else -# define compat_skb_header_cloned(skb) 0 -#endif -#endif /* __COMPAT_SKBUFF_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_slab.h b/open-vm-tools/modules/linux/shared/compat_slab.h deleted file mode 100644 index 1ce2c4fd1..000000000 --- a/open-vm-tools/modules/linux/shared/compat_slab.h +++ /dev/null @@ -1,85 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -#ifndef __COMPAT_SLAB_H__ -# define __COMPAT_SLAB_H__ - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) -# include -#else -# include -#endif - -/* - * Before 2.6.20, kmem_cache_t was the accepted way to refer to a kmem_cache - * structure. Prior to 2.6.15, this structure was called kmem_cache_s, and - * afterwards it was renamed to kmem_cache. Here we keep things simple and use - * the accepted typedef until it became deprecated, at which point we switch - * over to the kmem_cache name. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -# define compat_kmem_cache struct kmem_cache -#else -# define compat_kmem_cache kmem_cache_t -#endif - -/* - * Up to 2.6.22 kmem_cache_create has 6 arguments - name, size, alignment, flags, - * constructor, and destructor. Then for some time kernel was asserting that - * destructor is NULL, and since 2.6.23-pre1 kmem_cache_create takes only 5 - * arguments - destructor is gone. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) || defined(VMW_KMEMCR_HAS_DTOR) -#define compat_kmem_cache_create(name, size, align, flags, ctor) \ - kmem_cache_create(name, size, align, flags, ctor, NULL) -#else -#define compat_kmem_cache_create(name, size, align, flags, ctor) \ - kmem_cache_create(name, size, align, flags, ctor) -#endif - -/* - * Up to 2.6.23 kmem_cache constructor has three arguments - pointer to block to - * prepare (aka "this"), from which cache it came, and some unused flags. After - * 2.6.23 flags were removed, and order of "this" and cache parameters was swapped... - * Since 2.6.27-rc2 everything is different again, and ctor has only one argument. - * - * HAS_3_ARGS has precedence over HAS_2_ARGS if both are defined. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) -# define VMW_KMEMCR_CTOR_HAS_3_ARGS -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) && !defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) -# define VMW_KMEMCR_CTOR_HAS_2_ARGS -#endif - -#if defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) -typedef void compat_kmem_cache_ctor(void *, compat_kmem_cache *, unsigned long); -#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg, \ - compat_kmem_cache *cache, \ - unsigned long flags -#elif defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) -typedef void compat_kmem_cache_ctor(compat_kmem_cache *, void *); -#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) compat_kmem_cache *cache, \ - void *arg -#else -typedef void compat_kmem_cache_ctor(void *); -#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg -#endif - -#endif /* __COMPAT_SLAB_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_sock.h b/open-vm-tools/modules/linux/shared/compat_sock.h deleted file mode 100644 index 1aae4ec66..000000000 --- a/open-vm-tools/modules/linux/shared/compat_sock.h +++ /dev/null @@ -1,77 +0,0 @@ -/********************************************************* - * Copyright (C) 2003 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 - * - *********************************************************/ - -#ifndef __COMPAT_SOCK_H__ -# define __COMPAT_SOCK_H__ - -#include /* for NULL */ -#include - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) -static inline wait_queue_head_t *sk_sleep(struct sock *sk) -{ - return sk->sk_sleep; -} -#endif - - -/* - * Prior to 2.6.24, there was no sock network namespace member. In 2.6.26, it - * was hidden behind accessor functions so that its behavior could vary - * depending on the value of CONFIG_NET_NS. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -# define compat_sock_net(sk) sock_net(sk) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -# define compat_sock_net(sk) sk->sk_net -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) - -#ifndef CONFIG_FILTER -# define sk_filter(sk, skb, needlock) 0 -#endif - -/* Taken from 2.6.16's sock.h and modified for macro. */ -# define compat_sk_receive_skb(sk, skb, nested) \ - ({ \ - int rc = NET_RX_SUCCESS; \ - \ - if (sk_filter(sk, skb, 0)) { \ - kfree_skb(skb); \ - } else { \ - skb->dev = NULL; \ - bh_lock_sock(sk); \ - if (!sock_owned_by_user(sk)) { \ - rc = (sk)->sk_backlog_rcv(sk, skb); \ - } else { \ - sk_add_backlog(sk, skb); \ - } \ - bh_unlock_sock(sk); \ - } \ - \ - sock_put(sk); \ - rc; \ - }) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -# define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb) -#else -# define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb, nested) -#endif - -#endif /* __COMPAT_SOCK_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_spinlock.h b/open-vm-tools/modules/linux/shared/compat_spinlock.h deleted file mode 100644 index b8987a5a2..000000000 --- a/open-vm-tools/modules/linux/shared/compat_spinlock.h +++ /dev/null @@ -1,48 +0,0 @@ -/********************************************************* - * Copyright (C) 2005 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 - * - *********************************************************/ - -#ifndef __COMPAT_SPINLOCK_H__ -# define __COMPAT_SPINLOCK_H__ - -#include - -/* - * Preempt support was added during 2.5.x development cycle, and later - * it was backported to 2.4.x. In 2.4.x backport these definitions - * live in linux/spinlock.h, that's why we put them here (in 2.6.x they - * are defined in linux/preempt.h which is included by linux/spinlock.h). - */ -#ifdef CONFIG_PREEMPT -#define compat_preempt_disable() preempt_disable() -#define compat_preempt_enable() preempt_enable() -#else -#define compat_preempt_disable() do { } while (0) -#define compat_preempt_enable() do { } while (0) -#endif - -/* Some older kernels - 2.6.10 and earlier - lack DEFINE_SPINLOCK */ -#ifndef DEFINE_SPINLOCK -#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED -#endif - -/* Same goes for DEFINE_RWLOCK */ -#ifndef DEFINE_RWLOCK -#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED -#endif - -#endif /* __COMPAT_SPINLOCK_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_statfs.h b/open-vm-tools/modules/linux/shared/compat_statfs.h deleted file mode 100644 index 29ec4f8e6..000000000 --- a/open-vm-tools/modules/linux/shared/compat_statfs.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -#ifndef __COMPAT_STATFS_H__ -# define __COMPAT_STATFS_H__ - -/* vfs.h simply include statfs.h, but it knows what directory statfs.h is in. */ -#include - -/* 2.5.74 renamed struct statfs to kstatfs. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 74) -#define compat_kstatfs kstatfs -#else -#define compat_kstatfs statfs -#endif - -#endif /* __COMPAT_STATFS_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_string.h b/open-vm-tools/modules/linux/shared/compat_string.h deleted file mode 100644 index b74f87556..000000000 --- a/open-vm-tools/modules/linux/shared/compat_string.h +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -#ifndef __COMPAT_STRING_H__ -# define __COMPAT_STRING_H__ - -#include - -/* - * kstrdup was born in 2.6.13. This implementation is almost identical to the - * one found there. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -#define compat_kstrdup(s, gfp) kstrdup(s, gfp) -#else -#define compat_kstrdup(s, gfp) \ -({ \ - size_t len; \ - char *buf; \ - len = strlen(s) + 1; \ - buf = kmalloc(len, gfp); \ - memcpy(buf, s, len); \ - buf; \ -}) -#endif - -#endif /* __COMPAT_STRING_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_timer.h b/open-vm-tools/modules/linux/shared/compat_timer.h deleted file mode 100644 index 03a27971f..000000000 --- a/open-vm-tools/modules/linux/shared/compat_timer.h +++ /dev/null @@ -1,117 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_TIMER_H__ -# define __COMPAT_TIMER_H__ - - -/* - * The del_timer_sync() API appeared in 2.3.43 - * It became reliable in 2.4.0-test3 - * - * --hpreg - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -# define compat_del_timer_sync(timer) del_timer_sync(timer) -#else -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43) - /* 2.3.43 removed asm/softirq.h's reference to bh_base. */ -# include -# endif -# include - -static inline int -compat_del_timer_sync(struct timer_list *timer) // IN -{ - int wasPending; - - start_bh_atomic(); - wasPending = del_timer(timer); - end_bh_atomic(); - - return wasPending; -} -#endif - - -/* - * The msleep_interruptible() API appeared in 2.6.9. - * It is based on the msleep() API, which appeared in 2.4.29. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) -# include -# define compat_msleep_interruptible(msecs) msleep_interruptible(msecs) -# define compat_msleep(msecs) msleep(msecs) -#else -# include -/* - * msecs_to_jiffies appeared in 2.6.7. For earlier kernels, - * fall back to slow-case code (we don't use this operation - * enough to need the performance). - */ -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) -# define msecs_to_jiffies(msecs) (((msecs) * HZ + 999) / 1000) -# endif -/* - * set_current_state appeared in 2.2.18. - */ -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) -# define set_current_state(a) do { current->state = (a); } while(0) -# endif - -static inline void -compat_msleep_interruptible(unsigned long msecs) // IN -{ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(msecs) + 1); -} - -static inline void -compat_msleep(unsigned long msecs) // IN -{ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(msecs) + 1); -} -#endif - - -/* - * There is init_timer_deferrable() since 2.6.22. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -# define compat_init_timer_deferrable(timer) init_timer_deferrable(timer) -#else -# define compat_init_timer_deferrable(timer) init_timer(timer) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) -static inline void compat_setup_timer(struct timer_list * timer, - void (*function)(unsigned long), - unsigned long data) -{ - timer->function = function; - timer->data = data; - init_timer(timer); -} -#else -# define compat_setup_timer(timer, function, data) \ - setup_timer(timer, function, data) -#endif - - -#endif /* __COMPAT_TIMER_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_uaccess.h b/open-vm-tools/modules/linux/shared/compat_uaccess.h deleted file mode 100644 index d58ee0596..000000000 --- a/open-vm-tools/modules/linux/shared/compat_uaccess.h +++ /dev/null @@ -1,79 +0,0 @@ -/********************************************************* - * Copyright (C) 2002 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 - * - *********************************************************/ - -#ifndef __COMPAT_UACCESS_H__ -# define __COMPAT_UACCESS_H__ - - -/* User space access functions moved in 2.1.7 to asm/uaccess.h --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 7) -# include -#else -# include -#endif - - -/* get_user() API modified in 2.1.4 to take 2 arguments --hpreg */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 4) -# define compat_get_user get_user -#else -/* - * We assign 0 to the variable in case of failure to prevent "`_var' might be - * used uninitialized in this function" compiler warnings. I think it is OK, - * because the hardware-based version in newer kernels probably has the same - * semantics and does not guarantee that the value of _var will not be - * modified, should the access fail --hpreg - */ -# define compat_get_user(_var, _uvAddr) ({ \ - int _status; \ - \ - _status = verify_area(VERIFY_READ, _uvAddr, sizeof(*(_uvAddr))); \ - if (_status == 0) { \ - (_var) = get_user(_uvAddr); \ - } else { \ - (_var) = 0; \ - } \ - _status; \ -}) -#endif - - -/* - * The copy_from_user() API appeared in 2.1.4 - * - * The emulation is not perfect here, but it is conservative: on failure, we - * always return the total size, instead of the potentially smaller faulty - * size --hpreg - * - * Since 2.5.55 copy_from_user() is no longer macro. - */ -#if !defined(copy_from_user) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) -# define copy_from_user(_to, _from, _size) ( \ - verify_area(VERIFY_READ, _from, _size) \ - ? (_size) \ - : (memcpy_fromfs(_to, _from, _size), 0) \ -) -# define copy_to_user(_to, _from, _size) ( \ - verify_area(VERIFY_WRITE, _to, _size) \ - ? (_size) \ - : (memcpy_tofs(_to, _from, _size), 0) \ -) -#endif - - -#endif /* __COMPAT_UACCESS_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_version.h b/open-vm-tools/modules/linux/shared/compat_version.h deleted file mode 100644 index 56d021cff..000000000 --- a/open-vm-tools/modules/linux/shared/compat_version.h +++ /dev/null @@ -1,131 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef __COMPAT_VERSION_H__ -# define __COMPAT_VERSION_H__ - -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMKDRIVERS -#include "includeCheck.h" - - -#ifndef __linux__ -# error "linux-version.h" -#endif - - -#include - -#ifndef KERNEL_VERSION -# error KERNEL_VERSION macro is not defined, environment is busted -#endif - - -/* - * Distinguish relevant classes of Linux kernels. - * - * The convention is that version X defines all - * the KERNEL_Y symbols where Y <= X. - * - * XXX Do not add more definitions here. This way of doing things does not - * scale, and we are going to phase it out soon --hpreg - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) -# define KERNEL_2_1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) -# define KERNEL_2_2 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1) -# define KERNEL_2_3_1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15) -/* new networking */ -# define KERNEL_2_3_15 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) -/* new procfs */ -# define KERNEL_2_3_25 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) -/* even newer procfs */ -# define KERNEL_2_3_29 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43) -/* softnet changes */ -# define KERNEL_2_3_43 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47) -/* more softnet changes */ -# define KERNEL_2_3_47 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99) -/* name in netdevice struct is array and not pointer */ -# define KERNEL_2_3_99 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -/* New 'owner' member at the beginning of struct file_operations */ -# define KERNEL_2_4_0 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) -/* New netif_rx_ni() --hpreg */ -# define KERNEL_2_4_8 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2) -/* New kdev_t, major()/minor() API --hpreg */ -# define KERNEL_2_5_2 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) -/* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */ -# define KERNEL_2_5_5 -#endif - -/* Linux kernel 3.0 can be called 2.6.40, and 3.1 can be 2.6.41... - * Use COMPAT_LINUX_VERSION_CHECK_LT iff you need to compare running kernel to - * versions 3.0 and above. - * - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) - /* Straight forward comparison if kernel version is 3.0.0 and beyond */ -# define COMPAT_LINUX_VERSION_CHECK_LT(a, b, c) LINUX_VERSION_CODE < KERNEL_VERSION (a, b, c) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 40) - /* Use b of the check to calculate corresponding c of kernel - * version to compare */ -# define COMPAT_LINUX_VERSION_CHECK_LT(a, b, c) LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, (b + 40)) -#else - /* This is anyways lesser than any 3.x versions */ -# define COMPAT_LINUX_VERSION_CHECK_LT(a, b, c) 1 -#endif - -#endif /* __COMPAT_VERSION_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_workqueue.h b/open-vm-tools/modules/linux/shared/compat_workqueue.h deleted file mode 100644 index 78b5bfceb..000000000 --- a/open-vm-tools/modules/linux/shared/compat_workqueue.h +++ /dev/null @@ -1,166 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -#ifndef __COMPAT_WORKQUEUE_H__ -# define __COMPAT_WORKQUEUE_H__ - -#include - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) -# include -#endif - -/* - * - * Work queues and delayed work queues. - * - * Prior to 2.5.41, the notion of work queues did not exist. Taskqueues are - * used for work queues and timers are used for delayed work queues. - * - * After 2.6.20, normal work structs ("work_struct") and delayed work - * ("delayed_work") structs were separated so that the work_struct could be - * slimmed down. The interface was also changed such that the address of the - * work_struct itself is passed in as the argument to the work function. This - * requires that one embed the work struct in the larger struct containing the - * information necessary to complete the work and use container_of() to obtain - * the address of the containing structure. - * - * Users of these macros should embed a compat_work or compat_delayed_work in - * a larger structure, then specify the larger structure as the _data argument - * for the initialization functions, specify the work function to take - * a compat_work_arg or compat_delayed_work_arg, then use the appropriate - * _GET_DATA macro to obtain the reference to the structure passed in as _data. - * An example is below. - * - * - * typedef struct WorkData { - * int data; - * compat_work work; - * } WorkData; - * - * - * void - * WorkFunc(compat_work_arg data) - * { - * WorkData *workData = COMPAT_WORK_GET_DATA(data, WorkData, work); - * - * ... - * } - * - * - * { - * WorkData *workData = kmalloc(sizeof *workData, GFP_EXAMPLE); - * if (!workData) { - * return -ENOMEM; - * } - * - * COMPAT_INIT_WORK(&workData->work, WorkFunc, workData); - * compat_schedule_work(&workData->work); - * } - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 41) /* { */ -typedef struct tq_struct compat_work; -typedef struct compat_delayed_work { - struct tq_struct work; - struct timer_list timer; -} compat_delayed_work; -typedef void * compat_work_arg; -typedef void * compat_delayed_work_arg; - -/* - * Delayed work queues need to run at some point in the future in process - * context, but task queues don't support delaying the task one is scheduling. - * Timers allow us to delay the execution of our work queue until the future, - * but timer handlers run in bottom-half context. As such, we use both a timer - * and task queue and use the timer handler below to schedule the task in - * process context immediately. The timer lets us delay execution, and the - * task queue lets us run in process context. - * - * Note that this is similar to how delayed_work is implemented with work - * queues in later kernel versions. - */ -static inline void -__compat_delayed_work_timer(unsigned long arg) -{ - compat_delayed_work *dwork = (compat_delayed_work *)arg; - if (dwork) { - schedule_task(&dwork->work); - } -} - -# define COMPAT_INIT_WORK(_work, _func, _data) \ - INIT_LIST_HEAD(&(_work)->list); \ - (_work)->sync = 0; \ - (_work)->routine = _func; \ - (_work)->data = _data -# define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \ - COMPAT_INIT_WORK(&(_work)->work, _func, _data); \ - init_timer(&(_work)->timer); \ - (_work)->timer.expires = 0; \ - (_work)->timer.function = __compat_delayed_work_timer; \ - (_work)->timer.data = (unsigned long)_work -# define compat_schedule_work(_work) \ - schedule_task(_work) -# define compat_schedule_delayed_work(_work, _delay) \ - (_work)->timer.expires = jiffies + _delay; \ - add_timer(&(_work)->timer) -# define COMPAT_WORK_GET_DATA(_p, _type, _member) \ - (_type *)(_p) -# define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \ - (_type *)(_p) - -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) \ - && !defined(__VMKLNX__) /* } { */ -typedef struct work_struct compat_work; -typedef struct work_struct compat_delayed_work; -typedef void * compat_work_arg; -typedef void * compat_delayed_work_arg; -# define COMPAT_INIT_WORK(_work, _func, _data) \ - INIT_WORK(_work, _func, _data) -# define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \ - INIT_WORK(_work, _func, _data) -# define compat_schedule_work(_work) \ - schedule_work(_work) -# define compat_schedule_delayed_work(_work, _delay) \ - schedule_delayed_work(_work, _delay) -# define COMPAT_WORK_GET_DATA(_p, _type, _member) \ - (_type *)(_p) -# define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \ - (_type *)(_p) - -#else /* } Linux >= 2.6.20 { */ -typedef struct work_struct compat_work; -typedef struct delayed_work compat_delayed_work; -typedef struct work_struct * compat_work_arg; -typedef struct work_struct * compat_delayed_work_arg; -# define COMPAT_INIT_WORK(_work, _func, _data) \ - INIT_WORK(_work, _func) -# define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \ - INIT_DELAYED_WORK(_work, _func) -# define compat_schedule_work(_work) \ - schedule_work(_work) -# define compat_schedule_delayed_work(_work, _delay) \ - schedule_delayed_work(_work, _delay) -# define COMPAT_WORK_GET_DATA(_p, _type, _member) \ - container_of(_p, _type, _member) -# define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \ - container_of(_p, _type, _member.work) -#endif /* } */ - -#endif /* __COMPAT_WORKQUEUE_H__ */ - diff --git a/open-vm-tools/modules/linux/shared/driver-config.h b/open-vm-tools/modules/linux/shared/driver-config.h deleted file mode 100644 index fbf45d3c7..000000000 --- a/open-vm-tools/modules/linux/shared/driver-config.h +++ /dev/null @@ -1,79 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -/* - * Sets the proper defines from the Linux header files - * - * This file must be included before the inclusion of any kernel header file, - * with the exception of linux/autoconf.h and linux/version.h --hpreg - */ - -#ifndef __VMX_CONFIG_H__ -#define __VMX_CONFIG_H__ - -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_DISTRIBUTE -#define INCLUDE_ALLOW_VMKDRIVERS -#include "includeCheck.h" - -#include "compat_version.h" -#include "compat_autoconf.h" - -/* - * We rely on Kernel Module support. Check here. - */ -#ifndef CONFIG_MODULES -# error "No Module support in this kernel. Please configure with CONFIG_MODULES" -#endif - -/* - * 2.2 kernels still use __SMP__ (derived from CONFIG_SMP - * in the main Makefile), so we do it here. - */ - -#ifdef CONFIG_SMP -# define __SMP__ 1 -#endif - -#if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1) -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) -/* - * MODVERSIONS might be already defined when using kernel's Makefiles. - */ -# ifndef MODVERSIONS -# define MODVERSIONS -# endif -# include -# endif -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -/* - * Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h. - */ -# include -# define _STDINT_H 1 -#endif - -#ifndef __KERNEL__ -# define __KERNEL__ -#endif - -#endif diff --git a/open-vm-tools/modules/linux/shared/driverLog.c b/open-vm-tools/modules/linux/shared/driverLog.c deleted file mode 100644 index 39779f342..000000000 --- a/open-vm-tools/modules/linux/shared/driverLog.c +++ /dev/null @@ -1,207 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2014 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 - * - *********************************************************/ - - -/* - * driverLog.c -- - * - * Common logging functions for Linux kernel modules. - */ - -#include "driver-config.h" -#include "compat_kernel.h" -#include "compat_sched.h" -#include - -#include "driverLog.h" - -#define LINUXLOG_BUFFER_SIZE 1024 - -static const char *driverLogPrefix = ""; - -/* - * vsnprintf was born in 2.4.10. Fall back on vsprintf if we're - * an older kernel. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) -# define vsnprintf(str, size, fmt, args) vsprintf(str, fmt, args) -#endif - - -/* - *---------------------------------------------------------------------------- - * - * DriverLog_Init -- - * - * Initializes the Linux logging. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -DriverLog_Init(const char *prefix) // IN -{ - driverLogPrefix = prefix ? prefix : ""; -} - - -/* - *---------------------------------------------------------------------- - * - * DriverLogPrint -- - * - * Log error message from a Linux module. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -DriverLogPrint(const char *level, // IN: KERN_* constant - const char *fmt, // IN: error format string - va_list args) // IN: arguments for format string -{ - static char staticBuf[LINUXLOG_BUFFER_SIZE]; - char stackBuf[128]; - va_list args2; - const char *buf; - - /* - * By default, use a small buffer on the stack (thread safe). If it is too - * small, fall back to a larger static buffer (not thread safe). - */ - va_copy(args2, args); - if (vsnprintf(stackBuf, sizeof stackBuf, fmt, args2) < sizeof stackBuf) { - buf = stackBuf; - } else { - vsnprintf(staticBuf, sizeof staticBuf, fmt, args); - buf = staticBuf; - } - va_end(args2); - - printk("%s%s[%d]: %s", level, driverLogPrefix, current->pid, buf); -} - - -/* - *---------------------------------------------------------------------- - * - * Warning -- - * - * Warning messages from kernel module: logged into kernel log - * as warnings. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Warning(const char *fmt, ...) // IN: warning format string -{ - va_list args; - - va_start(args, fmt); - DriverLogPrint(KERN_WARNING, fmt, args); - va_end(args); -} - - -/* - *---------------------------------------------------------------------- - * - * Log -- - * - * Log messages from kernel module: logged into kernel log - * as debug information. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -Log(const char *fmt, ...) // IN: log format string -{ - va_list args; - - /* - * Use the kernel log with at least a KERN_DEBUG level - * so it doesn't garbage the screen at (re)boot time on RedHat 6.0. - */ - - va_start(args, fmt); - DriverLogPrint(KERN_DEBUG, fmt, args); - va_end(args); -} - - -/* - *---------------------------------------------------------------------- - * - * Panic -- - * - * ASSERTION failures and Panics from kernel module get here. - * Message is logged to the kernel log and on console. - * - * Results: - * None. - * - * Side effects: - * Never returns - * - *---------------------------------------------------------------------- - */ - -void -Panic(const char *fmt, ...) // IN: panic format string -{ - va_list args; - - va_start(args, fmt); - DriverLogPrint(KERN_EMERG, fmt, args); - va_end(args); - -#ifdef BUG - BUG(); -#else - /* Should die with %cs unwritable, or at least with page fault. */ - asm volatile("movb $0, %cs:(0)"); -#endif - - while (1); -} diff --git a/open-vm-tools/modules/linux/shared/driverLog.h b/open-vm-tools/modules/linux/shared/driverLog.h deleted file mode 100644 index 04dd07cd0..000000000 --- a/open-vm-tools/modules/linux/shared/driverLog.h +++ /dev/null @@ -1,37 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2014 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 - * - *********************************************************/ - - -/* - * driverLog.h -- - * - * Logging functions for Linux kernel modules. - */ - -#ifndef __DRIVERLOG_H__ -#define __DRIVERLOG_H__ - -/* - * The definitions of Warning(), Log(), and Panic() come from vm_assert.h for - * consistency. - */ -#include "vm_assert.h" - -void DriverLog_Init(const char *prefix); - -#endif /* __DRIVERLOG_H__ */ diff --git a/open-vm-tools/modules/linux/shared/kernelStubs.h b/open-vm-tools/modules/linux/shared/kernelStubs.h deleted file mode 100644 index 5d88cb740..000000000 --- a/open-vm-tools/modules/linux/shared/kernelStubs.h +++ /dev/null @@ -1,271 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * kernelStubs.h - * - * KernelStubs implements some userspace library functions in terms - * of kernel functions to allow library userspace code to be used in a - * kernel. - */ - -#ifndef __KERNELSTUBS_H__ -#define __KERNELSTUBS_H__ - -#define KRNL_STUBS_DRIVER_TYPE_POSIX 1 -#define KRNL_STUBS_DRIVER_TYPE_GDI 2 -#define KRNL_STUBS_DRIVER_TYPE_WDM 3 -#define KRNL_STUBS_DRIVER_TYPE_NDIS 4 - -// For now (vsphere-2015), choose a good default. Later we'll modify all the -// build files using KernelStubs to set this. -#ifndef KRNL_STUBS_DRIVER_TYPE -# if defined(_WIN32) -# define KRNL_STUBS_DRIVER_TYPE KRNL_STUBS_DRIVER_TYPE_WDM -# else -# define KRNL_STUBS_DRIVER_TYPE KRNL_STUBS_DRIVER_TYPE_POSIX -# endif -#endif - -#ifdef linux -# ifndef __KERNEL__ -# error "__KERNEL__ is not defined" -# endif -# include "driver-config.h" // Must be included before any other header files -# include "vm_basic_types.h" -# include -# include -#elif defined(_WIN32) -# define _CRT_ALLOCATION_DEFINED // prevent malloc.h from defining malloc et. all -# if KRNL_STUBS_DRIVER_TYPE == KRNL_STUBS_DRIVER_TYPE_GDI -# include -# include -# include -# include "vm_basic_types.h" -# include "vm_basic_defs.h" -# include "vm_assert.h" -# elif KRNL_STUBS_DRIVER_TYPE == KRNL_STUBS_DRIVER_TYPE_NDIS -# include "vm_basic_types.h" -# include -# include "kernelStubsFloorFixes.h" -# include -# elif KRNL_STUBS_DRIVER_TYPE == KRNL_STUBS_DRIVER_TYPE_WDM -# include "vm_basic_types.h" -# if defined(NTDDI_WINXP) && (NTDDI_VERSION >= NTDDI_WINXP) -# include /* kernel memory APIs, DbgPrintEx */ -# else -# include /* kernel memory APIs */ -# endif -# include /* for _vsnprintf, vsprintf */ -# include /* for va_start stuff */ -# include /* for min macro. */ -# include "vm_basic_defs.h" -# include "vm_assert.h" /* Our assert macros */ -# include "kernelStubsFloorFixes.h" -# else -# error Type KRNL_STUBS_DRIVER_TYPE must be defined. -# endif -#elif defined(__FreeBSD__) -# include "vm_basic_types.h" -# ifndef _KERNEL -# error "_KERNEL is not defined" -# endif -# include -# include -# include -# include -# include -# include -#elif defined(__APPLE__) -# include "vm_basic_types.h" -# ifndef KERNEL -# error "KERNEL is not defined" -# endif -# include -# include -# elif defined(sun) -# include "vm_basic_types.h" -# include -# include -#endif -#include "kernelStubsSal.h" - -/* - * Function Prototypes - */ - -#if defined(__linux__) || defined(__APPLE__) || defined (sun) - -# ifdef linux /* if (linux) { */ -char *strdup(const char *source); -# endif - -/* Shared between Linux and Apple kernel stubs. */ -void *malloc(size_t size); -void free(void *mem); -void *calloc(size_t num, size_t len); -void *realloc(void *ptr, size_t newSize); - -#elif defined(_WIN32) /* } else if (_WIN32) { */ - -_Ret_allocates_malloc_mem_opt_bytecap_(_Size) -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -_CRTNOALIAS _CRTRESTRICT -void * __cdecl malloc( - _In_ size_t _Size); - -_Ret_allocates_malloc_mem_opt_bytecount_(_Count*_Size) -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -_CRTNOALIAS _CRTRESTRICT -void * __cdecl calloc( - _In_ size_t _Count, - _In_ size_t _Size); - -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -_CRTNOALIAS -void __cdecl free( - _In_frees_malloc_mem_opt_ void * _Memory); - -_Success_(return != 0) -_When_(_Memory != 0, _Ret_reallocates_malloc_mem_opt_newbytecap_oldbytecap_(_NewSize, ((uintptr_t*)_Memory)[-1])) -_When_(_Memory == 0, _Ret_reallocates_malloc_mem_opt_newbytecap_(_NewSize)) -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -_CRTNOALIAS _CRTRESTRICT -void * __cdecl realloc( - _In_reallocates_malloc_mem_opt_oldptr_ void * _Memory, - _In_ size_t _NewSize); - -_Success_(return != 0) -_Ret_allocates_malloc_mem_opt_z_ -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -_CRTIMP -char * __cdecl _strdup_impl( - _In_opt_z_ const char * _Src); - -#define strdup _strdup_impl - -#elif defined(__FreeBSD__) /* } else if (FreeBSD) { */ - -/* Kernel memory on FreeBSD is tagged for statistics and sanity checking. */ -MALLOC_DECLARE(M_VMWARE_TEMP); - -/* - * On FreeBSD, the general memory allocator for both userland and the kernel is named - * malloc, but the kernel malloc() takes more arguments. The following alias & macros - * work around this, to provide the standard malloc() API for userspace code that is - * being used in the kernel. - */ - -# undef malloc - -static INLINE void * -__compat_malloc(unsigned long size, struct malloc_type *type, int flags) { - return malloc(size, type, flags); -} - -# define malloc(size) __compat_malloc(size, M_VMWARE_TEMP, M_NOWAIT) -# define calloc(count, size) __compat_malloc((count) * (size), \ - M_VMWARE_TEMP, M_NOWAIT|M_ZERO) -# define realloc(buf, size) realloc(buf, size, M_VMWARE_TEMP, M_NOWAIT) -# define free(buf) free(buf, M_VMWARE_TEMP) -# define strchr(s,c) index(s,c) -# define strrchr(s,c) rindex(s,c) - -#endif /* } */ - -_Ret_writes_z_(maxSize) -char *Str_Strcpy( - _Out_z_cap_(maxSize) char *buf, - _In_z_ const char *src, - _In_ size_t maxSize); - -_Ret_writes_z_(maxSize) -char *Str_Strcat( - _Inout_z_cap_(maxSize) char *buf, - _In_z_ const char *src, - _In_ size_t maxSize); - -_Success_(return >= 0) -int Str_Sprintf( - _Out_z_cap_(maxSize) _Post_z_count_(return+1) char *buf, - _In_ size_t maxSize, - _In_z_ _Printf_format_string_ const char *fmt, - ...) PRINTF_DECL(3, 4); - -_Success_(return != -1) -int Str_Vsnprintf( - _Out_z_cap_(size) _Post_z_count_(return+1) char *str, - _In_ size_t size, - _In_z_ _Printf_format_string_ const char *format, - _In_ va_list ap) PRINTF_DECL(3, 0); - -_Success_(return != 0) -_When_(length != 0, _Ret_allocates_malloc_mem_opt_z_bytecount_(*length)) -_When_(length == 0, _Ret_allocates_malloc_mem_opt_z_) -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -char *Str_Vasprintf( - _Out_opt_ size_t *length, - _In_z_ _Printf_format_string_ const char *format, - _In_ va_list arguments) PRINTF_DECL(2, 0); - -_Success_(return != 0) -_When_(length != 0, _Ret_allocates_malloc_mem_opt_z_bytecount_(*length)) -_When_(length == 0, _Ret_allocates_malloc_mem_opt_z_) -_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) -char *Str_Asprintf( - _Out_opt_ size_t *length, - _In_z_ _Printf_format_string_ const char *format, - ...) PRINTF_DECL(2, 3); - -#ifdef _WIN32 -#pragma warning(push) -#pragma warning(disable: 28301) // Suppress complaint that first declaration lacked annotations -#endif - -// For now (vsphere-2015), we don't implement Panic, Warning, or Debug in the -// GDI case. -#if KRNL_STUBS_DRIVER_TYPE != KRNL_STUBS_DRIVER_TYPE_GDI - -/* - * Stub functions we provide. - */ -#ifdef _WIN32 -NORETURN -#endif -void Panic( - _In_z_ _Printf_format_string_ const char *fmt, - ...) PRINTF_DECL(1, 2); - -void Warning( - _In_z_ _Printf_format_string_ const char *fmt, - ...) PRINTF_DECL(1, 2); - -/* - * Functions the driver must implement for the stubs. - */ -EXTERN void Debug( - _In_z_ _Printf_format_string_ const char *fmt, - ...) PRINTF_DECL(1, 2); - -#endif // KRNL_STUBS_DRIVER_TYPE != KRNL_STUBS_DRIVER_TYPE_GDI - -#ifdef _WIN32 -#pragma warning(pop) -#endif - -#endif /* __KERNELSTUBS_H__ */ diff --git a/open-vm-tools/modules/linux/shared/kernelStubsLinux.c b/open-vm-tools/modules/linux/shared/kernelStubsLinux.c deleted file mode 100644 index e19faf7cf..000000000 --- a/open-vm-tools/modules/linux/shared/kernelStubsLinux.c +++ /dev/null @@ -1,460 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2014 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 - * - *********************************************************/ - -/* - * kernelStubsLinux.c - * - * This file contains implementations of common userspace functions in terms - * that the Linux kernel can understand. - */ - -/* Must come before any kernel header file */ -#include "driver-config.h" -#include "kernelStubs.h" -#include "compat_kernel.h" -#include "compat_page.h" -#include "compat_sched.h" -#include - -#include "vm_assert.h" - - -/* - *----------------------------------------------------------------------------- - * - * Panic -- - * - * Prints the debug message and stops the system. - * - * Results: - * None. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -void -Panic(const char *fmt, ...) // IN -{ - va_list args; - char *result; - - va_start(args, fmt); - result = Str_Vasprintf(NULL, fmt, args); - va_end(args); - - if (result) { - printk(KERN_EMERG "%s", result); - } - - BUG(); - - while (1); // Avoid compiler warning. -} - - -/* - *---------------------------------------------------------------------- - * - * Str_Strcpy-- - * - * Wrapper for strcpy that checks for buffer overruns. - * - * Results: - * Same as strcpy. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -Str_Strcpy(char *buf, // OUT - const char *src, // IN - size_t maxSize) // IN -{ - size_t len; - - len = strlen(src); - if (len >= maxSize) { -#ifdef GetReturnAddress - Panic("%s:%d Buffer too small 0x%p\n", __FILE__, __LINE__, GetReturnAddress()); -#else - Panic("%s:%d Buffer too small\n", __FILE__, __LINE__); -#endif - } - return memcpy(buf, src, len + 1); -} - - -/* - *---------------------------------------------------------------------- - * - * Str_Vsnprintf -- - * - * Compatability wrapper b/w different libc versions - * - * Results: - * int - number of bytes written (not including NULL terminate character), - * -1 on overflow (insufficient space for NULL terminate is considered - * overflow) - * - * NB: on overflow the buffer WILL be null terminated - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -Str_Vsnprintf(char *str, // OUT - size_t size, // IN - const char *format, // IN - va_list arguments) // IN -{ - int retval; - retval = vsnprintf(str, size, format, arguments); - - /* - * Linux glibc 2.0.x returns -1 and null terminates (which we shouldn't - * be linking against), but glibc 2.1.x follows c99 and returns - * characters that would have been written. - */ - if (retval >= size) { - return -1; - } - return retval; -} - - -/* - *----------------------------------------------------------------------------- - * - * Str_Vasprintf -- - * - * Allocate and format a string, using the GNU libc way to specify the - * format (i.e. optionally allow the use of positional parameters) - * - * Results: - * The allocated string on success (if 'length' is not NULL, *length - * is set to the length of the allocated string) - * NULL on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -char * -Str_Vasprintf(size_t *length, // OUT - const char *format, // IN - va_list arguments) // IN -{ - /* - * Simple implementation of Str_Vasprintf when userlevel libraries are not - * available (e.g. for use in drivers). We just fallback to vsnprintf, - * doubling if we didn't have enough space. - */ - unsigned int bufSize; - char *buf; - int retval; - - bufSize = strlen(format); - buf = NULL; - - do { - /* - * Initial allocation of strlen(format) * 2. Should this be tunable? - * XXX Yes, this could overflow and spin forever when you get near 2GB - * allocations. I don't care. --rrdharan - */ - va_list args2; - - bufSize *= 2; - buf = realloc(buf, bufSize); - - if (!buf) { - return NULL; - } - - va_copy(args2, arguments); - retval = Str_Vsnprintf(buf, bufSize, format, args2); - va_end(args2); - } while (retval == -1); - - if (length) { - *length = retval; - } - - /* - * Try to trim the buffer here to save memory? - */ - return buf; -} - - -/* - *----------------------------------------------------------------------------- - * - * Str_Asprintf -- - * - * Same as Str_Vasprintf(), but parameters are passed inline --hpreg - * - * Results: - * Same as Str_Vasprintf() - * - * Side effects: - * Same as Str_Vasprintf() - * - *----------------------------------------------------------------------------- - */ - -char * -Str_Asprintf(size_t *length, // OUT - const char *format, // IN - ...) // IN -{ - va_list arguments; - char *result; - - va_start(arguments, format); - result = Str_Vasprintf(length, format, arguments); - va_end(arguments); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * strdup -- - * - * Duplicates a string. - * - * Results: - * A pointer to memory containing the duplicated string or NULL if no - * memory was available. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -char * -strdup(const char *source) // IN -{ - char *target = NULL; - if (source) { - - /* - * We call our special implementation of malloc() because the users of - * strdup() will call free(), and that'll decrement the pointer before - * freeing it. Thus, we need to make sure that the allocated block - * also stores the block length before the block itself (see malloc() - * below). - */ - unsigned int len = strlen(source); - target = malloc(len + 1); - if (target) { - memcpy(target, source, len + 1); - } - } - - return target; -} - - -/* - *---------------------------------------------------------------------------- - * - * mallocReal -- - * - * Allocate memory using kmalloc. There is no realloc - * equivalent, so we roll our own by padding each allocation with - * 4 (or 8 for 64 bit guests) extra bytes to store the block length. - * - * Results: - * Pointer to driver heap memory, offset by 4 (or 8) - * bytes from the real block pointer. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void * -mallocReal(size_t size) // IN -{ - size_t *ptr; - ptr = kmalloc(size + sizeof size, GFP_KERNEL); - - if (ptr) { - *ptr++ = size; - } - return ptr; -} - - -/* - *---------------------------------------------------------------------------- - * - * malloc -- - * - * Allocate memory using the common mallocReal. - * - * Note: This calls mallocReal and not malloc as the gcc 5.1.1 optimizer - * will replace the malloc and memset with a calloc call. This results - * in calloc calling itself and results in system crashes. See bug 1413226. - * - * Results: - * Pointer to driver heap memory, offset by 4 (or 8) - * bytes from the real block pointer. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void * -malloc(size_t size) // IN -{ - return mallocReal(size); -} - -/* - *--------------------------------------------------------------------------- - * - * free -- - * - * Free memory allocated by a previous call to malloc, calloc or realloc. - * - * Results: - * None. - * - * Side effects: - * Calls kfree to free the real (base) pointer. - * - *--------------------------------------------------------------------------- - */ - -void -free(void *mem) // IN -{ - if (mem) { - size_t *dataPtr = (size_t *)mem; - kfree(--dataPtr); - } -} - - -/* - *---------------------------------------------------------------------------- - * - * calloc -- - * - * Malloc and zero. - * - * Note: This calls mallocReal and not malloc as the gcc 5.1.1 optimizer - * will replace the malloc and memset with a calloc call. This results - * for system crashes when used by kernel components. See bug 1413226. - * - * Results: - * Pointer to driver heap memory (see malloc, above). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void * -calloc(size_t num, // IN - size_t len) // IN -{ - size_t size; - void *ptr; - - size = num * len; - ptr = mallocReal(size); - if (ptr) { - memset(ptr, 0, size); - } - return ptr; -} - - -/* - *---------------------------------------------------------------------------- - * - * realloc -- - * - * Since the driver heap has no realloc equivalent, we have to roll our - * own. Fortunately, we can retrieve the block size of every block we - * hand out since we stashed it at allocation time (see malloc above). - * - * Results: - * Pointer to memory block valid for 'newSize' bytes, or NULL if - * allocation failed. - * - * Side effects: - * Could copy memory around. - * - *---------------------------------------------------------------------------- - */ - -void * -realloc(void* ptr, // IN - size_t newSize) // IN -{ - void *newPtr; - size_t *dataPtr; - size_t length, lenUsed; - - dataPtr = (size_t *)ptr; - length = ptr ? dataPtr[-1] : 0; - if (newSize == 0) { - if (ptr) { - free(ptr); - newPtr = NULL; - } else { - newPtr = malloc(newSize); - } - } else if (newSize == length) { - newPtr = ptr; - } else if ((newPtr = malloc(newSize))) { - if (length < newSize) { - lenUsed = length; - } else { - lenUsed = newSize; - } - memcpy(newPtr, ptr, lenUsed); - free(ptr); - } - return newPtr; -} - - diff --git a/open-vm-tools/modules/linux/shared/kernelStubsSal.h b/open-vm-tools/modules/linux/shared/kernelStubsSal.h deleted file mode 100644 index 7d2720950..000000000 --- a/open-vm-tools/modules/linux/shared/kernelStubsSal.h +++ /dev/null @@ -1,123 +0,0 @@ -/********************************************************* - * Copyright (C) 2015-2016 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 - * - *********************************************************/ - -/* - * kernelStubsSal.h - * - * Contains definitions source annotation language definitions for kernel drivers. - * This solves two issues: - * 1. Microsoft changed their annotation language from SAL 1.0 (original one - * widely distributed by the Windows team) to their more final SAL 2.0 - * langauge (championed by the VS team). - * 2. We want these annotations to do nothing during non-Win32 compiles. - * - * A longer term goal is to rationalize this into Bora. - */ -#ifndef __KERNELSTUBSSAL_H__ -#define __KERNELSTUBSSAL_H__ - -#if defined(_WIN32) -# include -# if !defined(_SAL_VERSION) -# define _SAL_VERSION 10 -# endif -#endif - -#if !defined(_SAL_VERSION) || (defined(_SAL_VERSION) && _SAL_VERSION == 10) -#define _In_ -#define _In_opt_ -#define _In_reads_bytes_(count) -#define _In_reads_bytes_opt_(count) -#define _In_z_ -#define _In_opt_z_ -#define _Out_ -#define _Out_opt_ -#define _Out_writes_bytes_(capcount) -#define _Out_writes_bytes_opt_(capcount) -#define _Out_writes_bytes_to_(cap, count) -#define _Out_writes_bytes_to_opt_(cap, count) -#define _Out_bytecap_post_bytecount_(cap, count) -#define _Out_writes_z_(cap) -#define _Out_writes_opt_z_(cap) -#define _Out_z_cap_(e) -#define _Outptr_result_buffer_(count) -#define _Outptr_result_bytebuffer_(count) -#define _Outptr_result_bytebuffer_maybenull_(count) -#define _Outptr_opt_result_buffer_(count) -#define _Outptr_opt_result_bytebuffer_(count) -#define _Outptr_opt_result_bytebuffer_maybenull_(count) -#define _COM_Outptr_ -#define _Inout_ -#define _Inout_updates_bytes_(e) -#define _Inout_z_cap_(e) -#define _Post_z_count_(e) -#define _Ret_writes_z_(e) -#define _Ret_writes_maybenull_z_(e) -#define _Ret_maybenull_ -#define _Ret_maybenull_z_ -#define _Ret_range_(l,h) -#define _Success_(expr) -#define _Check_return_ -#define _Must_inspect_result_ -#define _Group_(annos) -#define _When_(expr, annos) -#define _Always_(annos) -#define _Printf_format_string_ -#define _Use_decl_annotations_ -#define _Dispatch_type_(mj) -#define _Function_class_(c) -#define _Requires_lock_held_(cs) -#define _Requires_lock_not_held_(cs) -#define _Acquires_lock_(l) -#define _Releases_lock_(l) -#define _IRQL_requires_max_(i) -#define _IRQL_requires_(i) -#define _IRQL_requires_same_ -#define _Analysis_assume_(e) -#define _Pre_notnull_ -#define _At_(expr,annos) - -#else -// Sal 2.0 path - everything is already defined. -#endif // _SAL_VERSION - -// Now define our own annotations -#if !defined(_SAL_VERSION) || (defined(_SAL_VERSION) && _SAL_VERSION == 10) -#define _When_windrv_(annos) -#define _Ret_allocates_malloc_mem_opt_bytecap_(_Size) -#define _Ret_allocates_malloc_mem_opt_bytecount_(_Size) -#define _Ret_allocates_malloc_mem_opt_bytecap_post_bytecount_(_Cap,_Count) -#define _Ret_allocates_malloc_mem_opt_z_bytecount_(_Size) -#define _Ret_allocates_malloc_mem_opt_z_ -#define _In_frees_malloc_mem_opt_ -#else -#define _When_windrv_(annos) annos -#define _Ret_allocates_malloc_mem_opt_bytecap_(_Cap) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_bytecap_(_Cap) -#define _Ret_allocates_malloc_mem_opt_bytecount_(_Count) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_bytecount_(_Count) -#define _Ret_allocates_malloc_mem_opt_bytecap_post_bytecount_(_Cap,_Count) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_bytecap_(_Cap) _Ret_opt_bytecount_(_Count) -#define _Ret_allocates_malloc_mem_opt_z_bytecount_(_Count) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_z_bytecount_(_Count) -#define _Ret_allocates_malloc_mem_opt_z_ __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_z_ -#define _In_frees_malloc_mem_opt_ __drv_freesMem("Memory") _Pre_maybenull_ _Post_invalid_ -#endif // _SAL_VERSION - -// Best we can do for reallocate with simple annotations: assume old size was fully initialized. -#define _Ret_reallocates_malloc_mem_opt_newbytecap_oldbytecap_(_NewSize, _OldSize) _Ret_allocates_malloc_mem_opt_bytecap_post_bytecount_(_NewSize, _OldSize <= _NewSize ? _OldSize : _NewSize) -#define _Ret_reallocates_malloc_mem_opt_newbytecap_(_NewSize) _Ret_allocates_malloc_mem_opt_z_bytecount_(_NewSize) -#define _In_reallocates_malloc_mem_opt_oldptr_ _In_frees_malloc_mem_opt_ - -#endif // __KERNELSTUBSSAL_H__ diff --git a/open-vm-tools/modules/linux/shared/vmciKernelAPI.h b/open-vm-tools/modules/linux/shared/vmciKernelAPI.h deleted file mode 100644 index d03ac3ced..000000000 --- a/open-vm-tools/modules/linux/shared/vmciKernelAPI.h +++ /dev/null @@ -1,40 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciKernelAPI.h -- - * - * Kernel API (current) exported from the VMCI host and guest drivers. - */ - -#ifndef __VMCI_KERNELAPI_H__ -#define __VMCI_KERNELAPI_H__ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - - -/* With this file you always get the latest version. */ -#include "vmciKernelAPI1.h" -#include "vmciKernelAPI2.h" - - -#endif /* !__VMCI_KERNELAPI_H__ */ - diff --git a/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h b/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h deleted file mode 100644 index ae99af6c2..000000000 --- a/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h +++ /dev/null @@ -1,209 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciKernelAPI1.h -- - * - * Kernel API (v1) exported from the VMCI host and guest drivers. - */ - -#ifndef __VMCI_KERNELAPI_1_H__ -#define __VMCI_KERNELAPI_1_H__ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" -#include "vmci_call_defs.h" - -#if defined __cplusplus -extern "C" { -#endif - - -/* VMCI module namespace on vmkernel. */ - -#define MOD_VMCI_NAMESPACE "com.vmware.vmci" - -/* Define version 1. */ - -#undef VMCI_KERNEL_API_VERSION -#define VMCI_KERNEL_API_VERSION_1 1 -#define VMCI_KERNEL_API_VERSION VMCI_KERNEL_API_VERSION_1 - -/* Macros to operate on the driver version number. */ - -#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. */ - -#if defined(__linux__) && !defined(VMKERNEL) -#define vmci_device_get(_a, _b, _c, _d) 1 -#define vmci_device_release(_x) -#else // !linux -typedef void (VMCI_DeviceShutdownFn)(void *deviceRegistration, - void *userData); -Bool vmci_device_get(uint32 *apiVersion, - VMCI_DeviceShutdownFn *deviceShutdownCB, - void *userData, void **deviceRegistration); -void vmci_device_release(void *deviceRegistration); -#endif // !linux - -#if defined(_WIN32) -/* Called when the client is unloading, for Windows only. */ -void vmci_exit(void); -#endif // _WIN32 - -/* VMCI Datagram API. */ - -int vmci_datagram_create_handle(uint32 resourceId, uint32 flags, - VMCIDatagramRecvCB recvCB, void *clientData, - VMCIHandle *outHandle); -int vmci_datagram_create_handle_priv(uint32 resourceID, uint32 flags, - VMCIPrivilegeFlags privFlags, - VMCIDatagramRecvCB recvCB, - void *clientData, VMCIHandle *outHandle); -int vmci_datagram_destroy_handle(VMCIHandle handle); -int vmci_datagram_send(VMCIDatagram *msg); - -/* VMCI Utility API. */ - -VMCIId vmci_get_context_id(void); - -#if defined(__linux__) && !defined(VMKERNEL) -/* Returned value is a bool, 0 for false, 1 for true. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) -int vmci_is_context_owner(VMCIId contextID, kuid_t uid); -#else -int vmci_is_context_owner(VMCIId contextID, uid_t uid); -#endif -#else // !linux || VMKERNEL -/* Returned value is a VMCI error code. */ -int vmci_is_context_owner(VMCIId contextID, void *hostUser); -#endif // !linux || VMKERNEL - -uint32 vmci_version(void); -int vmci_cid_2_host_vm_id(VMCIId contextID, void *hostVmID, - size_t hostVmIDLen); - -/* VMCI Event API. */ - -typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed, - void *clientData); - -int vmci_event_subscribe(VMCI_Event event, -#if !defined(__linux__) || defined(VMKERNEL) - uint32 flags, -#endif // !linux || VMKERNEL - VMCI_EventCB callback, - void *callbackData, VMCIId *subID); -int vmci_event_unsubscribe(VMCIId subID); - -/* VMCI Context API */ - -VMCIPrivilegeFlags vmci_context_get_priv_flags(VMCIId contextID); - -/* VMCI Queue Pair API. */ - -typedef struct VMCIQPair VMCIQPair; - -int vmci_qpair_alloc(VMCIQPair **qpair, VMCIHandle *handle, - uint64 produceQSize, uint64 consumeQSize, VMCIId peer, - uint32 flags, VMCIPrivilegeFlags privFlags); -int vmci_qpair_detach(VMCIQPair **qpair); -int vmci_qpair_get_produce_indexes(const VMCIQPair *qpair, - uint64 *producerTail, uint64 *consumerHead); -int vmci_qpair_get_consume_indexes(const VMCIQPair *qpair, - uint64 *consumerTail, uint64 *producerHead); -int64 vmci_qpair_produce_free_space(const VMCIQPair *qpair); -int64 vmci_qpair_produce_buf_ready(const VMCIQPair *qpair); -int64 vmci_qpair_consume_free_space(const VMCIQPair *qpair); -int64 vmci_qpair_consume_buf_ready(const VMCIQPair *qpair); -ssize_t vmci_qpair_enqueue(VMCIQPair *qpair, const void *buf, size_t bufSize, - int mode); -ssize_t vmci_qpair_dequeue(VMCIQPair *qpair, void *buf, size_t bufSize, - int mode); -ssize_t vmci_qpair_peek(VMCIQPair *qpair, void *buf, size_t bufSize, int mode); - -#if (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ - (defined(__linux__) && defined(__KERNEL__)) || \ - (defined(_WIN32) && defined(WINNT_DDK)) -/* - * Environments that support struct iovec - */ - -ssize_t vmci_qpair_enquev(VMCIQPair *qpair, void *iov, size_t iovSize, - int mode); -ssize_t vmci_qpair_dequev(VMCIQPair *qpair, void *iov, size_t iovSize, - int mode); -ssize_t vmci_qpair_peekv(VMCIQPair *qpair, void *iov, size_t iovSize, - int mode); -#endif /* Systems that support struct iovec */ - - -/* Typedefs for all of the above, used by the IOCTLs and the kernel library. */ - -typedef void (VMCI_DeviceReleaseFct)(void *); -typedef int (VMCIDatagram_CreateHndFct)(VMCIId, uint32, VMCIDatagramRecvCB, - void *, VMCIHandle *); -typedef int (VMCIDatagram_CreateHndPrivFct)(VMCIId, uint32, VMCIPrivilegeFlags, - VMCIDatagramRecvCB, void *, - VMCIHandle *); -typedef int (VMCIDatagram_DestroyHndFct)(VMCIHandle); -typedef int (VMCIDatagram_SendFct)(VMCIDatagram *); -typedef VMCIId (VMCI_GetContextIDFct)(void); -typedef uint32 (VMCI_VersionFct)(void); -typedef int (VMCI_ContextID2HostVmIDFct)(VMCIId, void *, size_t); -typedef int (VMCI_IsContextOwnerFct)(VMCIId, void *); -typedef int (VMCIEvent_SubscribeFct)(VMCI_Event, uint32, VMCI_EventCB, void *, - VMCIId *); -typedef int (VMCIEvent_UnsubscribeFct)(VMCIId); -typedef VMCIPrivilegeFlags (VMCIContext_GetPrivFlagsFct)(VMCIId); -typedef int (VMCIQPair_AllocFct)(VMCIQPair **, VMCIHandle *, uint64, uint64, - VMCIId, uint32, VMCIPrivilegeFlags); -typedef int (VMCIQPair_DetachFct)(VMCIQPair **); -typedef int (VMCIQPair_GetProduceIndexesFct)(const VMCIQPair *, uint64 *, - uint64 *); -typedef int (VMCIQPair_GetConsumeIndexesFct)(const VMCIQPair *, uint64 *, - uint64 *); -typedef int64 (VMCIQPair_ProduceFreeSpaceFct)(const VMCIQPair *); -typedef int64 (VMCIQPair_ProduceBufReadyFct)(const VMCIQPair *); -typedef int64 (VMCIQPair_ConsumeFreeSpaceFct)(const VMCIQPair *); -typedef int64 (VMCIQPair_ConsumeBufReadyFct)(const VMCIQPair *); -typedef ssize_t (VMCIQPair_EnqueueFct)(VMCIQPair *, const void *, size_t, int); -typedef ssize_t (VMCIQPair_DequeueFct)(VMCIQPair *, void *, size_t, int); -typedef ssize_t (VMCIQPair_PeekFct)(VMCIQPair *, void *, size_t, int); -typedef ssize_t (VMCIQPair_EnqueueVFct)(VMCIQPair *qpair, void *, size_t, int); -typedef ssize_t (VMCIQPair_DequeueVFct)(VMCIQPair *qpair, void *, size_t, int); -typedef ssize_t (VMCIQPair_PeekVFct)(VMCIQPair *qpair, void *, size_t, int); - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif /* !__VMCI_KERNELAPI_1_H__ */ - diff --git a/open-vm-tools/modules/linux/shared/vmciKernelAPI2.h b/open-vm-tools/modules/linux/shared/vmciKernelAPI2.h deleted file mode 100644 index f0a7ec119..000000000 --- a/open-vm-tools/modules/linux/shared/vmciKernelAPI2.h +++ /dev/null @@ -1,71 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciKernelAPI2.h -- - * - * Kernel API (v2) exported from the VMCI host and guest drivers. - */ - -#ifndef __VMCI_KERNELAPI_2_H__ -#define __VMCI_KERNELAPI_2_H__ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmciKernelAPI1.h" - -#if defined __cplusplus -extern "C" { -#endif - - -/* Define version 2. */ - -#undef VMCI_KERNEL_API_VERSION -#define VMCI_KERNEL_API_VERSION_2 2 -#define VMCI_KERNEL_API_VERSION VMCI_KERNEL_API_VERSION_2 - - -/* VMCI Doorbell API. */ - -#define VMCI_FLAG_DELAYED_CB 0x01 - -typedef void (*VMCICallback)(void *clientData); - -int vmci_doorbell_create(VMCIHandle *handle, uint32 flags, - VMCIPrivilegeFlags privFlags, VMCICallback notifyCB, - void *clientData); -int vmci_doorbell_destroy(VMCIHandle handle); -int vmci_doorbell_notify(VMCIHandle handle, VMCIPrivilegeFlags privFlags); - -/* Typedefs for all of the above, used by the IOCTLs and the kernel library. */ - -typedef int (VMCIDoorbell_CreateFct)(VMCIHandle *, uint32, VMCIPrivilegeFlags, - VMCICallback, void *); -typedef int (VMCIDoorbell_DestroyFct)(VMCIHandle); -typedef int (VMCIDoorbell_NotifyFct)(VMCIHandle, VMCIPrivilegeFlags); - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif /* !__VMCI_KERNELAPI_2_H__ */ diff --git a/open-vm-tools/modules/linux/shared/vmci_call_defs.h b/open-vm-tools/modules/linux/shared/vmci_call_defs.h deleted file mode 100644 index db2496c3f..000000000 --- a/open-vm-tools/modules/linux/shared/vmci_call_defs.h +++ /dev/null @@ -1,323 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -#ifndef _VMCI_CALL_DEFS_H_ -#define _VMCI_CALL_DEFS_H_ - -#define INCLUDE_ALLOW_USERLEVEL - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKMOD -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#include "includeCheck.h" - -#include "vm_basic_types.h" -#include "vmci_defs.h" - -#if defined __cplusplus -extern "C" { -#endif - - -/* - * All structs here are an integral size of their largest member, ie. a struct - * with at least one 8-byte member will have a size that is an integral of 8. - * A struct which has a largest member of size 4 will have a size that is an - * integral of 4. This is because Windows CL enforces this rule. 32 bit gcc - * doesn't e.g. 32 bit gcc can misalign an 8 byte member if it is preceeded by - * a 4 byte member. - */ - -/* - * Base struct for vmci datagrams. - */ - -typedef struct VMCIDatagram { - VMCIHandle dst; - VMCIHandle src; - uint64 payloadSize; -} VMCIDatagram; - - -/* - * Second flag is for creating a well-known handle instead of a per context - * handle. Next flag is for deferring datagram delivery, so that the - * datagram callback is invoked in a delayed context (not interrupt context). - */ -#define VMCI_FLAG_DG_NONE 0 -#define VMCI_FLAG_WELLKNOWN_DG_HND 0x1 -#define VMCI_FLAG_ANYCID_DG_HND 0x2 -#define VMCI_FLAG_DG_DELAYED_CB 0x4 - -/* Event callback should fire in a delayed context (not interrupt context.) */ -#define VMCI_FLAG_EVENT_NONE 0 -#define VMCI_FLAG_EVENT_DELAYED_CB 0x1 - -/* - * Maximum supported size of a VMCI datagram for routable datagrams. - * Datagrams going to the hypervisor are allowed to be larger. - */ -#define VMCI_MAX_DG_SIZE (17 * 4096) -#define VMCI_MAX_DG_PAYLOAD_SIZE (VMCI_MAX_DG_SIZE - sizeof(VMCIDatagram)) -#define VMCI_DG_PAYLOAD(_dg) (void *)((char *)(_dg) + sizeof(VMCIDatagram)) -#define VMCI_DG_HEADERSIZE sizeof(VMCIDatagram) -#define VMCI_DG_SIZE(_dg) (VMCI_DG_HEADERSIZE + (size_t)(_dg)->payloadSize) -#define VMCI_DG_SIZE_ALIGNED(_dg) ((VMCI_DG_SIZE(_dg) + 7) & (size_t)~7) -#define VMCI_MAX_DATAGRAM_QUEUE_SIZE (VMCI_MAX_DG_SIZE * 2) - -/* - * We allow at least 1024 more event datagrams from the hypervisor past the - * normally allowed datagrams pending for a given context. We define this - * limit on event datagrams from the hypervisor to guard against DoS attack - * from a malicious VM which could repeatedly attach to and detach from a queue - * pair, causing events to be queued at the destination VM. However, the rate - * at which such events can be generated is small since it requires a VM exit - * and handling of queue pair attach/detach call at the hypervisor. Event - * datagrams may be queued up at the destination VM if it has interrupts - * disabled or if it is not draining events for some other reason. 1024 - * datagrams is a grossly conservative estimate of the time for which - * interrupts may be disabled in the destination VM, but at the same time does - * not exacerbate the memory pressure problem on the host by much (size of each - * event datagram is small). - */ -#define VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE \ - (VMCI_MAX_DATAGRAM_QUEUE_SIZE + \ - 1024 * (sizeof(VMCIDatagram) + sizeof(VMCIEventData_Max))) - -/* - * Struct for sending VMCI_DATAGRAM_REQUEST_MAP and - * VMCI_DATAGRAM_REMOVE_MAP datagrams. Struct size is 32 bytes. All - * fields in struct are aligned to their natural alignment. These - * datagrams are obsoleted by the removal of VM to VM communication. - */ -typedef struct VMCIDatagramWellKnownMapMsg { - VMCIDatagram hdr; - VMCIId wellKnownID; - uint32 _pad; -} VMCIDatagramWellKnownMapMsg; - - -/* - * Struct used for querying, via VMCI_RESOURCES_QUERY, the availability of - * hypervisor resources. - * Struct size is 16 bytes. All fields in struct are aligned to their natural - * alignment. - */ -typedef struct VMCIResourcesQueryHdr { - VMCIDatagram hdr; - uint32 numResources; - uint32 _padding; -} VMCIResourcesQueryHdr; - - -/* - * Convenience struct for negotiating vectors. Must match layout of - * VMCIResourceQueryHdr minus the VMCIDatagram header. - */ -typedef struct VMCIResourcesQueryMsg { - uint32 numResources; - uint32 _padding; - VMCI_Resource resources[1]; -} VMCIResourcesQueryMsg; - - -/* - * The maximum number of resources that can be queried using - * VMCI_RESOURCE_QUERY is 31, as the result is encoded in the lower 31 - * bits of a positive return value. Negative values are reserved for - * errors. - */ -#define VMCI_RESOURCE_QUERY_MAX_NUM 31 - -/* Maximum size for the VMCI_RESOURCE_QUERY request. */ -#define VMCI_RESOURCE_QUERY_MAX_SIZE sizeof(VMCIResourcesQueryHdr) \ - + VMCI_RESOURCE_QUERY_MAX_NUM * sizeof(VMCI_Resource) - -/* - * Struct used for setting the notification bitmap. All fields in - * struct are aligned to their natural alignment. - */ -typedef struct VMCINotifyBitmapSetMsg { - VMCIDatagram hdr; - PPN bitmapPPN; - uint32 _pad; -} VMCINotifyBitmapSetMsg; - - -/* - * Struct used for linking a doorbell handle with an index in the - * notify bitmap. All fields in struct are aligned to their natural - * alignment. - */ -typedef struct VMCIDoorbellLinkMsg { - VMCIDatagram hdr; - VMCIHandle handle; - uint64 notifyIdx; -} VMCIDoorbellLinkMsg; - - -/* - * Struct used for unlinking a doorbell handle from an index in the - * notify bitmap. All fields in struct are aligned to their natural - * alignment. - */ -typedef struct VMCIDoorbellUnlinkMsg { - VMCIDatagram hdr; - VMCIHandle handle; -} VMCIDoorbellUnlinkMsg; - - -/* - * Struct used for generating a notification on a doorbell handle. All - * fields in struct are aligned to their natural alignment. - */ -typedef struct VMCIDoorbellNotifyMsg { - VMCIDatagram hdr; - VMCIHandle handle; -} VMCIDoorbellNotifyMsg; - - -/* - * This struct is used to contain data for events. Size of this struct is a - * multiple of 8 bytes, and all fields are aligned to their natural alignment. - */ -typedef struct VMCI_EventData { - VMCI_Event event; /* 4 bytes. */ - uint32 _pad; - /* - * Event payload is put here. - */ -} VMCI_EventData; - - -/* Callback needed for correctly waiting on events. */ - -typedef int -(*VMCIDatagramRecvCB)(void *clientData, // IN: client data for handler - VMCIDatagram *msg); // IN: - - -/* - * We use the following inline function to access the payload data associated - * with an event data. - */ - -static INLINE void * -VMCIEventDataPayload(VMCI_EventData *evData) // IN: -{ - return (void *)((char *)evData + sizeof *evData); -} - -/* - * Define the different VMCI_EVENT payload data types here. All structs must - * be a multiple of 8 bytes, and fields must be aligned to their natural - * alignment. - */ -typedef struct VMCIEventPayload_Context { - VMCIId contextID; /* 4 bytes. */ - uint32 _pad; -} VMCIEventPayload_Context; - -typedef struct VMCIEventPayload_QP { - VMCIHandle handle; /* QueuePair handle. */ - VMCIId peerId; /* Context id of attaching/detaching VM. */ - uint32 _pad; -} VMCIEventPayload_QP; - -/* - * We define the following struct to get the size of the maximum event data - * the hypervisor may send to the guest. If adding a new event payload type - * above, add it to the following struct too (inside the union). - */ -typedef struct VMCIEventData_Max { - VMCI_EventData eventData; - union { - VMCIEventPayload_Context contextPayload; - VMCIEventPayload_QP qpPayload; - } evDataPayload; -} VMCIEventData_Max; - - -/* - * Struct used for VMCI_EVENT_SUBSCRIBE/UNSUBSCRIBE and VMCI_EVENT_HANDLER - * messages. Struct size is 32 bytes. All fields in struct are aligned to - * their natural alignment. - */ -typedef struct VMCIEventMsg { - VMCIDatagram hdr; - VMCI_EventData eventData; /* Has event type and payload. */ - /* - * Payload gets put here. - */ -} VMCIEventMsg; - - -/* - * We use the following inline function to access the payload data associated - * with an event message. - */ - -static INLINE void * -VMCIEventMsgPayload(VMCIEventMsg *eMsg) // IN: -{ - return VMCIEventDataPayload(&eMsg->eventData); -} - - -/* Flags for VMCI QueuePair API. */ -#define VMCI_QPFLAG_ATTACH_ONLY 0x1 /* Fail alloc if QP not created by peer. */ -#define VMCI_QPFLAG_LOCAL 0x2 /* Only allow attaches from local context. */ -#define VMCI_QPFLAG_NONBLOCK 0x4 /* Host won't block when guest is quiesced. */ -/* For asymmetric queuepairs, update as new flags are added. */ -#define VMCI_QP_ASYMM VMCI_QPFLAG_NONBLOCK -#define VMCI_QP_ASYMM_PEER (VMCI_QPFLAG_ATTACH_ONLY | VMCI_QP_ASYMM) -/* Update the following (bitwise OR flags) while adding new flags. */ -#define VMCI_QP_ALL_FLAGS (VMCI_QPFLAG_ATTACH_ONLY | VMCI_QPFLAG_LOCAL | \ - VMCI_QPFLAG_NONBLOCK) - -/* - * Structs used for QueuePair alloc and detach messages. We align fields of - * these structs to 64bit boundaries. - */ - -typedef struct VMCIQueuePairAllocMsg { - VMCIDatagram hdr; - VMCIHandle handle; - VMCIId peer; /* 32bit field. */ - uint32 flags; - uint64 produceSize; - uint64 consumeSize; - uint64 numPPNs; - /* List of PPNs placed here. */ -} VMCIQueuePairAllocMsg; - - -typedef struct VMCIQueuePairDetachMsg { - VMCIDatagram hdr; - VMCIHandle handle; -} VMCIQueuePairDetachMsg; - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // _VMCI_CALL_DEFS_H_ diff --git a/open-vm-tools/modules/linux/shared/vmci_defs.h b/open-vm-tools/modules/linux/shared/vmci_defs.h deleted file mode 100644 index e959e4ba1..000000000 --- a/open-vm-tools/modules/linux/shared/vmci_defs.h +++ /dev/null @@ -1,916 +0,0 @@ -/********************************************************* - * Copyright (C) 2005-2016 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 - * - *********************************************************/ - -#ifndef _VMCI_DEF_H_ -#define _VMCI_DEF_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMMEXT -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#include "includeCheck.h" - -#include "vm_basic_types.h" -#include "vm_basic_defs.h" -#include "vm_atomic.h" -#include "vm_assert.h" - -#if defined __cplusplus -extern "C" { -#endif - -/* Register offsets. */ -#define VMCI_STATUS_ADDR 0x00 -#define VMCI_CONTROL_ADDR 0x04 -#define VMCI_ICR_ADDR 0x08 -#define VMCI_IMR_ADDR 0x0c -#define VMCI_DATA_OUT_ADDR 0x10 -#define VMCI_DATA_IN_ADDR 0x14 -#define VMCI_CAPS_ADDR 0x18 -#define VMCI_RESULT_LOW_ADDR 0x1c -#define VMCI_RESULT_HIGH_ADDR 0x20 - -/* Max number of devices. */ -#define VMCI_MAX_DEVICES 1 - -/* Status register bits. */ -#define VMCI_STATUS_INT_ON 0x1 - -/* Control register bits. */ -#define VMCI_CONTROL_RESET 0x1 -#define VMCI_CONTROL_INT_ENABLE 0x2 -#define VMCI_CONTROL_INT_DISABLE 0x4 - -/* Capabilities register bits. */ -#define VMCI_CAPS_HYPERCALL 0x1 -#define VMCI_CAPS_GUESTCALL 0x2 -#define VMCI_CAPS_DATAGRAM 0x4 -#define VMCI_CAPS_NOTIFICATIONS 0x8 - -/* Interrupt Cause register bits. */ -#define VMCI_ICR_DATAGRAM 0x1 -#define VMCI_ICR_NOTIFICATION 0x2 - -/* Interrupt Mask register bits. */ -#define VMCI_IMR_DATAGRAM 0x1 -#define VMCI_IMR_NOTIFICATION 0x2 - -/* Interrupt type. */ -typedef enum VMCIIntrType { - VMCI_INTR_TYPE_INTX = 0, - VMCI_INTR_TYPE_MSI = 1, - VMCI_INTR_TYPE_MSIX = 2 -} VMCIIntrType; - -/* - * Maximum MSI/MSI-X interrupt vectors in the device. - */ -#define VMCI_MAX_INTRS 2 - -/* - * Supported interrupt vectors. There is one for each ICR value above, - * but here they indicate the position in the vector array/message ID. - */ -#define VMCI_INTR_DATAGRAM 0 -#define VMCI_INTR_NOTIFICATION 1 - - -/* - * A single VMCI device has an upper limit of 128 MiB on the amount of - * memory that can be used for queue pairs. - */ -#define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024) - -/* - * We have a fixed set of resource IDs available in the VMX. - * This allows us to have a very simple implementation since we statically - * know how many will create datagram handles. If a new caller arrives and - * we have run out of slots we can manually increment the maximum size of - * available resource IDs. - */ - -typedef uint32 VMCI_Resource; - -/* VMCI reserved hypervisor datagram resource IDs. */ -#define VMCI_RESOURCES_QUERY 0 -#define VMCI_GET_CONTEXT_ID 1 -#define VMCI_SET_NOTIFY_BITMAP 2 -#define VMCI_DOORBELL_LINK 3 -#define VMCI_DOORBELL_UNLINK 4 -#define VMCI_DOORBELL_NOTIFY 5 -/* - * VMCI_DATAGRAM_REQUEST_MAP and VMCI_DATAGRAM_REMOVE_MAP are - * obsoleted by the removal of VM to VM communication. - */ -#define VMCI_DATAGRAM_REQUEST_MAP 6 -#define VMCI_DATAGRAM_REMOVE_MAP 7 -#define VMCI_EVENT_SUBSCRIBE 8 -#define VMCI_EVENT_UNSUBSCRIBE 9 -#define VMCI_QUEUEPAIR_ALLOC 10 -#define VMCI_QUEUEPAIR_DETACH 11 -/* - * VMCI_VSOCK_VMX_LOOKUP was assigned to 12 for Fusion 3.0/3.1, - * WS 7.0/7.1 and ESX 4.1 - */ -#define VMCI_HGFS_TRANSPORT 13 -#define VMCI_UNITY_PBRPC_REGISTER 14 -/* - * This resource is used for VMCI socket control packets sent to the - * hypervisor (CID 0) because RID 1 is already reserved. - */ -#define VSOCK_PACKET_HYPERVISOR_RID 15 -#define VMCI_RESOURCE_MAX 16 -/* - * 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 { - int8 action; // VMCI_FA_X, for use in filters. - VMCIId begin; // Beginning of range - VMCIId end; // End of range -} VMCIIdRange; - -typedef struct VMCIHandle { - VMCIId context; - VMCIId resource; -} VMCIHandle; - -static INLINE VMCIHandle -VMCI_MAKE_HANDLE(VMCIId cid, // IN: - VMCIId rid) // IN: -{ - VMCIHandle h; - h.context = cid; - h.resource = rid; - return h; -} - -/* - *---------------------------------------------------------------------- - * - * VMCI_HANDLE_TO_UINT64 -- - * - * Helper for VMCI handle to uint64 conversion. - * - * Results: - * The uint64 value. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE uint64 -VMCI_HANDLE_TO_UINT64(VMCIHandle handle) // IN: -{ - uint64 handle64; - - handle64 = handle.context; - handle64 <<= 32; - handle64 |= handle.resource; - return handle64; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_UINT64_TO_HANDLE -- - * - * Helper for uint64 to VMCI handle conversion. - * - * Results: - * The VMCI handle value. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE VMCIHandle -VMCI_UINT64_TO_HANDLE(uint64 handle64) // IN: -{ - VMCIId context = (VMCIId)(handle64 >> 32); - VMCIId resource = (VMCIId)handle64; - - return VMCI_MAKE_HANDLE(context, resource); -} - -#define VMCI_HANDLE_TO_CONTEXT_ID(_handle) ((_handle).context) -#define VMCI_HANDLE_TO_RESOURCE_ID(_handle) ((_handle).resource) -#define VMCI_HANDLE_EQUAL(_h1, _h2) ((_h1).context == (_h2).context && \ - (_h1).resource == (_h2).resource) - -#define VMCI_INVALID_ID 0xFFFFFFFF -static const VMCIHandle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID, - VMCI_INVALID_ID}; - -#define VMCI_HANDLE_INVALID(_handle) \ - VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE) - -/* - * The below defines can be used to send anonymous requests. - * This also indicates that no response is expected. - */ -#define VMCI_ANON_SRC_CONTEXT_ID VMCI_INVALID_ID -#define VMCI_ANON_SRC_RESOURCE_ID VMCI_INVALID_ID -#define VMCI_ANON_SRC_HANDLE VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID, \ - VMCI_ANON_SRC_RESOURCE_ID) - -/* The lowest 16 context ids are reserved for internal use. */ -#define VMCI_RESERVED_CID_LIMIT 16 - -/* - * Hypervisor context id, used for calling into hypervisor - * supplied services from the VM. - */ -#define VMCI_HYPERVISOR_CONTEXT_ID 0 - -/* - * Well-known context id, a logical context that contains a set of - * well-known services. This context ID is now obsolete. - */ -#define VMCI_WELL_KNOWN_CONTEXT_ID 1 - -/* - * Context ID used by host endpoints. - */ -#define VMCI_HOST_CONTEXT_ID 2 -#define VMCI_HOST_CONTEXT_INVALID_EVENT ((uintptr_t)~0) - -#define VMCI_CONTEXT_IS_VM(_cid) (VMCI_INVALID_ID != _cid && \ - _cid > VMCI_HOST_CONTEXT_ID) - -/* - * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make - * handles that refer to a specific context. - */ -#define VMCI_CONTEXT_RESOURCE_ID 0 - - -/* - *----------------------------------------------------------------------------- - * - * VMCI error codes. - * - *----------------------------------------------------------------------------- - */ - -#define VMCI_SUCCESS_QUEUEPAIR_ATTACH 5 -#define VMCI_SUCCESS_QUEUEPAIR_CREATE 4 -#define VMCI_SUCCESS_LAST_DETACH 3 -#define VMCI_SUCCESS_ACCESS_GRANTED 2 -#define VMCI_SUCCESS_ENTRY_DEAD 1 -#define VMCI_SUCCESS 0LL -#define VMCI_ERROR_INVALID_RESOURCE (-1) -#define VMCI_ERROR_INVALID_ARGS (-2) -#define VMCI_ERROR_NO_MEM (-3) -#define VMCI_ERROR_DATAGRAM_FAILED (-4) -#define VMCI_ERROR_MORE_DATA (-5) -#define VMCI_ERROR_NO_MORE_DATAGRAMS (-6) -#define VMCI_ERROR_NO_ACCESS (-7) -#define VMCI_ERROR_NO_HANDLE (-8) -#define VMCI_ERROR_DUPLICATE_ENTRY (-9) -#define VMCI_ERROR_DST_UNREACHABLE (-10) -#define VMCI_ERROR_PAYLOAD_TOO_LARGE (-11) -#define VMCI_ERROR_INVALID_PRIV (-12) -#define VMCI_ERROR_GENERIC (-13) -#define VMCI_ERROR_PAGE_ALREADY_SHARED (-14) -#define VMCI_ERROR_CANNOT_SHARE_PAGE (-15) -#define VMCI_ERROR_CANNOT_UNSHARE_PAGE (-16) -#define VMCI_ERROR_NO_PROCESS (-17) -#define VMCI_ERROR_NO_DATAGRAM (-18) -#define VMCI_ERROR_NO_RESOURCES (-19) -#define VMCI_ERROR_UNAVAILABLE (-20) -#define VMCI_ERROR_NOT_FOUND (-21) -#define VMCI_ERROR_ALREADY_EXISTS (-22) -#define VMCI_ERROR_NOT_PAGE_ALIGNED (-23) -#define VMCI_ERROR_INVALID_SIZE (-24) -#define VMCI_ERROR_REGION_ALREADY_SHARED (-25) -#define VMCI_ERROR_TIMEOUT (-26) -#define VMCI_ERROR_DATAGRAM_INCOMPLETE (-27) -#define VMCI_ERROR_INCORRECT_IRQL (-28) -#define VMCI_ERROR_EVENT_UNKNOWN (-29) -#define VMCI_ERROR_OBSOLETE (-30) -#define VMCI_ERROR_QUEUEPAIR_MISMATCH (-31) -#define VMCI_ERROR_QUEUEPAIR_NOTSET (-32) -#define VMCI_ERROR_QUEUEPAIR_NOTOWNER (-33) -#define VMCI_ERROR_QUEUEPAIR_NOTATTACHED (-34) -#define VMCI_ERROR_QUEUEPAIR_NOSPACE (-35) -#define VMCI_ERROR_QUEUEPAIR_NODATA (-36) -#define VMCI_ERROR_BUSMEM_INVALIDATION (-37) -#define VMCI_ERROR_MODULE_NOT_LOADED (-38) -#define VMCI_ERROR_DEVICE_NOT_FOUND (-39) -#define VMCI_ERROR_QUEUEPAIR_NOT_READY (-40) -#define VMCI_ERROR_WOULD_BLOCK (-41) - -/* VMCI clients should return error code withing this range */ -#define VMCI_ERROR_CLIENT_MIN (-500) -#define VMCI_ERROR_CLIENT_MAX (-550) - -/* Internal error codes. */ -#define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000) - -#define VMCI_PATH_MAX 256 - -/* VMCI reserved events. */ -typedef uint32 VMCI_Event; - -#define VMCI_EVENT_CTX_ID_UPDATE 0 // Only applicable to guest endpoints -#define VMCI_EVENT_CTX_REMOVED 1 // Applicable to guest and host -#define VMCI_EVENT_QP_RESUMED 2 // Only applicable to guest endpoints -#define VMCI_EVENT_QP_PEER_ATTACH 3 // Applicable to guest, host and VMX -#define VMCI_EVENT_QP_PEER_DETACH 4 // Applicable to guest, host and VMX -#define VMCI_EVENT_MEM_ACCESS_ON 5 // Applicable to VMX and vmk. On vmk, - // this event has the Context payload type. -#define VMCI_EVENT_MEM_ACCESS_OFF 6 // Applicable to VMX and vmk. Same as - // above for the payload type. -#define VMCI_EVENT_GUEST_PAUSED 7 // Applicable to vmk. This event has the - // Context payload type. -#define VMCI_EVENT_GUEST_UNPAUSED 8 // Applicable to vmk. Same as above for - // the payload type. -#define VMCI_EVENT_MAX 9 - -/* - * Of the above events, a few are reserved for use in the VMX, and - * other endpoints (guest and host kernel) should not use them. For - * the rest of the events, we allow both host and guest endpoints to - * subscribe to them, to maintain the same API for host and guest - * endpoints. - */ - -#define VMCI_EVENT_VALID_VMX(_event) (_event == VMCI_EVENT_QP_PEER_ATTACH || \ - _event == VMCI_EVENT_QP_PEER_DETACH || \ - _event == VMCI_EVENT_MEM_ACCESS_ON || \ - _event == VMCI_EVENT_MEM_ACCESS_OFF) - -#if defined(VMX86_SERVER) -#define VMCI_EVENT_VALID(_event) (_event < VMCI_EVENT_MAX) -#else // VMX86_SERVER -#define VMCI_EVENT_VALID(_event) (_event < VMCI_EVENT_MAX && \ - _event != VMCI_EVENT_MEM_ACCESS_ON && \ - _event != VMCI_EVENT_MEM_ACCESS_OFF && \ - _event != VMCI_EVENT_GUEST_PAUSED && \ - _event != VMCI_EVENT_GUEST_UNPAUSED) -#endif // VMX86_SERVER - -/* Reserved guest datagram resource ids. */ -#define VMCI_EVENT_HANDLER 0 - -/* VMCI privileges. */ -typedef enum VMCIResourcePrivilegeType { - VMCI_PRIV_CH_PRIV, - VMCI_PRIV_DESTROY_RESOURCE, - VMCI_PRIV_ASSIGN_CLIENT, - VMCI_PRIV_DG_CREATE, - VMCI_PRIV_DG_SEND, - VMCI_PRIV_NOTIFY, - VMCI_NUM_PRIVILEGES, -} VMCIResourcePrivilegeType; - -/* - * VMCI coarse-grained privileges (per context or host - * process/endpoint. An entity with the restricted flag is only - * allowed to interact with the hypervisor and trusted entities. - */ -typedef uint32 VMCIPrivilegeFlags; - -#define VMCI_PRIVILEGE_FLAG_RESTRICTED 0x01 -#define VMCI_PRIVILEGE_FLAG_TRUSTED 0x02 -#define VMCI_PRIVILEGE_ALL_FLAGS (VMCI_PRIVILEGE_FLAG_RESTRICTED | \ - VMCI_PRIVILEGE_FLAG_TRUSTED) -#define VMCI_NO_PRIVILEGE_FLAGS 0x00 -#define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS VMCI_NO_PRIVILEGE_FLAGS -#define VMCI_LEAST_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_RESTRICTED -#define VMCI_MAX_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_TRUSTED - -#define VMCI_PUBLIC_GROUP_NAME "vmci public group" -/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */ -#define VMCI_RESERVED_RESOURCE_ID_MAX 1023 - -#define VMCI_DOMAIN_NAME_MAXLEN 32 - -#define VMCI_LGPFX "VMCI: " - - -/* - * VMCIQueueHeader - * - * A Queue cannot stand by itself as designed. Each Queue's header - * contains a pointer into itself (the producerTail) and into its peer - * (consumerHead). The reason for the separation is one of - * accessibility: Each end-point can modify two things: where the next - * location to enqueue is within its produceQ (producerTail); and - * where the next dequeue location is in its consumeQ (consumerHead). - * - * An end-point cannot modify the pointers of its peer (guest to - * guest; NOTE that in the host both queue headers are mapped r/w). - * But, each end-point needs read access to both Queue header - * structures in order to determine how much space is used (or left) - * in the Queue. This is because for an end-point to know how full - * its produceQ is, it needs to use the consumerHead that points into - * the produceQ but -that- consumerHead is in the Queue header for - * that end-points consumeQ. - * - * Thoroughly confused? Sorry. - * - * producerTail: the point to enqueue new entrants. When you approach - * a line in a store, for example, you walk up to the tail. - * - * consumerHead: the point in the queue from which the next element is - * dequeued. In other words, who is next in line is he who is at the - * head of the line. - * - * Also, producerTail points to an empty byte in the Queue, whereas - * consumerHead points to a valid byte of data (unless producerTail == - * consumerHead in which case consumerHead does not point to a valid - * byte of data). - * - * For a queue of buffer 'size' bytes, the tail and head pointers will be in - * the range [0, size-1]. - * - * If produceQHeader->producerTail == consumeQHeader->consumerHead - * then the produceQ is empty. - */ - -typedef struct VMCIQueueHeader { - /* All fields are 64bit and aligned. */ - VMCIHandle handle; /* Identifier. */ - Atomic_uint64 producerTail; /* Offset in this queue. */ - Atomic_uint64 consumerHead; /* Offset in peer queue. */ -} VMCIQueueHeader; - - -/* - * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair - * size to be less than 4GB, and use 32bit atomic operations on the head and - * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which - * is an atomic read-modify-write. This will cause traces to fire when a 32bit - * consumer tries to read the producer's tail pointer, for example, because the - * consumer has read-only access to the producer's tail pointer. - * - * We provide the following macros to invoke 32bit or 64bit atomic operations - * based on the architecture the code is being compiled on. - */ - -/* Architecture independent maximum queue size. */ -#define QP_MAX_QUEUE_SIZE_ARCH_ANY CONST64U(0xffffffff) - -#ifdef __x86_64__ -# define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffffffffffff) -# define QPAtomic_ReadOffset(x) Atomic_Read64(x) -# define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y) -#else - /* - * Wrappers below are being used to call Atomic_Read32 because of the - * 'type punned' compilation warning received when Atomic_Read32 is - * called with a Atomic_uint64 pointer typecasted to Atomic_uint32 - * pointer from QPAtomic_ReadOffset. Ditto with QPAtomic_WriteOffset. - */ - - static INLINE uint32 - TypeSafe_Atomic_Read32(void *var) // IN: - { - return Atomic_Read32((Atomic_uint32 *)(var)); - } - - static INLINE void - TypeSafe_Atomic_Write32(void *var, uint32 val) // IN: - { - Atomic_Write32((Atomic_uint32 *)(var), (uint32)(val)); - } - -# define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffff) -# define QPAtomic_ReadOffset(x) TypeSafe_Atomic_Read32((void *)(x)) -# define QPAtomic_WriteOffset(x, y) \ - TypeSafe_Atomic_Write32((void *)(x), (uint32)(y)) -#endif /* __x86_64__ */ - - -/* - *----------------------------------------------------------------------------- - * - * QPAddPointer -- - * - * Helper to add a given offset to a head or tail pointer. Wraps the value - * of the pointer around the max size of the queue. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -QPAddPointer(Atomic_uint64 *var, // IN: - size_t add, // IN: - uint64 size) // IN: -{ - uint64 newVal = QPAtomic_ReadOffset(var); - - if (newVal >= size - add) { - newVal -= size; - } - newVal += add; - - QPAtomic_WriteOffset(var, newVal); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_ProducerTail() -- - * - * Helper routine to get the Producer Tail from the supplied queue. - * - * Results: - * The contents of the queue's producer tail. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -VMCIQueueHeader_ProducerTail(const VMCIQueueHeader *qHeader) // IN: -{ - VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader; - return QPAtomic_ReadOffset(&qh->producerTail); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_ConsumerHead() -- - * - * Helper routine to get the Consumer Head from the supplied queue. - * - * Results: - * The contents of the queue's consumer tail. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE uint64 -VMCIQueueHeader_ConsumerHead(const VMCIQueueHeader *qHeader) // IN: -{ - VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader; - return QPAtomic_ReadOffset(&qh->consumerHead); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_AddProducerTail() -- - * - * Helper routine to increment the Producer Tail. Fundamentally, - * QPAddPointer() is used to manipulate the tail itself. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQueueHeader_AddProducerTail(VMCIQueueHeader *qHeader, // IN/OUT: - size_t add, // IN: - uint64 queueSize) // IN: -{ - QPAddPointer(&qHeader->producerTail, add, queueSize); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_AddConsumerHead() -- - * - * Helper routine to increment the Consumer Head. Fundamentally, - * QPAddPointer() is used to manipulate the head itself. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQueueHeader_AddConsumerHead(VMCIQueueHeader *qHeader, // IN/OUT: - size_t add, // IN: - uint64 queueSize) // IN: -{ - QPAddPointer(&qHeader->consumerHead, add, queueSize); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_CheckAlignment -- - * - * Checks if the given queue is aligned to page boundary. Returns TRUE if - * the alignment is good. - * - * Results: - * TRUE or FALSE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE Bool -VMCIQueueHeader_CheckAlignment(const VMCIQueueHeader *qHeader) // IN: -{ - uintptr_t hdr, offset; - - hdr = (uintptr_t) qHeader; - offset = hdr & (PAGE_SIZE -1); - - return offset == 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_GetPointers -- - * - * Helper routine for getting the head and the tail pointer for a queue. - * Both the VMCIQueues are needed to get both the pointers for one queue. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQueueHeader_GetPointers(const VMCIQueueHeader *produceQHeader, // IN: - const VMCIQueueHeader *consumeQHeader, // IN: - uint64 *producerTail, // OUT: - uint64 *consumerHead) // OUT: -{ - if (producerTail) { - *producerTail = VMCIQueueHeader_ProducerTail(produceQHeader); - } - - if (consumerHead) { - *consumerHead = VMCIQueueHeader_ConsumerHead(consumeQHeader); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_ResetPointers -- - * - * Reset the tail pointer (of "this" queue) and the head pointer (of - * "peer" queue). - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQueueHeader_ResetPointers(VMCIQueueHeader *qHeader) // IN/OUT: -{ - QPAtomic_WriteOffset(&qHeader->producerTail, CONST64U(0)); - QPAtomic_WriteOffset(&qHeader->consumerHead, CONST64U(0)); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_Init -- - * - * Initializes a queue's state (head & tail pointers). - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQueueHeader_Init(VMCIQueueHeader *qHeader, // IN/OUT: - const VMCIHandle handle) // IN: -{ - qHeader->handle = handle; - VMCIQueueHeader_ResetPointers(qHeader); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_FreeSpace -- - * - * Finds available free space in a produce queue to enqueue more - * data or reports an error if queue pair corruption is detected. - * - * Results: - * Free space size in bytes or an error code. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int64 -VMCIQueueHeader_FreeSpace(const VMCIQueueHeader *produceQHeader, // IN: - const VMCIQueueHeader *consumeQHeader, // IN: - const uint64 produceQSize) // IN: -{ - uint64 tail; - uint64 head; - uint64 freeSpace; - - tail = VMCIQueueHeader_ProducerTail(produceQHeader); - head = VMCIQueueHeader_ConsumerHead(consumeQHeader); - - if (tail >= produceQSize || head >= produceQSize) { - return VMCI_ERROR_INVALID_SIZE; - } - - /* - * Deduct 1 to avoid tail becoming equal to head which causes ambiguity. If - * head and tail are equal it means that the queue is empty. - */ - - if (tail >= head) { - freeSpace = produceQSize - (tail - head) - 1; - } else { - freeSpace = head - tail - 1; - } - - return freeSpace; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueHeader_BufReady -- - * - * VMCIQueueHeader_FreeSpace() does all the heavy lifting of - * determing the number of free bytes in a Queue. This routine, - * then subtracts that size from the full size of the Queue so - * the caller knows how many bytes are ready to be dequeued. - * - * Results: - * On success, available data size in bytes (up to MAX_INT64). - * On failure, appropriate error code. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int64 -VMCIQueueHeader_BufReady(const VMCIQueueHeader *consumeQHeader, // IN: - const VMCIQueueHeader *produceQHeader, // IN: - const uint64 consumeQSize) // IN: -{ - int64 freeSpace; - - freeSpace = VMCIQueueHeader_FreeSpace(consumeQHeader, - produceQHeader, - consumeQSize); - if (freeSpace < VMCI_SUCCESS) { - return freeSpace; - } else { - return consumeQSize - freeSpace - 1; - } -} - - -/* - * Defines for the VMCI traffic filter: - * - VMCI_FA_ defines the filter action values - * - 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_FA_INVALID -1 -#define VMCI_FA_ALLOW 0 -#define VMCI_FA_DENY (VMCI_FA_ALLOW + 1) -#define VMCI_FA_MAX (VMCI_FA_DENY + 1) - -#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_ANY (VMCI_FP_STREAMSOCK + 1) -#define VMCI_FP_MAX (VMCI_FP_ANY + 1) - -#define VMCI_FD_INVALID -1 -#define VMCI_FD_GUEST 0 -#define VMCI_FD_HOST (VMCI_FD_GUEST + 1) -#define VMCI_FD_ANY (VMCI_FD_HOST + 1) -#define VMCI_FD_MAX (VMCI_FD_ANY + 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 -} 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]; -typedef VMCIProtoFilters VMCIFilters[VMCI_FD_MAX]; - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // _VMCI_DEF_H_ diff --git a/open-vm-tools/modules/linux/shared/vmci_infrastructure.h b/open-vm-tools/modules/linux/shared/vmci_infrastructure.h deleted file mode 100644 index 2d3f28070..000000000 --- a/open-vm-tools/modules/linux/shared/vmci_infrastructure.h +++ /dev/null @@ -1,161 +0,0 @@ -/********************************************************* - * Copyright (C) 2006,2014 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_infrastructure.h -- - * - * This file implements the VMCI infrastructure. - */ - -#ifndef _VMCI_INFRASTRUCTURE_H_ -#define _VMCI_INFRASTRUCTURE_H_ - -#define INCLUDE_ALLOW_USERLEVEL - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#define INCLUDE_ALLOW_DISTRIBUTE -#include "includeCheck.h" - -#include "vmware.h" -#include "vmci_defs.h" - -#if defined __cplusplus -extern "C" { -#endif - - -typedef enum { - VMCIOBJ_VMX_VM = 10, - VMCIOBJ_CONTEXT, - VMCIOBJ_SOCKET, - VMCIOBJ_NOT_SET, -} VMCIObjType; - -/* For storing VMCI structures in file handles. */ -typedef struct VMCIObj { - void *ptr; - VMCIObjType type; -} VMCIObj; - -/* Guestcalls currently support a maximum of 8 uint64 arguments. */ -#define VMCI_GUESTCALL_MAX_ARGS_SIZE 64 - -/* - * Structure used for checkpointing the doorbell mappings. It is - * written to the checkpoint as is, so changing this structure will - * break checkpoint compatibility. - */ - -typedef struct VMCIDoorbellCptState { - VMCIHandle handle; - uint64 bitmapIdx; -} VMCIDoorbellCptState; - -/* Used to determine what checkpoint state to get and set. */ -#define VMCI_NOTIFICATION_CPT_STATE 0x1 -#define VMCI_WELLKNOWN_CPT_STATE 0x2 -#define VMCI_DG_OUT_STATE 0x3 -#define VMCI_DG_IN_STATE 0x4 -#define VMCI_DG_IN_SIZE_STATE 0x5 -#define VMCI_DOORBELL_CPT_STATE 0x6 -#define VMCI_DG_HYPERVISOR_SAVE_STATE_SIZE 0x7 -#define VMCI_DG_HYPERVISOR_SAVE_STATE 0x8 - -/* Used to control the VMCI device in the vmkernel */ -#define VMCI_DEV_RESET 0x01 -#define VMCI_DEV_QP_RESET 0x02 // DEPRECATED -#define VMCI_DEV_QUIESCE 0x03 -#define VMCI_DEV_UNQUIESCE 0x04 -#define VMCI_DEV_QP_BREAK_SHARING 0x05 // DEPRECATED -#define VMCI_DEV_RESTORE_SYNC 0x06 -#define VMCI_DEV_BMASTER_OFF 0x07 -#define VMCI_DEV_BMASTER_ON 0x08 - - -/* - *------------------------------------------------------------------------- - * - * VMCI_Hash -- - * - * Hash function used by the Simple Datagram API. Based on the djb2 - * hash function by Dan Bernstein. - * - * Result: - * Returns guest call size. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -static INLINE int -VMCI_Hash(VMCIHandle handle, // IN - unsigned size) // IN -{ - unsigned i; - int hash = 5381; - const uint64 handleValue = QWORD(handle.resource, handle.context); - - for (i = 0; i < sizeof handle; i++) { - hash = ((hash << 5) + hash) + (uint8)(handleValue >> (i * 8)); - } - return hash & (size - 1); -} - - -/* - *------------------------------------------------------------------------- - * - * VMCI_HashId -- - * - * Hash function used by the Simple Datagram API. Hashes only a VMCI id - * (not the full VMCI handle) Based on the djb2 - * hash function by Dan Bernstein. - * - * Result: - * Returns guest call size. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -static INLINE int -VMCI_HashId(VMCIId id, // IN - unsigned size) // IN -{ - unsigned i; - int hash = 5381; - - for (i = 0; i < sizeof id; i++) { - hash = ((hash << 5) + hash) + (uint8)(id >> (i * 8)); - } - return hash & (size - 1); -} - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // _VMCI_INFRASTRUCTURE_H_ diff --git a/open-vm-tools/modules/linux/shared/vmci_iocontrols.h b/open-vm-tools/modules/linux/shared/vmci_iocontrols.h deleted file mode 100644 index d5891a667..000000000 --- a/open-vm-tools/modules/linux/shared/vmci_iocontrols.h +++ /dev/null @@ -1,762 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2014 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_iocontrols.h - * - * The VMCI driver io controls. - */ - -#ifndef _VMCI_IOCONTROLS_H_ -#define _VMCI_IOCONTROLS_H_ - -#define INCLUDE_ALLOW_USERLEVEL -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vm_assert.h" -#include "vmci_defs.h" - -#if defined(_WIN32) && defined(WINNT_DDK) -/* We need to expose the API through an IOCTL on Windows. Use latest API. */ -#include "vmciKernelAPI.h" -#endif // _WIN32 && WINNT_DDK - -#if defined __cplusplus -extern "C" { -#endif - - -/* - *----------------------------------------------------------------------------- - * - * VMCIVA64ToPtr -- - * - * Convert a VA64 to a pointer. - * - * Results: - * Virtual address. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void * -VMCIVA64ToPtr(VA64 va64) // IN -{ -#ifdef VM_64BIT - ASSERT_ON_COMPILE(sizeof (void *) == 8); -#else - ASSERT_ON_COMPILE(sizeof (void *) == 4); - // Check that nothing of value will be lost. - ASSERT(!(va64 >> 32)); -#endif - return (void *)(uintptr_t)va64; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIPtrToVA64 -- - * - * Convert a pointer to a VA64. - * - * Results: - * Virtual address. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE VA64 -VMCIPtrToVA64(void const *ptr) // IN -{ - ASSERT_ON_COMPILE(sizeof ptr <= sizeof (VA64)); - return (VA64)(uintptr_t)ptr; -} - - -/* - * Driver version. - * - * Increment major version when you make an incompatible change. - * Compatibility goes both ways (old driver with new executable - * as well as new driver with old executable). - */ - -#define VMCI_VERSION_SHIFT_WIDTH 16 /* Never change this. */ -#define VMCI_MAKE_VERSION(_major, _minor) ((_major) << \ - VMCI_VERSION_SHIFT_WIDTH | \ - (uint16) (_minor)) -#define VMCI_VERSION_MAJOR(v) ((uint32) (v) >> VMCI_VERSION_SHIFT_WIDTH) -#define VMCI_VERSION_MINOR(v) ((uint16) (v)) - -/* - * VMCI_VERSION is always the current version. Subsequently listed - * versions are ways of detecting previous versions of the connecting - * application (i.e., VMX). - * - * VMCI_VERSION_NOVMVM: This version removed support for VM to VM - * communication. - * - * VMCI_VERSION_NOTIFY: This version introduced doorbell notification - * support. - * - * VMCI_VERSION_HOSTQP: This version introduced host end point support - * for hosted products. - * - * VMCI_VERSION_PREHOSTQP: This is the version prior to the adoption of - * support for host end-points. - * - * VMCI_VERSION_PREVERS2: This fictional version number is intended to - * represent the version of a VMX which doesn't call into the driver - * with ioctl VERSION2 and thus doesn't establish its version with the - * driver. - */ - -#define VMCI_VERSION VMCI_VERSION_NOVMVM -#define VMCI_VERSION_NOVMVM VMCI_MAKE_VERSION(11, 0) -#define VMCI_VERSION_NOTIFY VMCI_MAKE_VERSION(10, 0) -#define VMCI_VERSION_HOSTQP VMCI_MAKE_VERSION(9, 0) -#define VMCI_VERSION_PREHOSTQP VMCI_MAKE_VERSION(8, 0) -#define VMCI_VERSION_PREVERS2 VMCI_MAKE_VERSION(1, 0) - -/* - * VMCISockets driver version. The version is platform-dependent and is - * embedded in vsock_version.h for each platform. It can be obtained via - * VMCISock_Version() (which uses IOCTL_VMCI_SOCKETS_VERSION). The - * following is simply for constructing an unsigned integer value from the - * comma-separated version in the header. This must match the macros defined - * in vmci_sockets.h. An example of using this is: - * uint16 parts[4] = { VSOCK_DRIVER_VERSION_COMMAS }; - * uint32 version = VMCI_SOCKETS_MAKE_VERSION(parts); - */ - -#define VMCI_SOCKETS_MAKE_VERSION(_p) \ - ((((_p)[0] & 0xFF) << 24) | (((_p)[1] & 0xFF) << 16) | ((_p)[2])) - -#if defined(__linux__) || defined(VMKERNEL) -/* - * Linux defines _IO* macros, but the core kernel code ignore the encoded - * ioctl value. It is up to individual drivers to decode the value (for - * example to look at the size of a structure to determine which version - * of a specific command should be used) or not (which is what we - * currently do, so right now the ioctl value for a given command is the - * command itself). - * - * Hence, we just define the IOCTL_VMCI_foo values directly, with no - * intermediate IOCTLCMD_ representation. - */ -# define IOCTLCMD(_cmd) IOCTL_VMCI_ ## _cmd -#elif defined (__APPLE__) -#include -#define IOCTLCMD(_cmd) IOCTL_VMCI_ ## _cmd -#define IOCTLCMD_I(_cmd, _type) \ - IOCTL_VMCI_MACOS_ ## _cmd = _IOW('V', IOCTL_VMCI_ ## _cmd, _type) -#define IOCTLCMD_O(_cmd, _type) \ - IOCTL_VMCI_MACOS_ ## _cmd = _IOR('V', IOCTL_VMCI_ ## _cmd, _type) -#define IOCTLCMD_IO(_cmd, _type) \ - IOCTL_VMCI_MACOS_ ## _cmd = _IOWR('V', IOCTL_VMCI_ ## _cmd, _type) -#else // if defined(__linux__) -/* - * On platforms other than Linux, IOCTLCMD_foo values are just numbers, and - * we build the IOCTL_VMCI_foo values around these using platform-specific - * format for encoding arguments and sizes. - */ -# define IOCTLCMD(_cmd) IOCTLCMD_VMCI_ ## _cmd -#endif - - -enum IOCTLCmd_VMCI { - /* - * We need to bracket the range of values used for ioctls, because x86_64 - * Linux forces us to explicitly register ioctl handlers by value for - * handling 32 bit ioctl syscalls. Hence FIRST and LAST. Pick something - * for FIRST that doesn't collide with vmmon (2001+). - */ -#if defined(__linux__) - IOCTLCMD(FIRST) = 1951, -#else - /* Start at 0. */ - IOCTLCMD(FIRST), -#endif - IOCTLCMD(VERSION) = IOCTLCMD(FIRST), - - /* BEGIN VMCI */ - IOCTLCMD(INIT_CONTEXT), - - /* - * The following two were used for process and datagram process creation. - * They are not used anymore and reserved for future use. - * They will fail if issued. - */ - IOCTLCMD(RESERVED1), - IOCTLCMD(RESERVED2), - - /* - * The following used to be for shared memory. It is now unused and and is - * reserved for future use. It will fail if issued. - */ - IOCTLCMD(RESERVED3), - - /* - * The follwoing three were also used to be for shared memory. An - * old WS6 user-mode client might try to use them with the new - * driver, but since we ensure that only contexts created by VMX'en - * of the appropriate version (VMCI_VERSION_NOTIFY or - * VMCI_VERSION_NEWQP) or higher use these ioctl, everything is - * fine. - */ - IOCTLCMD(QUEUEPAIR_SETVA), - IOCTLCMD(NOTIFY_RESOURCE), - IOCTLCMD(NOTIFICATIONS_RECEIVE), - IOCTLCMD(VERSION2), - IOCTLCMD(QUEUEPAIR_ALLOC), - IOCTLCMD(QUEUEPAIR_SETPAGEFILE), - IOCTLCMD(QUEUEPAIR_DETACH), - IOCTLCMD(DATAGRAM_SEND), - IOCTLCMD(DATAGRAM_RECEIVE), - IOCTLCMD(DATAGRAM_REQUEST_MAP), - IOCTLCMD(DATAGRAM_REMOVE_MAP), - IOCTLCMD(CTX_ADD_NOTIFICATION), - IOCTLCMD(CTX_REMOVE_NOTIFICATION), - IOCTLCMD(CTX_GET_CPT_STATE), - IOCTLCMD(CTX_SET_CPT_STATE), - IOCTLCMD(GET_CONTEXT_ID), - /* END VMCI */ - - /* - * BEGIN VMCI SOCKETS - * - * We mark the end of the vmci commands and the start of the vmci sockets - * commands since they are used in separate modules on Linux. - * */ - IOCTLCMD(LAST), - IOCTLCMD(SOCKETS_FIRST) = IOCTLCMD(LAST), - - /* - * This used to be for accept() on Windows and Mac OS, which is now - * redundant (since we now use real handles). It is used instead for - * getting the version. This value is now public, so it cannot change. - */ - IOCTLCMD(SOCKETS_VERSION) = IOCTLCMD(SOCKETS_FIRST), - IOCTLCMD(SOCKETS_BIND), - - /* - * This used to be for close() on Windows and Mac OS, but is no longer - * used for the same reason as accept() above. It is used instead for - * sending private symbols to the Mac OS driver. - */ - IOCTLCMD(SOCKETS_SET_SYMBOLS), - IOCTLCMD(SOCKETS_CONNECT), - - /* - * The next two values are public (vmci_sockets.h) and cannot be changed. - * That means the number of values above these cannot be changed either - * unless the base index (specified below) is updated accordingly. - */ - IOCTLCMD(SOCKETS_GET_AF_VALUE), - IOCTLCMD(SOCKETS_GET_LOCAL_CID), - IOCTLCMD(SOCKETS_GET_SOCK_NAME), - IOCTLCMD(SOCKETS_GET_SOCK_OPT), - IOCTLCMD(SOCKETS_GET_VM_BY_NAME), - IOCTLCMD(SOCKETS_IOCTL), - IOCTLCMD(SOCKETS_LISTEN), - IOCTLCMD(SOCKETS_RECV), - IOCTLCMD(SOCKETS_RECV_FROM), - IOCTLCMD(SOCKETS_SELECT), - IOCTLCMD(SOCKETS_SEND), - IOCTLCMD(SOCKETS_SEND_TO), - IOCTLCMD(SOCKETS_SET_SOCK_OPT), - IOCTLCMD(SOCKETS_SHUTDOWN), - IOCTLCMD(SOCKETS_SOCKET), - IOCTLCMD(SOCKETS_UUID_2_CID), /* 1991 on Linux. */ - /* END VMCI SOCKETS */ - - /* - * We reserve a range of 3 ioctls for VMCI Sockets to grow. We cannot - * reserve many ioctls here since we are close to overlapping with vmmon - * ioctls. Define a meta-ioctl if running out of this binary space. - */ - // Must be last. - IOCTLCMD(SOCKETS_LAST) = IOCTLCMD(SOCKETS_UUID_2_CID) + 3, /* 1994 on Linux. */ - /* - * The VSockets ioctls occupy the block above. We define a new range of - * VMCI ioctls to maintain binary compatibility between the user land and - * the kernel driver. Careful, vmmon ioctls start from 2001, so this means - * we can add only 4 new VMCI ioctls. Define a meta-ioctl if running out of - * this binary space. - */ - - IOCTLCMD(FIRST2), - IOCTLCMD(SET_NOTIFY) = IOCTLCMD(FIRST2), /* 1995 on Linux. */ - IOCTLCMD(LAST2), -}; - -#if defined (__APPLE__) -/* - * The size of this must match the size of VSockIoctlPrivSyms in - * modules/vsock/common/vsockIoctl.h. - */ -#pragma pack(push, 1) -struct IOCTLCmd_VMCIMacOS_PrivSyms { - char data[344]; -}; -#pragma pack(pop) - -enum IOCTLCmd_VMCIMacOS { - IOCTLCMD_I(SOCKETS_SET_SYMBOLS, struct IOCTLCmd_VMCIMacOS_PrivSyms), - IOCTLCMD_O(SOCKETS_VERSION, unsigned int), - IOCTLCMD_O(SOCKETS_GET_AF_VALUE, int), - IOCTLCMD_O(SOCKETS_GET_LOCAL_CID, unsigned int), -}; -#endif // __APPLE__ - - -#if defined _WIN32 -/* - * Windows VMCI ioctl definitions. - */ - -/* PUBLIC: For VMCISockets user-mode clients that use CreateFile(). */ -#define VMCI_INTERFACE_VSOCK_PUBLIC_NAME TEXT("\\\\.\\VMCI") - -/* PUBLIC: For VMCISockets user-mode clients that use NtCreateFile(). */ -#define VMCI_INTERFACE_VSOCK_PUBLIC_NAME_NT L"\\??\\VMCI" - -/* PUBLIC: For the VMX, which uses CreateFile(). */ -#define VMCI_INTERFACE_VMX_PUBLIC_NAME TEXT("\\\\.\\VMCIDev\\VMX") - -/* PRIVATE NAMES */ -#define VMCI_DEVICE_VMCI_LINK_PATH L"\\DosDevices\\VMCIDev" -#define VMCI_DEVICE_VSOCK_LINK_PATH L"\\DosDevices\\vmci" -#define VMCI_DEVICE_HOST_NAME_PATH L"\\Device\\VMCIHostDev" -#define VMCI_DEVICE_GUEST_NAME_PATH L"\\Device\\VMCIGuestDev" -/* PRIVATE NAMES */ - -/* These values cannot be changed since some of the ioctl values are public. */ -#define FILE_DEVICE_VMCI 0x8103 -#define VMCI_IOCTL_BASE_INDEX 0x801 -#define VMCIIOCTL_BUFFERED(name) \ - CTL_CODE(FILE_DEVICE_VMCI, \ - VMCI_IOCTL_BASE_INDEX + IOCTLCMD_VMCI_ ## name, \ - METHOD_BUFFERED, \ - FILE_ANY_ACCESS) -#define VMCIIOCTL_NEITHER(name) \ - CTL_CODE(FILE_DEVICE_VMCI, \ - VMCI_IOCTL_BASE_INDEX + IOCTLCMD_VMCI_ ## name, \ - METHOD_NEITHER, \ - FILE_ANY_ACCESS) - -enum IOCTLCmd_VMCIWin32 { - IOCTLCMD(DEVICE_GET) = IOCTLCMD(LAST2) + 1, - IOCTLCMD(SOCKETS_SERVICE_GET), - IOCTLCMD(SOCKETS_STOP), -}; - -#define IOCTL_VMCI_VERSION VMCIIOCTL_BUFFERED(VERSION) - -/* BEGIN VMCI */ -#define IOCTL_VMCI_INIT_CONTEXT \ - VMCIIOCTL_BUFFERED(INIT_CONTEXT) -#define IOCTL_VMCI_HYPERCALL \ - VMCIIOCTL_BUFFERED(HYPERCALL) -#define IOCTL_VMCI_CREATE_DATAGRAM_HANDLE \ - VMCIIOCTL_BUFFERED(CREATE_DATAGRAM_HANDLE) -#define IOCTL_VMCI_DESTROY_DATAGRAM_HANDLE \ - VMCIIOCTL_BUFFERED(DESTROY_DATAGRAM_HANDLE) -#define IOCTL_VMCI_NOTIFY_RESOURCE \ - VMCIIOCTL_BUFFERED(NOTIFY_RESOURCE) -#define IOCTL_VMCI_NOTIFICATIONS_RECEIVE \ - VMCIIOCTL_BUFFERED(NOTIFICATIONS_RECEIVE) -#define IOCTL_VMCI_VERSION2 \ - VMCIIOCTL_BUFFERED(VERSION2) -#define IOCTL_VMCI_QUEUEPAIR_ALLOC \ - VMCIIOCTL_BUFFERED(QUEUEPAIR_ALLOC) -#define IOCTL_VMCI_QUEUEPAIR_SETVA \ - VMCIIOCTL_BUFFERED(QUEUEPAIR_SETVA) -#define IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE \ - VMCIIOCTL_BUFFERED(QUEUEPAIR_SETPAGEFILE) -#define IOCTL_VMCI_QUEUEPAIR_DETACH \ - VMCIIOCTL_BUFFERED(QUEUEPAIR_DETACH) -#define IOCTL_VMCI_DATAGRAM_SEND \ - VMCIIOCTL_BUFFERED(DATAGRAM_SEND) -#define IOCTL_VMCI_DATAGRAM_RECEIVE \ - VMCIIOCTL_NEITHER(DATAGRAM_RECEIVE) -#define IOCTL_VMCI_DATAGRAM_REQUEST_MAP \ - VMCIIOCTL_BUFFERED(DATAGRAM_REQUEST_MAP) -#define IOCTL_VMCI_DATAGRAM_REMOVE_MAP \ - VMCIIOCTL_BUFFERED(DATAGRAM_REMOVE_MAP) -#define IOCTL_VMCI_CTX_ADD_NOTIFICATION \ - VMCIIOCTL_BUFFERED(CTX_ADD_NOTIFICATION) -#define IOCTL_VMCI_CTX_REMOVE_NOTIFICATION \ - VMCIIOCTL_BUFFERED(CTX_REMOVE_NOTIFICATION) -#define IOCTL_VMCI_CTX_GET_CPT_STATE \ - VMCIIOCTL_BUFFERED(CTX_GET_CPT_STATE) -#define IOCTL_VMCI_CTX_SET_CPT_STATE \ - VMCIIOCTL_BUFFERED(CTX_SET_CPT_STATE) -#define IOCTL_VMCI_GET_CONTEXT_ID \ - VMCIIOCTL_BUFFERED(GET_CONTEXT_ID) -#define IOCTL_VMCI_DEVICE_GET \ - VMCIIOCTL_BUFFERED(DEVICE_GET) -/* END VMCI */ - -/* BEGIN VMCI SOCKETS */ -#define IOCTL_VMCI_SOCKETS_VERSION \ - VMCIIOCTL_BUFFERED(SOCKETS_VERSION) -#define IOCTL_VMCI_SOCKETS_BIND \ - VMCIIOCTL_BUFFERED(SOCKETS_BIND) -#define IOCTL_VMCI_SOCKETS_CONNECT \ - VMCIIOCTL_BUFFERED(SOCKETS_CONNECT) -#define IOCTL_VMCI_SOCKETS_GET_AF_VALUE \ - VMCIIOCTL_BUFFERED(SOCKETS_GET_AF_VALUE) -#define IOCTL_VMCI_SOCKETS_GET_LOCAL_CID \ - VMCIIOCTL_BUFFERED(SOCKETS_GET_LOCAL_CID) -#define IOCTL_VMCI_SOCKETS_GET_SOCK_NAME \ - VMCIIOCTL_BUFFERED(SOCKETS_GET_SOCK_NAME) -#define IOCTL_VMCI_SOCKETS_GET_SOCK_OPT \ - VMCIIOCTL_BUFFERED(SOCKETS_GET_SOCK_OPT) -#define IOCTL_VMCI_SOCKETS_GET_VM_BY_NAME \ - VMCIIOCTL_BUFFERED(SOCKETS_GET_VM_BY_NAME) -#define IOCTL_VMCI_SOCKETS_IOCTL \ - VMCIIOCTL_BUFFERED(SOCKETS_IOCTL) -#define IOCTL_VMCI_SOCKETS_LISTEN \ - VMCIIOCTL_BUFFERED(SOCKETS_LISTEN) -#define IOCTL_VMCI_SOCKETS_RECV_FROM \ - VMCIIOCTL_BUFFERED(SOCKETS_RECV_FROM) -#define IOCTL_VMCI_SOCKETS_SELECT \ - VMCIIOCTL_BUFFERED(SOCKETS_SELECT) -#define IOCTL_VMCI_SOCKETS_SEND_TO \ - VMCIIOCTL_BUFFERED(SOCKETS_SEND_TO) -#define IOCTL_VMCI_SOCKETS_SET_SOCK_OPT \ - VMCIIOCTL_BUFFERED(SOCKETS_SET_SOCK_OPT) -#define IOCTL_VMCI_SOCKETS_SHUTDOWN \ - VMCIIOCTL_BUFFERED(SOCKETS_SHUTDOWN) -#define IOCTL_VMCI_SOCKETS_SERVICE_GET \ - VMCIIOCTL_BUFFERED(SOCKETS_SERVICE_GET) -#define IOCTL_VMCI_SOCKETS_STOP \ - VMCIIOCTL_NEITHER(SOCKETS_STOP) -/* END VMCI SOCKETS */ - -#endif // _WIN32 - - -/* - * VMCI driver initialization. This block can also be used to - * pass initial group membership etc. - */ -typedef struct VMCIInitBlock { - VMCIId cid; - VMCIPrivilegeFlags flags; -#ifdef _WIN32 - uint64 event; /* Handle for signalling vmci calls on windows. */ -#endif // _WIN32 -} VMCIInitBlock; - -typedef struct VMCISharedMemInfo { - VMCIHandle handle; - uint32 size; - uint32 result; - VA64 va; /* Currently only used in the guest. */ - char pageFileName[VMCI_PATH_MAX]; -} VMCISharedMemInfo; - -typedef struct VMCIQueuePairAllocInfo_VMToVM { - VMCIHandle handle; - VMCIId peer; - uint32 flags; - uint64 produceSize; - uint64 consumeSize; -#if !defined(VMX86_SERVER) && !defined(VMKERNEL) - VA64 producePageFile; /* User VA. */ - VA64 consumePageFile; /* User VA. */ - uint64 producePageFileSize; /* Size of the file name array. */ - uint64 consumePageFileSize; /* Size of the file name array. */ -#else - PPN * PPNs; - uint64 numPPNs; -#endif - int32 result; - uint32 _pad; -} VMCIQueuePairAllocInfo_VMToVM; - -typedef struct VMCIQueuePairAllocInfo { - VMCIHandle handle; - VMCIId peer; - uint32 flags; - uint64 produceSize; - uint64 consumeSize; -#if !defined(VMX86_SERVER) && !defined(VMKERNEL) - VA64 ppnVA; /* Start VA of queue pair PPNs. */ -#else - PPN * PPNs; -#endif - uint64 numPPNs; - int32 result; - uint32 version; -} VMCIQueuePairAllocInfo; - -typedef struct VMCIQueuePairSetVAInfo { - VMCIHandle handle; - VA64 va; /* Start VA of queue pair PPNs. */ - uint64 numPPNs; - uint32 version; - int32 result; -} VMCIQueuePairSetVAInfo; - -/* - * For backwards compatibility, here is a version of the - * VMCIQueuePairPageFileInfo before host support end-points was added. - * Note that the current version of that structure requires VMX to - * pass down the VA of the mapped file. Before host support was added - * there was nothing of the sort. So, when the driver sees the ioctl - * with a parameter that is the sizeof - * VMCIQueuePairPageFileInfo_NoHostQP then it can infer that the version - * of VMX running can't attach to host end points because it doesn't - * provide the VA of the mapped files. - * - * The Linux driver doesn't get an indication of the size of the - * structure passed down from user space. So, to fix a long standing - * but unfiled bug, the _pad field has been renamed to version. - * Existing versions of VMX always initialize the PageFileInfo - * structure so that _pad, er, version is set to 0. - * - * A version value of 1 indicates that the size of the structure has - * been increased to include two UVA's: produceUVA and consumeUVA. - * These UVA's are of the mmap()'d queue contents backing files. - * - * In addition, if when VMX is sending down the - * VMCIQueuePairPageFileInfo structure it gets an error then it will - * try again with the _NoHostQP version of the file to see if an older - * VMCI kernel module is running. - */ -typedef struct VMCIQueuePairPageFileInfo_NoHostQP { - VMCIHandle handle; - VA64 producePageFile; /* User VA. */ - VA64 consumePageFile; /* User VA. */ - uint64 producePageFileSize; /* Size of the file name array. */ - uint64 consumePageFileSize; /* Size of the file name array. */ - int32 result; - uint32 version; /* Was _pad. Must be 0. */ -} VMCIQueuePairPageFileInfo_NoHostQP; - -typedef struct VMCIQueuePairPageFileInfo { - VMCIHandle handle; -#if !defined(VMX86_SERVER) && !defined(VMKERNEL) - VA64 producePageFile; /* User VA. */ - VA64 consumePageFile; /* User VA. */ - uint64 producePageFileSize; /* Size of the file name array. */ - uint64 consumePageFileSize; /* Size of the file name array. */ -#endif - int32 result; - uint32 version; /* Was _pad. */ - VA64 produceVA; /* User VA of the mapped file. */ - VA64 consumeVA; /* User VA of the mapped file. */ -} VMCIQueuePairPageFileInfo; - -typedef struct VMCIQueuePairDetachInfo { - VMCIHandle handle; - int32 result; - uint32 _pad; -} VMCIQueuePairDetachInfo; - -typedef struct VMCIDatagramSendRecvInfo { - VA64 addr; - uint32 len; - int32 result; -} VMCIDatagramSendRecvInfo; - -/* Used to add/remove well-known datagram mappings. */ -typedef struct VMCIDatagramMapInfo { - VMCIId wellKnownID; - int result; -} VMCIDatagramMapInfo; - -/* Used to add/remove remote context notifications. */ -typedef struct VMCINotifyAddRemoveInfo { - VMCIId remoteCID; - int result; -} VMCINotifyAddRemoveInfo; - -/* Used to set/get current context's checkpoint state. */ -typedef struct VMCICptBufInfo { - VA64 cptBuf; - uint32 cptType; - uint32 bufSize; - int32 result; - uint32 _pad; -} VMCICptBufInfo; - -/* Used to pass notify flag's address to the host driver. */ -typedef struct VMCISetNotifyInfo { - VA64 notifyUVA; - int32 result; - uint32 _pad; -} VMCISetNotifyInfo; - -#define VMCI_NOTIFY_RESOURCE_QUEUE_PAIR 0 -#define VMCI_NOTIFY_RESOURCE_DOOR_BELL 1 - -#define VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY 0 -#define VMCI_NOTIFY_RESOURCE_ACTION_CREATE 1 -#define VMCI_NOTIFY_RESOURCE_ACTION_DESTROY 2 - -/* - * Used to create and destroy doorbells, and generate a notification - * for a doorbell or queue pair. - */ - -typedef struct VMCINotifyResourceInfo { - VMCIHandle handle; - uint16 resource; - uint16 action; - int32 result; -} VMCINotifyResourceInfo; - -/* - * Used to recieve pending notifications for doorbells and queue - * pairs. - */ - -typedef struct VMCINotificationReceiveInfo { - VA64 dbHandleBufUVA; - uint64 dbHandleBufSize; - VA64 qpHandleBufUVA; - uint64 qpHandleBufSize; - int32 result; - uint32 _pad; -} VMCINotificationReceiveInfo; - -#if defined(_WIN32) && defined(WINNT_DDK) -/* - * Used on Windows to expose the API calls that are no longer exported. This - * is kernel-mode only, and both sides will have the same bitness, so we can - * use pointers directly. - */ - -/* Version 1. */ -typedef struct VMCIDeviceGetInfoVer1 { - VMCI_DeviceReleaseFct *deviceRelease; - VMCIDatagram_CreateHndFct *dgramCreateHnd; - VMCIDatagram_CreateHndPrivFct *dgramCreateHndPriv; - VMCIDatagram_DestroyHndFct *dgramDestroyHnd; - VMCIDatagram_SendFct *dgramSend; - VMCI_GetContextIDFct *getContextId; - VMCI_VersionFct *version; - VMCIEvent_SubscribeFct *eventSubscribe; - VMCIEvent_UnsubscribeFct *eventUnsubscribe; - VMCIQPair_AllocFct *qpairAlloc; - VMCIQPair_DetachFct *qpairDetach; - VMCIQPair_GetProduceIndexesFct *qpairGetProduceIndexes; - VMCIQPair_GetConsumeIndexesFct *qpairGetConsumeIndexes; - VMCIQPair_ProduceFreeSpaceFct *qpairProduceFreeSpace; - VMCIQPair_ProduceBufReadyFct *qpairProduceBufReady; - VMCIQPair_ConsumeFreeSpaceFct *qpairConsumeFreeSpace; - VMCIQPair_ConsumeBufReadyFct *qpairConsumeBufReady; - VMCIQPair_EnqueueFct *qpairEnqueue; - VMCIQPair_DequeueFct *qpairDequeue; - VMCIQPair_PeekFct *qpairPeek; - VMCIQPair_EnqueueVFct *qpairEnqueueV; - VMCIQPair_DequeueVFct *qpairDequeueV; - VMCIQPair_PeekVFct *qpairPeekV; - VMCI_ContextID2HostVmIDFct *contextID2HostVmID; - VMCI_IsContextOwnerFct *isContextOwner; - VMCIContext_GetPrivFlagsFct *contextGetPrivFlags; -} VMCIDeviceGetInfoVer1; - -/* Version 2. */ -typedef struct VMCIDeviceGetInfoVer2 { - VMCIDoorbell_CreateFct *doorbellCreate; - VMCIDoorbell_DestroyFct *doorbellDestroy; - VMCIDoorbell_NotifyFct *doorbellNotify; -} VMCIDeviceGetInfoVer2; - -typedef struct VMCIDeviceGetInfoHdr { - /* Requested API version on input, supported version on output. */ - uint32 apiVersion; - VMCI_DeviceShutdownFn *deviceShutdownCB; - void *userData; - void *deviceRegistration; -} VMCIDeviceGetInfoHdr; - -/* Combination of all versions. */ -typedef struct VMCIDeviceGetInfo { - VMCIDeviceGetInfoHdr hdr; - VMCIDeviceGetInfoVer1 ver1; - VMCIDeviceGetInfoVer2 ver2; -} VMCIDeviceGetInfo; -#endif // _WIN32 && WINNT_DDK - - -#ifdef __APPLE__ -/* - * Mac OS ioctl definitions. - * - * Mac OS defines _IO* macros, and the core kernel code uses the size encoded - * in the ioctl value to copy the memory back and forth (depending on the - * direction encoded in the ioctl value) between the user and kernel address - * spaces. - * See iocontrolsMacOS.h for details on how this is done. We use sockets only - * for vmci. - */ - -#include - -enum VMCrossTalkSockOpt { - VMCI_SO_VERSION = 0, - VMCI_SO_CONTEXT = IOCTL_VMCI_INIT_CONTEXT, - VMCI_SO_NOTIFY_RESOURCE = IOCTL_VMCI_NOTIFY_RESOURCE, - VMCI_SO_NOTIFICATIONS_RECEIVE = IOCTL_VMCI_NOTIFICATIONS_RECEIVE, - VMCI_SO_VERSION2 = IOCTL_VMCI_VERSION2, - VMCI_SO_QUEUEPAIR_ALLOC = IOCTL_VMCI_QUEUEPAIR_ALLOC, - VMCI_SO_QUEUEPAIR_SETVA = IOCTL_VMCI_QUEUEPAIR_SETVA, - VMCI_SO_QUEUEPAIR_SETPAGEFILE = IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE, - VMCI_SO_QUEUEPAIR_DETACH = IOCTL_VMCI_QUEUEPAIR_DETACH, - VMCI_SO_DATAGRAM_SEND = IOCTL_VMCI_DATAGRAM_SEND, - VMCI_SO_DATAGRAM_RECEIVE = IOCTL_VMCI_DATAGRAM_RECEIVE, - VMCI_SO_DATAGRAM_REQUEST_MAP = IOCTL_VMCI_DATAGRAM_REQUEST_MAP, - VMCI_SO_DATAGRAM_REMOVE_MAP = IOCTL_VMCI_DATAGRAM_REMOVE_MAP, - VMCI_SO_CTX_ADD_NOTIFICATION = IOCTL_VMCI_CTX_ADD_NOTIFICATION, - VMCI_SO_CTX_REMOVE_NOTIFICATION = IOCTL_VMCI_CTX_REMOVE_NOTIFICATION, - VMCI_SO_CTX_GET_CPT_STATE = IOCTL_VMCI_CTX_GET_CPT_STATE, - VMCI_SO_CTX_SET_CPT_STATE = IOCTL_VMCI_CTX_SET_CPT_STATE, - VMCI_SO_GET_CONTEXT_ID = IOCTL_VMCI_GET_CONTEXT_ID, - VMCI_SO_USERFD, -}; - -#define VMCI_MACOS_HOST_DEVICE "com.vmware.kext.vmci" - -#endif - -/* Clean up helper macros */ -#undef IOCTLCMD - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // ifndef _VMCI_IOCONTROLS_H_ diff --git a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h deleted file mode 100644 index ef9eb8297..000000000 --- a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h +++ /dev/null @@ -1,472 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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_kernel_if.h -- - * - * This file defines helper functions for VMCI host _and_ guest - * kernel code. It must work for Windows, Mac OS, vmkernel, Linux and - * Solaris kernels, i.e. using defines where necessary. - */ - -#ifndef _VMCI_KERNEL_IF_H_ -#define _VMCI_KERNEL_IF_H_ - -#if !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) && \ - !defined(VMKERNEL) -# error "Platform not supported." -#endif - -#if defined(_WIN32) -# include -#else -#define UNREFERENCED_PARAMETER(P) -#endif - -#if defined(__linux__) && !defined(VMKERNEL) -# include "driver-config.h" -# include "compat_cred.h" -# include "compat_module.h" -# include "compat_semaphore.h" -# include "compat_spinlock.h" -# include "compat_version.h" -# include -#endif // linux - -#ifdef __APPLE__ -# include -# include -# include -# include -#endif - -#ifdef VMKERNEL -# include "splock.h" -# include "splock_customRanks.h" -# include "semaphore_ext.h" -# include "vmkapi.h" -# include "world_dist.h" -#endif - -#include "vm_basic_types.h" -#include "vmci_defs.h" - -#if defined(VMKERNEL) -# include "list.h" -#else -# include "dbllnklst.h" -#endif - -#if defined __cplusplus -extern "C" { -#endif - - -/* Flags for specifying memory type. */ -#define VMCI_MEMORY_NORMAL 0x0 -#define VMCI_MEMORY_ATOMIC 0x1 -#define VMCI_MEMORY_NONPAGED 0x2 - -/* Platform specific type definitions. */ - -#if defined(VMKERNEL) -# define VMCI_EXPORT_SYMBOL(_SYMBOL) VMK_MODULE_EXPORT_SYMBOL(_SYMBOL); -#elif defined(__linux__) -# define VMCI_EXPORT_SYMBOL(_symbol) EXPORT_SYMBOL(_symbol); -#elif defined(__APPLE__) -# define VMCI_EXPORT_SYMBOL(_symbol) __attribute__((visibility("default"))) -#else -# define VMCI_EXPORT_SYMBOL(_symbol) -#endif - -#if defined(VMKERNEL) - typedef MCSLock VMCILock; - typedef SP_IRQL VMCILockFlags; - typedef Semaphore VMCIEvent; - typedef Semaphore VMCIMutex; - typedef World_ID VMCIHostVmID; - typedef uint32 VMCIHostUser; - typedef PPN *VMCIQPGuestMem; -#elif defined(__linux__) - typedef spinlock_t VMCILock; - typedef unsigned long VMCILockFlags; - typedef wait_queue_head_t VMCIEvent; - typedef struct semaphore VMCIMutex; - typedef PPN *VMCIPpnList; /* List of PPNs in produce/consume queue. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) - typedef kuid_t VMCIHostUser; -#else - typedef uid_t VMCIHostUser; -#endif - typedef VA64 VMCIQPGuestMem; -#elif defined(__APPLE__) - typedef IOLock *VMCILock; - typedef unsigned long VMCILockFlags; - typedef struct { - IOLock *lock; - DblLnkLst_Links waiters; - int buffered; - } VMCIEvent; - typedef IOLock *VMCIMutex; - typedef void *VMCIPpnList; /* Actually a pointer to the C++ Object IOMemoryDescriptor */ - typedef uid_t VMCIHostUser; - typedef VA64 *VMCIQPGuestMem; -#elif defined(_WIN32) - typedef KSPIN_LOCK VMCILock; - typedef KIRQL VMCILockFlags; - typedef KEVENT VMCIEvent; - typedef FAST_MUTEX VMCIMutex; - typedef PMDL VMCIPpnList; /* MDL to map the produce/consume queue. */ - typedef PSID VMCIHostUser; - typedef VA64 *VMCIQPGuestMem; -#endif // VMKERNEL - -/* Callback needed for correctly waiting on events. */ -typedef int (*VMCIEventReleaseCB)(void *clientData); - -/* - * Internal locking dependencies within VMCI: - * * CONTEXTFIRE < CONTEXT, CONTEXTLIST, EVENT, HASHTABLE - * * DOORBELL < HASHTABLE - * * QPHIBERNATE < EVENT - */ - -#ifdef VMKERNEL - typedef Lock_Rank VMCILockRank; - typedef SemaRank VMCISemaRank; - - #define VMCI_SEMA_RANK_QPHEADER (SEMA_RANK_FS - 1) - - #define VMCI_LOCK_RANK_MAX_NONBLOCK (MIN(SP_RANK_WAIT, \ - SP_RANK_HEAPLOCK_DYNAMIC) - 1) - #define VMCI_LOCK_RANK_MAX (SP_RANK_BLOCKABLE_HIGHEST_MAJOR - 2) - - /* - * Determines whether VMCI locks will be blockable or not. If blockable, - * all locks will be at or below VMCI_LOCK_RANK_MAX. If not, locks will - * instead use VMCI_LOCK_RANK_MAX_NONBLOCK as the maximum. The other - * VMCI_LOCK_RANK_XXX values will be rebased to be non-blocking as well - * in that case. - */ - extern Bool vmciBlockableLock; -#else - typedef unsigned long VMCILockRank; - typedef unsigned long VMCISemaRank; - - #define VMCI_LOCK_RANK_MAX 0x0fff - - #define VMCI_SEMA_RANK_QPHEADER 0x0fff -#endif // VMKERNEL -#define VMCI_LOCK_RANK_CONTEXT VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_CONTEXTLIST VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_DATAGRAMVMK VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_EVENT VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_HASHTABLE VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_RESOURCE VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_QPHEADER VMCI_LOCK_RANK_MAX -#define VMCI_LOCK_RANK_DOORBELL (VMCI_LOCK_RANK_HASHTABLE - 1) -#define VMCI_LOCK_RANK_CONTEXTFIRE (MIN(VMCI_LOCK_RANK_CONTEXT, \ - MIN(VMCI_LOCK_RANK_CONTEXTLIST, \ - MIN(VMCI_LOCK_RANK_EVENT, \ - VMCI_LOCK_RANK_HASHTABLE))) - 1) -#define VMCI_LOCK_RANK_QPHIBERNATE (VMCI_LOCK_RANK_EVENT - 1) -#define VMCI_LOCK_RANK_PACKET_QP (VMCI_LOCK_RANK_QPHEADER - 1) -//#define VMCI_LOCK_RANK_PACKET_QP 0xffd /* For vVol */ - -#define VMCI_SEMA_RANK_QUEUEPAIRLIST (VMCI_SEMA_RANK_QPHEADER - 1) -#define VMCI_SEMA_RANK_GUESTMEM (VMCI_SEMA_RANK_QUEUEPAIRLIST - 1) - -/* - * Host specific struct used for signalling. - */ - -typedef struct VMCIHost { -#if defined(VMKERNEL) - World_ID vmmWorldID[2]; /* - * First one is the active one and the second - * one is shadow world during FSR. - */ -#elif defined(__linux__) - wait_queue_head_t waitQueue; -#elif defined(__APPLE__) - struct Socket *socket; /* vmci Socket object on Mac OS. */ -#elif defined(_WIN32) - KEVENT *callEvent; /* Ptr to userlevel event used when signalling - * new pending guestcalls in kernel. - */ -#endif -} VMCIHost; - -/* - * Guest device port I/O. - */ - -#if defined(__linux__) - typedef unsigned short int VMCIIoPort; - typedef int VMCIIoHandle; -#elif defined(_WIN32) - typedef PUCHAR VMCIIoPort; - typedef int VMCIIoHandle; -#elif defined(__APPLE__) - typedef unsigned short int VMCIIoPort; - typedef void *VMCIIoHandle; -#endif // __APPLE__ - -void VMCI_ReadPortBytes(VMCIIoHandle handle, VMCIIoPort port, uint8 *buffer, - size_t bufferLength); - - -int VMCI_InitLock(VMCILock *lock, char *name, VMCILockRank rank); -void VMCI_CleanupLock(VMCILock *lock); -void VMCI_GrabLock(VMCILock *lock, VMCILockFlags *flags); -void VMCI_ReleaseLock(VMCILock *lock, VMCILockFlags flags); -void VMCI_GrabLock_BH(VMCILock *lock, VMCILockFlags *flags); -void VMCI_ReleaseLock_BH(VMCILock *lock, VMCILockFlags flags); - -void VMCIHost_InitContext(VMCIHost *hostContext, uintptr_t eventHnd); -void VMCIHost_ReleaseContext(VMCIHost *hostContext); -void VMCIHost_SignalCall(VMCIHost *hostContext); -void VMCIHost_ClearCall(VMCIHost *hostContext); -Bool VMCIHost_WaitForCallLocked(VMCIHost *hostContext, - VMCILock *lock, - VMCILockFlags *flags, - Bool useBH); -#ifdef VMKERNEL -int VMCIHost_ContextToHostVmID(VMCIHost *hostContext, VMCIHostVmID *hostVmID); -int VMCIHost_ContextHasUuid(VMCIHost *hostContext, const char *uuid); -void VMCIHost_SetActiveHnd(VMCIHost *hostContext, uintptr_t eventHnd); -Bool VMCIHost_RemoveHnd(VMCIHost *hostContext, uintptr_t eventHnd); -Bool VMCIHost_IsActiveHnd(VMCIHost *hostContext, uintptr_t eventHnd); -void VMCIHost_SetInactiveHnd(VMCIHost *hostContext, uintptr_t eventHnd); -uint32 VMCIHost_NumHnds(VMCIHost *hostContext); -uintptr_t VMCIHost_GetActiveHnd(VMCIHost *hostContext); -void VMCIHost_SignalBitmap(VMCIHost *hostContext); -void VMCIHost_SignalBitmapAlways(VMCIHost *hostContext); -void VMCIHost_SignalCallAlways(VMCIHost *hostContext); -#endif - -#if defined(_WIN32) - /* - * On Windows, Driver Verifier will panic() if we leak memory when we are - * unloaded. It dumps the leaked blocks for us along with callsites, which - * it handily tracks, but if we embed ExAllocate() inside a function, then - * the callsite is useless. So make this a macro on this platform only. - */ -# define VMCI_AllocKernelMem(_sz, _f) \ - ExAllocatePoolWithTag((((_f) & VMCI_MEMORY_NONPAGED) ? \ - NonPagedPool : PagedPool), \ - (_sz), 'MMTC') -#else // _WIN32 -void *VMCI_AllocKernelMem(size_t size, int flags); -#endif // _WIN32 -void VMCI_FreeKernelMem(void *ptr, size_t size); - -int VMCI_CopyToUser(VA64 dst, const void *src, size_t len); -Bool VMCIWellKnownID_AllowMap(VMCIId wellKnownID, - VMCIPrivilegeFlags privFlags); - -int VMCIHost_CompareUser(VMCIHostUser *user1, VMCIHostUser *user2); - -void VMCI_CreateEvent(VMCIEvent *event); -void VMCI_DestroyEvent(VMCIEvent *event); -void VMCI_SignalEvent(VMCIEvent *event); -void VMCI_WaitOnEvent(VMCIEvent *event, VMCIEventReleaseCB releaseCB, - void *clientData); -#if (defined(__APPLE__) || defined(__linux__) || defined(_WIN32)) && !defined(VMKERNEL) -Bool VMCI_WaitOnEventInterruptible(VMCIEvent *event, - VMCIEventReleaseCB releaseCB, - void *clientData); -#endif - -#if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \ - defined(__APPLE__)) -int VMCI_CopyFromUser(void *dst, VA64 src, size_t len); -#endif - -typedef void (VMCIWorkFn)(void *data); -Bool VMCI_CanScheduleDelayedWork(void); -int VMCI_ScheduleDelayedWork(VMCIWorkFn *workFn, void *data); - -int VMCIMutex_Init(VMCIMutex *mutex, char *name, VMCILockRank rank); -void VMCIMutex_Destroy(VMCIMutex *mutex); -void VMCIMutex_Acquire(VMCIMutex *mutex); -void VMCIMutex_Release(VMCIMutex *mutex); - -#if defined(_WIN32) || defined(__APPLE__) -int VMCIKernelIf_Init(void); -void VMCIKernelIf_Exit(void); -#if defined(_WIN32) -void VMCIKernelIf_DrainDelayedWork(void); -#endif // _WIN32 -#endif // _WIN32 || __APPLE__ - -#if !defined(VMKERNEL) && \ - (defined(__linux__) || defined(_WIN32) || defined(__APPLE__)) -void *VMCI_AllocQueue(uint64 size, uint32 flags); -void VMCI_FreeQueue(void *q, uint64 size); -typedef struct PPNSet { - uint64 numProducePages; - uint64 numConsumePages; - VMCIPpnList producePPNs; - VMCIPpnList consumePPNs; - Bool initialized; -} PPNSet; -int VMCI_AllocPPNSet(void *produceQ, uint64 numProducePages, void *consumeQ, - uint64 numConsumePages, PPNSet *ppnSet); -void VMCI_FreePPNSet(PPNSet *ppnSet); -int VMCI_PopulatePPNList(uint8 *callBuf, const PPNSet *ppnSet); -#endif - -struct VMCIQueue; - -struct PageStoreAttachInfo; -struct VMCIQueue *VMCIHost_AllocQueue(uint64 queueSize); -void VMCIHost_FreeQueue(struct VMCIQueue *queue, uint64 queueSize); - -#if defined(VMKERNEL) -typedef World_Handle *VMCIGuestMemID; -#define INVALID_VMCI_GUEST_MEM_ID NULL -#else -typedef uint32 VMCIGuestMemID; -#define INVALID_VMCI_GUEST_MEM_ID 0 -#endif - -#if defined(VMKERNEL) || defined(__linux__) || defined(_WIN32) || \ - defined(__APPLE__) - struct QueuePairPageStore; - int VMCIHost_RegisterUserMemory(struct QueuePairPageStore *pageStore, - struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - void VMCIHost_UnregisterUserMemory(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - int VMCIHost_MapQueues(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ, - uint32 flags); - int VMCIHost_UnmapQueues(VMCIGuestMemID gid, - struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - void VMCI_InitQueueMutex(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - void VMCI_CleanupQueueMutex(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - int VMCI_AcquireQueueMutex(struct VMCIQueue *queue, Bool canBlock); - void VMCI_ReleaseQueueMutex(struct VMCIQueue *queue); -#else // Below are the guest OS'es without host side support. -# define VMCI_InitQueueMutex(_pq, _cq) -# define VMCI_CleanupQueueMutex(_pq, _cq) do { } while (0) -# define VMCI_AcquireQueueMutex(_q, _cb) VMCI_SUCCESS -# define VMCI_ReleaseQueueMutex(_q) do { } while (0) -# define VMCIHost_RegisterUserMemory(_ps, _pq, _cq) VMCI_ERROR_UNAVAILABLE -# define VMCIHost_UnregisterUserMemory(_pq, _cq) do { } while (0) -# define VMCIHost_MapQueues(_pq, _cq, _f) VMCI_SUCCESS -# define VMCIHost_UnmapQueues(_gid, _pq, _cq) VMCI_SUCCESS -#endif - -#if defined(VMKERNEL) - void VMCIHost_MarkQueuesAvailable(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - void VMCIHost_MarkQueuesUnavailable(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - int VMCIHost_RevalidateQueues(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); -#else -# define VMCIHost_MarkQueuesAvailable(_q, _p) do { } while (0) -# define VMCIHost_MarkQueuesUnavailable(_q, _p) do { } while(0) -#endif - -#if defined(VMKERNEL) || defined(__linux__) - void VMCI_LockQueueHeader(struct VMCIQueue *queue); - void VMCI_UnlockQueueHeader(struct VMCIQueue *queue); -#else -# define VMCI_LockQueueHeader(_q) NOT_IMPLEMENTED() -# define VMCI_UnlockQueueHeader(_q) NOT_IMPLEMENTED() -#endif - -#if defined(VMKERNEL) - int VMCI_QueueHeaderUpdated(struct VMCIQueue *produceQ); -#else -# define VMCI_QueueHeaderUpdated(_q) VMCI_SUCCESS -#endif - -#if (!defined(VMKERNEL) && defined(__linux__)) || defined(_WIN32) || \ - defined(__APPLE__) - int VMCIHost_GetUserMemory(VA64 produceUVA, VA64 consumeUVA, - struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); - void VMCIHost_ReleaseUserMemory(struct VMCIQueue *produceQ, - struct VMCIQueue *consumeQ); -#else -# define VMCIHost_GetUserMemory(_puva, _cuva, _pq, _cq) VMCI_ERROR_UNAVAILABLE -# define VMCIHost_ReleaseUserMemory(_pq, _cq) NOT_IMPLEMENTED() -#endif - -#if defined(_WIN32) - Bool VMCI_EnqueueToDevNull(struct VMCIQueue *queue); - int VMCI_ConvertToLocalQueue(struct VMCIQueue *queueInfo, - struct VMCIQueue *otherQueueInfo, - uint64 size, Bool keepContent, - void **oldQueue); - void VMCI_RevertToNonLocalQueue(struct VMCIQueue *queueInfo, - void *nonLocalQueue, uint64 size); - void VMCI_FreeQueueBuffer(void *queue, uint64 size); - Bool VMCI_CanCreate(void); -#else // _WIN32 -# define VMCI_EnqueueToDevNull(_q) FALSE -# define VMCI_ConvertToLocalQueue(_pq, _cq, _s, _oq, _kc) VMCI_ERROR_UNAVAILABLE -# define VMCI_RevertToNonLocalQueue(_q, _nlq, _s) -# define VMCI_FreeQueueBuffer(_q, _s) -# define VMCI_CanCreate() TRUE -#endif // !_WIN32 -Bool VMCI_GuestPersonalityActive(void); -Bool VMCI_HostPersonalityActive(void); - - -#if defined(VMKERNEL) - typedef List_Links VMCIListItem; - typedef List_Links VMCIList; - -# define VMCIList_Init(_l) List_Init(_l) -# define VMCIList_InitEntry(_e) List_InitElement(_e) -# define VMCIList_Empty(_l) List_IsEmpty(_l) -# define VMCIList_Insert(_e, _l) List_Insert(_e, LIST_ATREAR(_l)) -# define VMCIList_Remove(_e) List_Remove(_e) -# define VMCIList_Scan(_cur, _l) LIST_FORALL(_l, _cur) -# define VMCIList_ScanSafe(_cur, _next, _l) LIST_FORALL_SAFE(_l, _cur, _next) -# define VMCIList_Entry(_elem, _type, _field) List_Entry(_elem, _type, _field) -# define VMCIList_First(_l) (VMCIList_Empty(_l)?NULL:List_First(_l)) -#else - typedef DblLnkLst_Links VMCIListItem; - typedef DblLnkLst_Links VMCIList; - -# define VMCIList_Init(_l) DblLnkLst_Init(_l) -# define VMCIList_InitEntry(_e) DblLnkLst_Init(_e) -# define VMCIList_Empty(_l) (!DblLnkLst_IsLinked(_l)) -# define VMCIList_Insert(_e, _l) DblLnkLst_LinkLast(_l, _e) -# define VMCIList_Remove(_e) DblLnkLst_Unlink1(_e) -# define VMCIList_Scan(_cur, _l) DblLnkLst_ForEach(_cur, _l) -# define VMCIList_ScanSafe(_cur, _next, _l) DblLnkLst_ForEachSafe(_cur, _next, _l) -# define VMCIList_Entry(_elem, _type, _field) DblLnkLst_Container(_elem, _type, _field) -# define VMCIList_First(_l) (VMCIList_Empty(_l)?NULL:(_l)->next) -#endif - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // _VMCI_KERNEL_IF_H_ diff --git a/open-vm-tools/modules/linux/vmblock/COPYING b/open-vm-tools/modules/linux/vmblock/COPYING deleted file mode 100644 index d511905c1..000000000 --- a/open-vm-tools/modules/linux/vmblock/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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; either version 2 of the License, or - (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/open-vm-tools/modules/linux/vmblock/Makefile b/open-vm-tools/modules/linux/vmblock/Makefile deleted file mode 100644 index 0a7cae6d8..000000000 --- a/open-vm-tools/modules/linux/vmblock/Makefile +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware kernel module Makefile to be distributed externally -#### - -#### -#### SRCROOT _must_ be a relative path. -#### -SRCROOT = . - -# -# open-vm-tools doesn't replicate shared source files for different modules; -# instead, files are kept in shared locations. So define a few useful macros -# to be able to handle both cases cleanly. -# -INCLUDE := -ifdef OVT_SOURCE_DIR -AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf -VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1) -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared -INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include -else -AUTOCONF_DIR := $(SRCROOT)/shared/autoconf -INCLUDE += -I$(SRCROOT)/shared -endif - - -VM_UNAME = $(shell uname -r) - -# Header directory for the running kernel -ifdef LINUXINCLUDE -HEADER_DIR = $(LINUXINCLUDE) -else -HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include -endif - -BUILD_DIR = $(HEADER_DIR)/.. - -DRIVER := vmblock -PRODUCT := tools-source - -# Grep program -GREP = /bin/grep - -vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) -vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi) - -ifndef VM_KBUILD -VM_KBUILD := no -ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes) -VM_KBUILD := yes -endif -export VM_KBUILD -endif - -ifndef VM_KBUILD_SHOWN -ifeq ($(VM_KBUILD), no) -VM_DUMMY := $(shell echo >&2 "Using standalone build system.") -else -VM_DUMMY := $(shell echo >&2 "Using kernel build system.") -endif -VM_KBUILD_SHOWN := yes -export VM_KBUILD_SHOWN -endif - -ifneq ($(VM_KBUILD), no) - -VMCCVER := $(shell $(CC) -dumpversion) - -# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles... -ifeq ($(VERSION),) - -DRIVER_KO := $(DRIVER).ko - -.PHONY: $(DRIVER_KO) - -auto-build: $(DRIVER_KO) - cp -f $< $(SRCROOT)/../$(DRIVER).o - -# $(DRIVER_KO) is a phony target, so compare file times explicitly -$(DRIVER): $(DRIVER_KO) - if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi - -# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler -VM_CCVER := $(VMCCVER) -export VM_CCVER -VM_CC := $(CC) -export VM_CC - -MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES)) - -# -# Define a setup target that gets built before the actual driver. -# This target may not be used at all, but if it is then it will be defined -# in Makefile.kernel -# -prebuild:: ; -postbuild:: ; - -$(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) modules - $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild -endif - -vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \ - $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \ - -DKBUILD_BASENAME=\"$(DRIVER)\" \ - -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -CC_WARNINGS := -Wall -Wstrict-prototypes -CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD -ifdef VMX86_DEVEL -CC_OPTS += -DVMX86_DEVEL -endif -ifdef VMX86_DEBUG -CC_OPTS += -DVMX86_DEBUG -endif - -include $(SRCROOT)/Makefile.kernel - -else - -include $(SRCROOT)/Makefile.normal - -endif - -#.SILENT: diff --git a/open-vm-tools/modules/linux/vmblock/Makefile.kernel b/open-vm-tools/modules/linux/vmblock/Makefile.kernel deleted file mode 100644 index ab7a7279b..000000000 --- a/open-vm-tools/modules/linux/vmblock/Makefile.kernel +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 2006 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 -# -########################################################## - -INCLUDE += -I$(SRCROOT)/include - -EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) - -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/cachecreate.c, -DVMW_KMEMCR_HAS_DTOR, ) -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, ) - -# Note: These tests are inverted. -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/getsb1.c, , -DVMW_GETSB_2618) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/statfs1.c, , -DVMW_STATFS_2618) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/filldir1.c, , -DVMW_FILLDIR_2618) - -obj-m += $(DRIVER).o - -$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, $(wildcard $(SRCROOT)/linux/*.c))) - -# -# In open-vm-tools, need to compile the common sources from the shared directories. -# -ifdef OVT_SOURCE_DIR -VMBLOCK_PATH := $(shell cd $(SRCROOT) && pwd) -VMBLOCK_SHARED_PATH := $(OVT_SOURCE_DIR)/modules/shared/vmblock - -VMBLOCK_SHARED := block.o -VMBLOCK_SHARED += stubs.o - -EXTRA_CFLAGS += -I$(VMBLOCK_PATH)/linux -EXTRA_CFLAGS += -I$(VMBLOCK_SHARED_PATH) - -$(addprefix $(VMBLOCK_PATH)/,$(VMBLOCK_SHARED)): $(VMBLOCK_PATH)/%.o: $(VMBLOCK_SHARED_PATH)/%.c - $(Q)$(rule_cc_o_c) - -$(DRIVER)-y += $(VMBLOCK_SHARED) -endif - -clean: - rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ - Module.symvers Modules.symvers Module.markers modules.order \ - $(foreach dir,./ linux/,$(addprefix $(dir),.*.cmd .*.o.flags *.o))) diff --git a/open-vm-tools/modules/linux/vmblock/README b/open-vm-tools/modules/linux/vmblock/README deleted file mode 100644 index fdb750f6d..000000000 --- a/open-vm-tools/modules/linux/vmblock/README +++ /dev/null @@ -1,17 +0,0 @@ -This files in this directory and its subdirectories are the kernel module -for the VMware Blocking File System. In order to build, make certain the -Makefile is correct and then just type - - make - -from this directory. A copy of the module will be left in - - driver-/vmblock.o - -(e.g. driver-up-2.4.20/vmblock.o) for 2.4 series kernels and in - - ../vmblock.o - -for 2.6 series kernels. - -If you have any problems or questions, send mail to support@vmware.com diff --git a/open-vm-tools/modules/linux/vmblock/linux/control.c b/open-vm-tools/modules/linux/vmblock/linux/control.c deleted file mode 100644 index 79716bd68..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/control.c +++ /dev/null @@ -1,375 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * control.c -- - * - * Control operations for the vmblock driver. - * - */ - -#include "driver-config.h" -#include -#include -#include -#include - -#include - -#include "vmblockInt.h" -#include "block.h" - - -/* procfs initialization/cleanup functions */ -static int SetupProcDevice(void); -static int CleanupProcDevice(void); - -/* procfs entry file operations */ -ssize_t ControlFileOpWrite(struct file *filp, const char __user *buf, - size_t cmd, loff_t *ppos); -static int ControlFileOpRelease(struct inode *inode, struct file *file); - - -static struct proc_dir_entry *controlProcDirEntry; -struct file_operations ControlFileOps = { - .owner = THIS_MODULE, - .write = ControlFileOpWrite, - .release = ControlFileOpRelease, -}; - - -/* Public initialization/cleanup routines */ - -/* - *---------------------------------------------------------------------------- - * - * VMBlockInitControlOps -- - * - * Sets up state for control operations. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMBlockInitControlOps(void) -{ - int ret; - - ret = BlockInit(); - if (ret < 0) { - Warning("VMBlockInitControlOps: could not initialize blocking ops.\n"); - return ret; - } - - ret = SetupProcDevice(); - if (ret < 0) { - Warning("VMBlockInitControlOps: could not setup proc device.\n"); - BlockCleanup(); - return ret; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VMBlockCleanupControlOps -- - * - * Cleans up state for control operations. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMBlockCleanupControlOps(void) -{ - int ret; - - ret = CleanupProcDevice(); - if (ret < 0) { - Warning("VMBlockCleanupControlOps: could not cleanup proc device.\n"); - return ret; - } - - BlockCleanup(); - return 0; -} - - -/* Private initialization/cleanup routines */ - - -/* - *---------------------------------------------------------------------------- - * - * VMBlockSetProcEntryOwner -- - * - * Sets proc_dir_entry owner if necessary: - * - * Before version 2.6.24 kernel prints nasty warning when in-use - * directory entry is destroyed, which happens when module is unloaded. - * We try to prevent this warning in most cases by setting owner to point - * to our module, so long operations (like current directory pointing to - * directory we created) prevent module from unloading. Since 2.6.24 this - * situation is handled without nastygrams, allowing module unload even - * when current directory points to directory created by unloaded module, - * so we do not have to set owner anymore. And since 2.6.29 we must not - * set owner at all, as there is none... - * - * Results: - * None. Always succeeds. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VMBlockSetProcEntryOwner(struct proc_dir_entry *entry) // IN/OUT: directory entry -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - entry->owner = THIS_MODULE; -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * SetupProcDevice -- - * - * Adds entries to /proc used to control file blocks. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -SetupProcDevice(void) -{ - struct proc_dir_entry *controlProcEntry; - struct proc_dir_entry *controlProcMountpoint; - - /* Create /proc/fs/vmblock */ - controlProcDirEntry = proc_mkdir(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); - if (!controlProcDirEntry) { - Warning("SetupProcDevice: could not create /proc/" - VMBLOCK_CONTROL_PROC_DIRNAME "\n"); - return -EINVAL; - } - - VMBlockSetProcEntryOwner(controlProcDirEntry); - - /* Create /proc/fs/vmblock/mountPoint */ - controlProcMountpoint = proc_mkdir(VMBLOCK_CONTROL_MOUNTPOINT, - controlProcDirEntry); - if (!controlProcMountpoint) { - Warning("SetupProcDevice: could not create " - VMBLOCK_MOUNT_POINT "\n"); - remove_proc_entry(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); - return -EINVAL; - } - - VMBlockSetProcEntryOwner(controlProcMountpoint); - - /* Create /proc/fs/vmblock/dev */ - controlProcEntry = create_proc_entry(VMBLOCK_CONTROL_DEVNAME, - VMBLOCK_CONTROL_MODE, - controlProcDirEntry); - if (!controlProcEntry) { - Warning("SetupProcDevice: could not create " VMBLOCK_DEVICE "\n"); - remove_proc_entry(VMBLOCK_CONTROL_MOUNTPOINT, controlProcDirEntry); - remove_proc_entry(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); - return -EINVAL; - } - - controlProcEntry->proc_fops = &ControlFileOps; - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * CleanupProcDevice -- - * - * Removes /proc entries for controlling file blocks. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -CleanupProcDevice(void) -{ - if (controlProcDirEntry) { - remove_proc_entry(VMBLOCK_CONTROL_MOUNTPOINT, controlProcDirEntry); - remove_proc_entry(VMBLOCK_CONTROL_DEVNAME, controlProcDirEntry); - remove_proc_entry(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); - } - return 0; -} - - -/* procfs file operations */ - - -/* - *---------------------------------------------------------------------------- - * - * ExecuteBlockOp -- - * - * Copy block name from user buffer into kernel space, canonicalize it - * by removing all trailing path separators, and execute desired block - * operation. - * - * Results: - * 0 on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -ExecuteBlockOp(const char __user *buf, // IN: buffer with name - const os_blocker_id_t blocker, // IN: blocker ID (file) - int (*blockOp)(const char *filename, // IN: block operation - const os_blocker_id_t blocker)) -{ - char *name; - int i; - int retval; - - name = getname(buf); - if (IS_ERR(name)) { - return PTR_ERR(name); - } - - for (i = strlen(name) - 1; i >= 0 && name[i] == '/'; i--) { - name[i] = '\0'; - } - - retval = i < 0 ? -EINVAL : blockOp(name, blocker); - - putname(name); - - return retval; -} - -/* - *---------------------------------------------------------------------------- - * - * ControlFileOpWrite -- - * - * write implementation for our control file. This accepts either add or - * delete commands and the buffer contains the file to block. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -ssize_t -ControlFileOpWrite(struct file *file, // IN: Opened file, used for ID - const char __user *buf, // IN: NUL-terminated filename - size_t cmd, // IN: VMBlock command (usually count) - loff_t *ppos) // IN/OUT: File offset (unused) -{ - int ret; - - switch (cmd) { - case VMBLOCK_ADD_FILEBLOCK: - ret = ExecuteBlockOp(buf, file, BlockAddFileBlock); - break; - - case VMBLOCK_DEL_FILEBLOCK: - ret = ExecuteBlockOp(buf, file, BlockRemoveFileBlock); - break; - -#ifdef VMX86_DEVEL - case VMBLOCK_LIST_FILEBLOCKS: - BlockListFileBlocks(); - ret = 0; - break; -#endif - - default: - Warning("ControlFileOpWrite: unrecognized command (%u) recieved\n", - (unsigned)cmd); - ret = -EINVAL; - break; - } - - return ret; -} - - -/* - *---------------------------------------------------------------------------- - * - * ControlFileOpRelease -- - * - * Called when the file is closed. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -ControlFileOpRelease(struct inode *inode, // IN - struct file *file) // IN -{ - BlockRemoveAllBlocks(file); - return 0; -} diff --git a/open-vm-tools/modules/linux/vmblock/linux/dentry.c b/open-vm-tools/modules/linux/vmblock/linux/dentry.c deleted file mode 100644 index 05ea95a9f..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/dentry.c +++ /dev/null @@ -1,118 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * dentry.c -- - * - * Dentry operations for the file system of the vmblock driver. - * - */ - -#include "driver-config.h" - -#include -#include "compat_namei.h" -#include "vmblockInt.h" -#include "filesystem.h" -#include "block.h" - - -static int DentryOpRevalidate(struct dentry *dentry, struct nameidata *nd); - -struct dentry_operations LinkDentryOps = { - .d_revalidate = DentryOpRevalidate, -}; - - -/* - *---------------------------------------------------------------------------- - * - * DentryOpRevalidate -- - * - * This function is invoked every time the dentry is accessed from the cache - * to ensure it is still valid. We use it to block since any threads - * looking up this dentry after the initial lookup should still block if the - * block has not been cleared. - * - * Results: - * 1 if the dentry is valid, 0 if it is not. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating - struct nameidata *nd) // IN: lookup flags & intent -{ - VMBlockInodeInfo *iinfo; - struct nameidata actualNd; - struct dentry *actualDentry; - int ret; - - if (!dentry) { - Warning("DentryOpRevalidate: invalid args from kernel\n"); - return 0; - } - - /* - * If a dentry does not have an inode associated with it then - * we are dealing with a negative dentry. Always invalidate a negative - * dentry which will cause a fresh lookup. - */ - if (!dentry->d_inode) { - return 0; - } - - - iinfo = INODE_TO_IINFO(dentry->d_inode); - if (!iinfo) { - Warning("DentryOpRevalidate: dentry has no fs-specific data\n"); - return 0; - } - - /* Block if there is a pending block on this file */ - BlockWaitOnFile(iinfo->name, NULL); - - /* - * If the actual dentry has a revalidate function, we'll let it figure out - * whether the dentry is still valid. If not, do a path lookup to ensure - * that the file still exists. - */ - actualDentry = iinfo->actualDentry; - - if (actualDentry && - actualDentry->d_op && - actualDentry->d_op->d_revalidate) { - return actualDentry->d_op->d_revalidate(actualDentry, nd); - } - - if (compat_path_lookup(iinfo->name, 0, &actualNd)) { - LOG(4, "DentryOpRevalidate: [%s] no longer exists\n", iinfo->name); - return 0; - } - ret = compat_vmw_nd_to_dentry(actualNd) && - compat_vmw_nd_to_dentry(actualNd)->d_inode; - compat_path_release(&actualNd); - - LOG(8, "DentryOpRevalidate: [%s] %s revalidated\n", - iinfo->name, ret ? "" : "not"); - return ret; -} diff --git a/open-vm-tools/modules/linux/vmblock/linux/file.c b/open-vm-tools/modules/linux/vmblock/linux/file.c deleted file mode 100644 index d7ac1f634..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/file.c +++ /dev/null @@ -1,244 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * file.c -- - * - * File operations for the file system of the vmblock driver. - * - */ - -#include "driver-config.h" -#include -#include -#include -#include - -#include "vmblockInt.h" -#include "filesystem.h" - -#if defined(VMW_FILLDIR_2618) -typedef u64 inode_num_t; -#else -typedef ino_t inode_num_t; -#endif - -/* Specifically for our filldir_t callback */ -typedef struct FilldirInfo { - filldir_t filldir; - void *dirent; -} FilldirInfo; - - -/* - *---------------------------------------------------------------------------- - * - * Filldir -- - * - * Callback function for readdir that we use in place of the one provided. - * This allows us to specify that each dentry is a symlink, but pass through - * everything else to the original filldir function. - * - * Results: - * Original filldir's return value. - * - * Side effects: - * Directory information gets copied to user's buffer. - * - *---------------------------------------------------------------------------- - */ - -static int -Filldir(void *buf, // IN: Dirent buffer passed from FileOpReaddir - const char *name, // IN: Dirent name - int namelen, // IN: len of dirent's name - loff_t offset, // IN: Offset - inode_num_t ino, // IN: Inode number of dirent - unsigned int d_type) // IN: Type of file -{ - FilldirInfo *info = buf; - - /* Specify DT_LNK regardless */ - return info->filldir(info->dirent, name, namelen, offset, ino, DT_LNK); -} - - -/* File operations */ - -/* - *---------------------------------------------------------------------------- - * - * FileOpOpen -- - * - * Invoked when open(2) has been called on our root inode. We get an open - * file instance of the actual file that we are providing indirect access - * to. - * - * Results: - * 0 on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -FileOpOpen(struct inode *inode, // IN - struct file *file) // IN -{ - VMBlockInodeInfo *iinfo; - struct file *actualFile; - - if (!inode || !file || !INODE_TO_IINFO(inode)) { - Warning("FileOpOpen: invalid args from kernel\n"); - return -EINVAL; - } - - iinfo = INODE_TO_IINFO(inode); - - /* - * Get an open file for the directory we are redirecting to. This ensure we - * can gracefully handle cases where that directory is removed after we are - * mounted. - */ - actualFile = filp_open(iinfo->name, file->f_flags, file->f_flags); - if (IS_ERR(actualFile)) { - Warning("FileOpOpen: could not open file [%s]\n", iinfo->name); - file->private_data = NULL; - return PTR_ERR(actualFile); - } - - /* - * If the file opened is the same as the one retrieved for the file then we - * shouldn't allow the open to happen. This can only occur if the - * redirected root directory specified at mount time is the same as where - * the mount is placed. Later in FileOpReaddir() we'd call vfs_readdir() - * and that would try to acquire the inode's semaphore; if the two inodes - * are the same we'll deadlock. - */ - if (actualFile->f_dentry && inode == actualFile->f_dentry->d_inode) { - Warning("FileOpOpen: identical inode encountered, open cannot succeed.\n"); - if (filp_close(actualFile, current->files) < 0) { - Warning("FileOpOpen: unable to close opened file.\n"); - } - return -EINVAL; - } - - file->private_data = actualFile; - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * FileOpReaddir -- - * - * Invoked when a user invokes getdents(2) or readdir(2) on the root of our - * file system. We perform a readdir on the actual underlying file but - * interpose the callback by providing our own Filldir() function. This - * enables us to change dentry types to symlinks. - * - * Results: - * 0 on success, negative error code on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -FileOpReaddir(struct file *file, // IN - void *dirent, // IN - filldir_t filldir) // IN -{ - int ret; - FilldirInfo info; - struct file *actualFile; - - if (!file) { - Warning("FileOpReaddir: invalid args from kernel\n"); - return -EINVAL; - } - - actualFile = file->private_data; - if (!actualFile) { - Warning("FileOpReaddir: no actual file found\n"); - return -EINVAL; - } - - info.filldir = filldir; - info.dirent = dirent; - - actualFile->f_pos = file->f_pos; - ret = vfs_readdir(actualFile, Filldir, &info); - file->f_pos = actualFile->f_pos; - - return ret; -} - - -/* - *---------------------------------------------------------------------------- - * - * FileOpRelease -- - * - * Invoked when a user close(2)s the root of our file system. Here we just - * close the actual file we opened in FileOpOpen(). - * - * Results: - * 0 on success, negative value on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -FileOpRelease(struct inode *inode, // IN - struct file *file) // IN -{ - int ret; - struct file *actualFile; - - if (!inode || !file) { - Warning("FileOpRelease: invalid args from kerel\n"); - return -EINVAL; - } - - actualFile = file->private_data; - if (!actualFile) { - Warning("FileOpRelease: no actual file found\n"); - return -EINVAL; - } - - ret = filp_close(actualFile, current->files); - - return ret; -} - - -struct file_operations RootFileOps = { - .readdir = FileOpReaddir, - .open = FileOpOpen, - .release = FileOpRelease, -}; - diff --git a/open-vm-tools/modules/linux/vmblock/linux/filesystem.c b/open-vm-tools/modules/linux/vmblock/linux/filesystem.c deleted file mode 100644 index af574995b..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/filesystem.c +++ /dev/null @@ -1,625 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * filesystem.c -- - * - * File system for the vmblock driver. - * - */ - -#include "driver-config.h" -#include -#include -#include -#include - -#include "compat_fs.h" -#include "compat_namei.h" - -#include "os.h" -#include "vmblockInt.h" -#include "filesystem.h" - -#define VMBLOCK_ROOT_INO 1 -#define GetRootInode(sb) Iget(sb, NULL, NULL, VMBLOCK_ROOT_INO) - -static struct inode *GetInode(struct super_block *sb, ino_t ino); - -/* File system operations */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) -static struct dentry *FsOpMount(struct file_system_type *fsType, int flags, - const char *devName, void *rawData); -#elif defined(VMW_GETSB_2618) -static int FsOpGetSb(struct file_system_type *fsType, int flags, - const char *devName, void *rawData, struct vfsmount *mnt); -#else -static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags, - const char *devName, void *rawData); -#endif -static int FsOpReadSuper(struct super_block *sb, void *rawData, int flags); - - -/* Utility */ -static compat_kmem_cache_ctor InodeCacheCtor; - - -/* Variables */ -compat_kmem_cache *VMBlockInodeCache; - -/* Local variables */ -static char const *fsRoot; -static size_t fsRootLen; -static struct file_system_type fsType = { - .owner = THIS_MODULE, - .name = VMBLOCK_FS_NAME, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) - .mount = FsOpMount, -#else - .get_sb = FsOpGetSb, -#endif - .kill_sb = kill_anon_super, -}; - - -/* - * Public functions (with respect to the module) - */ - -/* - *---------------------------------------------------------------------------- - * - * VMBlockInitFileSystem -- - * - * Initializes the file system and registers it with the kernel. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMBlockInitFileSystem(char const *root) // IN: directory redirecting to -{ - int ret; - - if (!root) { - Warning("VMBlockInitFileSystem: root not provided " - "(missing module parameter?)\n"); - return -EINVAL; - } - - /* - * Here we assume that the provided root is valid so the module will load. - * The mount operation will fail if that is not the case. - */ - fsRoot = root; - fsRootLen = strlen(fsRoot); - - if (fsRootLen >= PATH_MAX) { - return -ENAMETOOLONG; - } - - /* Initialize our inode slab allocator */ - VMBlockInodeCache = os_kmem_cache_create("VMBlockInodeCache", - sizeof (VMBlockInodeInfo), - 0, - InodeCacheCtor); - if (!VMBlockInodeCache) { - Warning("VMBlockInitFileSystem: could not initialize inode cache\n"); - return -ENOMEM; - } - - /* Tell the kernel about our file system */ - ret = register_filesystem(&fsType); - if (ret < 0) { - Warning("VMBlockInitFileSystem: could not initialize file system\n"); - kmem_cache_destroy(VMBlockInodeCache); - return ret; - } - - LOG(4, "file system registered with root of [%s]\n", fsRoot); - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VMBlockCleanupFileSystem -- - * - * Cleans up file system and unregisters it with the kernel. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMBlockCleanupFileSystem(void) -{ - int ret; - - ret = unregister_filesystem(&fsType); - if (ret < 0) { - Warning("VMBlockCleanupFileSystem: could not unregister file system\n"); - return ret; - } - - kmem_cache_destroy(VMBlockInodeCache); - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VMBlockReadInode -- - * - * A filesystem wide function that is called to initialize a new inode. - * This is called from two different places depending on the kernel version. - * In older kernels that provide the iget() interface, this function is - * called by the kernel as part of inode initialization (from - * SuperOpReadInode). In newer kernels that call iget_locked(), this - * function is called by filesystem code to initialize the new inode. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMBlockReadInode(struct inode *inode) // IN: Inode to initialize -{ - VMBlockInodeInfo *iinfo = INODE_TO_IINFO(inode); - - iinfo->name[0] = '\0'; - iinfo->nameLen = 0; - iinfo->actualDentry = NULL; -} - - -/* - *---------------------------------------------------------------------------- - * - * GetNextIno -- - * - * Gets the next available inode number. - * - * Results: - * The next available inode number. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -ino_t -GetNextIno(void) -{ - static atomic_t nextIno = ATOMIC_INIT(VMBLOCK_ROOT_INO + 1); - - return (ino_t) atomic_inc_return(&nextIno); -} - - -/* - *---------------------------------------------------------------------------- - * - * GetInode -- - * - * This function replaces iget() and should be called instead of it. In newer - * kernels that have removed the iget() interface, GetInode() obtains an inode - * and if it is a new one, then initializes the inode by calling - * VMBlockReadInode(). In older kernels that support the iget() interface, - * VMBlockReadInode() is called by iget() internally by the superblock function - * SuperOpReadInode. - * - * Results: - * A new inode object on success, NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static struct inode * -GetInode(struct super_block *sb, // IN: file system superblock object - ino_t ino) // IN: inode number to assign to new inode -{ - struct inode *inode; - - inode = iget_locked(sb, ino); - if (!inode) { - return NULL; - } else if (inode->i_state & I_NEW) { - VMBlockReadInode(inode); - unlock_new_inode(inode); - } - return inode; -} - - -/* - *---------------------------------------------------------------------------- - * - * Iget -- - * - * Lookup or create a new inode. - * - * Inode creation in detail: - * Throughout the file system, we call the VFS iget() function to get a new - * inode. This in turn invokes our file system's SuperOpAllocInode() - * function, which allocates an inode info structure (VMBlockInodeInfo) - * using the kernel's slab allocator. When a new slab is created, each - * object is initialized with the constructor (InodeCacheCtor()), but that - * occurs only once per struct (e.g., when a struct from a slab is freed and - * reused, the constructor is not invoked again). SuperOpAllocInode() then - * returns the address of the inode struct that is embedded within the inode - * info we have allocated. iget() also invokes our SuperOpReadInode() - * function to do any further file system wide initialization to the inode, - * then returns the inode to us (this function). - * - * Note that in older kernels that don't have the alloc_inode operation - * (where VMW_EMBED_INODE is undefined), the allocation is delayed until - * this function and is contained within the INODE_TO_IINFO macro. That - * allocation is freed in the SuperOpClearInode() function. - * - * This function then constructs the full path of the actual file name and - * does a path_lookup() to see if it exists. If it does, we save a pointer - * to the actual dentry within our inode info for future use. If it - * doesn't, we still provide an inode but indicate that it doesn't exist by - * setting the actual dentry to NULL. Callers that need to handle this case - * differently check for the existence of the actual dentry (and actual - * inode) to ensure the actual file exists. - * - * Results: - * A new inode object on success, NULL on error. - * - * Side effects: - * A path lookup is done for the actual file. - * - *---------------------------------------------------------------------------- - */ - -struct inode * -Iget(struct super_block *sb, // IN: file system superblock object - struct inode *dir, // IN: containing directory - struct dentry *dentry, // IN: dentry within directory - ino_t ino) // IN: inode number to assign to new inode -{ - VMBlockInodeInfo *iinfo; - struct inode *inode; - struct nameidata actualNd; - - ASSERT(sb); - - inode = GetInode(sb, ino); - if (!inode) { - return NULL; - } - - iinfo = INODE_TO_IINFO(inode); - if (!iinfo) { - Warning("Iget: invalid inode provided, or unable to allocate inode info\n"); - goto error_inode; - } - - /* Populate iinfo->name with the full path of the target file */ - if (MakeFullName(dir, dentry, iinfo->name, sizeof iinfo->name) < 0) { - Warning("Iget: could not make full name\n"); - goto error_inode; - } - - if (compat_path_lookup(iinfo->name, 0, &actualNd)) { - /* - * This file does not exist, so we create an inode that doesn't know - * about its underlying file. Operations that create files and - * directories need an inode to operate on even if there is no actual - * file yet. - */ - iinfo->actualDentry = NULL; - return inode; - } - - iinfo->actualDentry = compat_vmw_nd_to_dentry(actualNd); - compat_path_release(&actualNd); - - return inode; - -error_inode: - iput(inode); - return NULL; -} - - -/* - *---------------------------------------------------------------------------- - * - * InodeCacheCtor -- - * - * The constructor for inode info structs that occurs once at slab - * allocation. That is, this is called once for each piece of memory that - * is used to satisfy inode info allocations; it should only be used to - * initialized items that will naturally return to their initialized state - * before deallocation (such as locks, list_heads). - * - * We only invoke the inode's initialization routine since all of the inode - * info members need to be initialized on each allocation (in - * SuperOpReadInode()). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -InodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem)) // IN: allocated slab item to initialize -{ - VMBlockInodeInfo *iinfo = slabElem; - - inode_init_once(&iinfo->inode); -} - - -/* - *---------------------------------------------------------------------------- - * - * MakeFullName -- - * - * Constructs the full filename from the provided directory and a dentry - * contained within it. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -MakeFullName(struct inode *dir, // IN : directory - struct dentry *dentry, // IN : dentry in that directory - char *bufOut, // OUT: output buffer - size_t bufOutSize) // IN : size of output buffer -{ - ASSERT(bufOut); - - /* - * If dir is supplied, contruct the full path of the actual file, otherwise - * it's the root directory. - */ - if (dir == NULL) { - if (fsRootLen >= bufOutSize) { - Warning("MakeFullName: root path was too long.\n"); - return -ENAMETOOLONG; - } - memcpy(bufOut, fsRoot, fsRootLen); - bufOut[fsRootLen] = '\0'; - } else { - VMBlockInodeInfo *dirIinfo; - int ret; - - ASSERT(dir); - ASSERT(dentry); - - if (!dentry->d_name.name) { - Warning("MakeFullName: dentry name is empty\n"); - return -EINVAL; - } - - dirIinfo = INODE_TO_IINFO(dir); - - /* - * If dirIinfo->name[1] is '\0', then it is "/" and we don't need - * another '/' between it and the additional name. - */ - ret = snprintf(bufOut, bufOutSize, - dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s", - dirIinfo->name, dentry->d_name.name); - if (ret >= bufOutSize) { - Warning("MakeFullName: path was too long.\n"); - return -ENAMETOOLONG; - } - } - - return 0; -} - - -/* File system operations */ - -/* - *----------------------------------------------------------------------------- - * - * FsOpReadSuper -- - * - * The main entry point of the filesystem side of the driver. Called when - * a userland process does a mount(2) of an hgfs filesystem. This makes the - * whole driver transition from its initial state to state 1. Fill the - * content of the uninitialized superblock provided by the kernel. - * - * 'rawData' is a pointer (that can be NULL) to a kernel buffer (whose - * size is <= PAGE_SIZE) that corresponds to the filesystem-specific 'data' - * argument passed to mount(2). - * - * Results: - * zero and initialized superblock on success - * negative value on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -FsOpReadSuper(struct super_block *sb, // OUT: Superblock object - void *rawData, // IN: Fs-specific mount data - int flags) // IN: Mount flags -{ - struct inode *rootInode; - struct dentry *rootDentry; - - if (!sb) { - Warning("FsOpReadSuper: invalid arg from kernel\n"); - return -EINVAL; - } - - sb->s_magic = VMBLOCK_SUPER_MAGIC; - sb->s_blocksize = 1024; - sb->s_op = &VMBlockSuperOps; - - /* - * Make root inode and dentry. Ensure that the directory we are redirecting - * to has an actual dentry and inode, and that it is in fact a directory. - */ - rootInode = GetRootInode(sb); - if (!rootInode) { - return -EINVAL; - } - - if (!INODE_TO_IINFO(rootInode) || - !INODE_TO_ACTUALDENTRY(rootInode) || - !INODE_TO_ACTUALINODE(rootInode) || - !S_ISDIR(INODE_TO_ACTUALINODE(rootInode)->i_mode)) { - iput(rootInode); - return -EINVAL; - } - - rootDentry = d_make_root(rootInode); - if (!rootDentry) { - return -ENOMEM; - } - sb->s_root = rootDentry; - - rootInode->i_op = &RootInodeOps; - rootInode->i_fop = &RootFileOps; - rootInode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - - LOG(4, "%s file system mounted\n", VMBLOCK_FS_NAME); - return 0; -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) -/* - *----------------------------------------------------------------------------- - * - * FsOpMount -- - * - * Invokes generic kernel code to mount a deviceless filesystem. - * - * Results: - * Mount's root dentry tructure on success - * ERR_PTR()-encoded negative error code on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -struct dentry * -FsOpMount(struct file_system_type *fs_type, // IN: file system type of mount - int flags, // IN: mount flags - const char *dev_name, // IN: device mounting on - void *rawData) // IN: mount arguments -{ - return mount_nodev(fs_type, flags, rawData, FsOpReadSuper); -} -#elif defined(VMW_GETSB_2618) -/* - *----------------------------------------------------------------------------- - * - * FsOpGetSb -- - * - * Invokes generic kernel code to prepare superblock for - * deviceless filesystem. - * - * Results: - * 0 on success - * negative error code on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount - int flags, // IN: mount flags - const char *dev_name, // IN: device mounting on - void *rawData, // IN: mount arguments - struct vfsmount *mnt) // IN: vfs mount -{ - return get_sb_nodev(fs_type, flags, rawData, FsOpReadSuper, mnt); -} -#else -/* - *----------------------------------------------------------------------------- - * - * FsOpGetSb -- - * - * Invokes generic kernel code to prepare superblock for - * deviceless filesystem. - * - * Results: - * The initialized superblock on success - * NULL on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static struct super_block * -FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount - int flags, // IN: mount flags - const char *dev_name, // IN: device mounting on - void *rawData) // IN: mount arguments -{ - return get_sb_nodev(fs_type, flags, rawData, FsOpReadSuper); -} -#endif - diff --git a/open-vm-tools/modules/linux/vmblock/linux/filesystem.h b/open-vm-tools/modules/linux/vmblock/linux/filesystem.h deleted file mode 100644 index e4772fcf9..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/filesystem.h +++ /dev/null @@ -1,87 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * filesystem.h -- - * - * Definitions and prototypes for file system portion of vmblock driver. - * - * There are currently two classes of files in the blocking file system: the - * root directory and symlinks to actual files on the file system. The root - * directory provides a way to lookup directory entries in the directory we - * are redirecting to; each of these directory entries is presented as - * a symlink. These symlinks within the root directory contain the path of - * the actual file and will block any time the inode is accessed or dentry is - * revalidated (if there is a pending block). This blocking ensures that any - * access to the file through the symlink will not proceed until the block is - * lifted. - * - * Operation tables for the root directory and symlinks are are named Root*Ops - * and Link*Ops respectively. All operations are preceded by their operation - * type (e.g., the file_operation table's open is named FileOpOpen and the - * inode_operation table's lookup is named InodeOpLookup). - * - * The use of symlinks greatly simplifies the driver's implementation but also - * limits blocking to a depth of one level within the redirected directory - * (since after the symlink is followed all operations are passed on to the - * actual file system and are out of our control). This limitation is fine - * under the current use of this driver. - */ - -#ifndef __FILESYSTEM_H__ -#define __FILESYSTEM_H__ - -#include "compat_slab.h" -#include - -#include "vm_basic_types.h" - -#define INODE_TO_IINFO(_inode) container_of(_inode, VMBlockInodeInfo, inode) -#define INODE_TO_ACTUALDENTRY(inode) INODE_TO_IINFO(inode)->actualDentry -#define INODE_TO_ACTUALINODE(inode) INODE_TO_IINFO(inode)->actualDentry->d_inode - -#define VMBLOCK_SUPER_MAGIC 0xabababab - -typedef struct VMBlockInodeInfo { - char name[PATH_MAX]; - size_t nameLen; - struct dentry *actualDentry; - /* Embedded inode */ - struct inode inode; -} VMBlockInodeInfo; - - -ino_t GetNextIno(void); -struct inode *Iget(struct super_block *sb, struct inode *dir, - struct dentry *dentry, ino_t ino); -int MakeFullName(struct inode *dir, struct dentry *dentry, - char *bufOut, size_t bufOutSize); -void VMBlockReadInode(struct inode *inode); - -/* Variables */ -extern compat_kmem_cache *VMBlockInodeCache; -/* File system wide superblock operations */ -extern struct super_operations VMBlockSuperOps; -/* File operations on fs's root inode to read directory entries. */ -extern struct file_operations RootFileOps; -/* Inode operations to lookup inodes of directory entries in fs's root inode. */ -extern struct inode_operations RootInodeOps; -/* Dentry operations for our symlinks to actual files (to enable blocking). */ -extern struct dentry_operations LinkDentryOps; - -#endif /* __FILESYSTEM_H__ */ diff --git a/open-vm-tools/modules/linux/vmblock/linux/inode.c b/open-vm-tools/modules/linux/vmblock/linux/inode.c deleted file mode 100644 index 098c94c8c..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/inode.c +++ /dev/null @@ -1,232 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * inode.c -- - * - * Inode operations for the file system of the vmblock driver. - * - */ - -#include "driver-config.h" -#include -#include -#include -#include - -#include "vmblockInt.h" -#include "filesystem.h" -#include "block.h" - - -/* Inode operations */ -static struct dentry *InodeOpLookup(struct inode *dir, - struct dentry *dentry, struct nameidata *nd); -static int InodeOpReadlink(struct dentry *dentry, char __user *buffer, int buflen); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -static void *InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd); -#else -static int InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd); -#endif - - -struct inode_operations RootInodeOps = { - .lookup = InodeOpLookup, -}; - -static struct inode_operations LinkInodeOps = { - .readlink = InodeOpReadlink, - .follow_link = InodeOpFollowlink, -}; - - -/* - *---------------------------------------------------------------------------- - * - * InodeOpLookup -- - * - * Looks up a name (dentry) in provided directory. Invoked every time - * a directory entry is traversed in path lookups. - * - * Results: - * NULL on success, negative error code on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static struct dentry * -InodeOpLookup(struct inode *dir, // IN: parent directory's inode - struct dentry *dentry, // IN: dentry to lookup - struct nameidata *nd) // IN: lookup intent and information -{ - char *filename; - struct inode *inode; - int ret; - - if (!dir || !dentry) { - Warning("InodeOpLookup: invalid args from kernel\n"); - return ERR_PTR(-EINVAL); - } - - /* The kernel should only pass us our own inodes, but check just to be safe. */ - if (!INODE_TO_IINFO(dir)) { - Warning("InodeOpLookup: invalid inode provided\n"); - return ERR_PTR(-EINVAL); - } - - /* Get a slab from the kernel's names_cache of PATH_MAX-sized buffers. */ - filename = __getname(); - if (!filename) { - Warning("InodeOpLookup: unable to obtain memory for filename.\n"); - return ERR_PTR(-ENOMEM); - } - - ret = MakeFullName(dir, dentry, filename, PATH_MAX); - if (ret < 0) { - Warning("InodeOpLookup: could not construct full name\n"); - __putname(filename); - return ERR_PTR(ret); - } - - /* Block if there is a pending block on this file */ - BlockWaitOnFile(filename, NULL); - __putname(filename); - - inode = Iget(dir->i_sb, dir, dentry, GetNextIno()); - if (!inode) { - Warning("InodeOpLookup: failed to get inode\n"); - return ERR_PTR(-ENOMEM); - } - - dentry->d_op = &LinkDentryOps; - dentry->d_time = jiffies; - - /* - * If the actual file's dentry doesn't have an inode, it means the file we - * are redirecting to doesn't exist. Give back the inode that was created - * for this and add a NULL dentry->inode entry in the dcache. (The NULL - * entry is added so ops to create files/directories are invoked by VFS.) - */ - if (!INODE_TO_ACTUALDENTRY(inode) || !INODE_TO_ACTUALINODE(inode)) { - iput(inode); - d_add(dentry, NULL); - return NULL; - } - - inode->i_mode = S_IFLNK | S_IRWXUGO; - inode->i_size = INODE_TO_IINFO(inode)->nameLen; - inode->i_version = 1; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_uid = inode->i_gid = 0; - inode->i_op = &LinkInodeOps; - - d_add(dentry, inode); - return NULL; -} - - -/* - *---------------------------------------------------------------------------- - * - * InodeOpReadlink -- - * - * Provides the symbolic link's contents to the user. Invoked when - * readlink(2) is invoked on our symlinks. - * - * Results: - * 0 on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -InodeOpReadlink(struct dentry *dentry, // IN : dentry of symlink - char __user *buffer, // OUT: output buffer (user space) - int buflen) // IN : length of output buffer -{ - VMBlockInodeInfo *iinfo; - - if (!dentry || !buffer) { - Warning("InodeOpReadlink: invalid args from kernel\n"); - return -EINVAL; - } - - iinfo = INODE_TO_IINFO(dentry->d_inode); - if (!iinfo) { - return -EINVAL; - } - - return vfs_readlink(dentry, buffer, buflen, iinfo->name); -} - - -/* - *---------------------------------------------------------------------------- - * - * InodeOpFollowlink -- - * - * Provides the inode corresponding to this symlink through the nameidata - * structure. - * - * Results: - * 0 on success, negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -static void * -#else -static int -#endif -InodeOpFollowlink(struct dentry *dentry, // IN : dentry of symlink - struct nameidata *nd) // OUT: stores result -{ - int ret; - VMBlockInodeInfo *iinfo; - - if (!dentry) { - Warning("InodeOpReadlink: invalid args from kernel\n"); - ret = -EINVAL; - goto out; - } - - iinfo = INODE_TO_IINFO(dentry->d_inode); - if (!iinfo) { - ret = -EINVAL; - goto out; - } - - ret = vfs_follow_link(nd, iinfo->name); - -out: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) - return ERR_PTR(ret); -#else - return ret; -#endif -} diff --git a/open-vm-tools/modules/linux/vmblock/linux/module.c b/open-vm-tools/modules/linux/vmblock/linux/module.c deleted file mode 100644 index bb33165d4..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/module.c +++ /dev/null @@ -1,130 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * module.c -- - * - * Module loading/unloading functions. - * - */ - -#include "driver-config.h" -#include -#include -#include -#include - -#include "vmblockInt.h" -#include "vmblock_version.h" - -/* Module parameters */ -#ifdef VMX86_DEVEL /* { */ -int LOGLEVEL_THRESHOLD = 4; -module_param(LOGLEVEL_THRESHOLD, int, 0600); -MODULE_PARM_DESC(LOGLEVEL_THRESHOLD, "Logging level (0 means no log, " - "10 means very verbose, 4 is default)"); -#endif /* } */ - -static char *root = "/tmp/VMwareDnD"; -module_param(root, charp, 0600); -MODULE_PARM_DESC(root, "The directory the file system redirects to."); - -/* Module information */ -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Blocking File System"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(VMBLOCK_DRIVER_VERSION_STRING); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); - -/* - *---------------------------------------------------------------------------- - * - * VMBlockInit -- - * - * Module entry point and initialization. - * - * Results: - * Zero on success, negative value on failure. - * - * Side effects: - * /proc entries are available and file system is registered with kernel and - * ready to be mounted. - * - *---------------------------------------------------------------------------- - */ - -static int -VMBlockInit(void) -{ - int ret; - - ret = VMBlockInitControlOps(); - if (ret < 0) { - goto error; - } - - ret = VMBlockInitFileSystem(root); - if (ret < 0) { - VMBlockCleanupControlOps(); - goto error; - } - - LOG(4, "module loaded\n"); - return 0; - -error: - Warning("VMBlock: could not initialize module\n"); - return ret; -} - -module_init(VMBlockInit); - - -/* - *---------------------------------------------------------------------------- - * - * VMBlockExit -- - * - * Unloads module from kernel and removes associated state. - * - * Results: - * None. - * - * Side effects: - * Opposite of VMBlockInit(): /proc entries go away and file system is - * unregistered. - * - *---------------------------------------------------------------------------- - */ - -static void -VMBlockExit(void) -{ - VMBlockCleanupControlOps(); - VMBlockCleanupFileSystem(); - - LOG(4, "module unloaded\n"); -} - -module_exit(VMBlockExit); diff --git a/open-vm-tools/modules/linux/vmblock/linux/os.h b/open-vm-tools/modules/linux/vmblock/linux/os.h deleted file mode 100644 index f592e17e5..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/os.h +++ /dev/null @@ -1,103 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - - -/* - * os.h -- - * - * OS-specific definitions. - */ - - -#ifndef __OS_H__ -#define __OS_H__ - -#include "driver-config.h" -#include -#include -#include "compat_slab.h" -#include -#include -#include -#include - -typedef rwlock_t os_rwlock_t; -typedef compat_kmem_cache os_kmem_cache_t; -typedef struct completion os_completion_t; -typedef atomic_t os_atomic_t; -typedef struct file * os_blocker_id_t; - -#define OS_UNKNOWN_BLOCKER NULL -#define OS_ENOMEM (-ENOMEM) -#define OS_ENOENT (-ENOENT) -#define OS_EEXIST (-EEXIST) -#define OS_PATH_MAX PATH_MAX - -#define OS_FMTTID "d" -#define os_threadid (current->pid) - -#define os_panic(fmt, args) \ - ({ \ - vprintk(fmt, args); \ - BUG(); \ - }) - -#define os_rwlock_init(lock) rwlock_init(lock) -#define os_rwlock_destroy(lock) -/* - * XXX We'd like to check for kernel version 2.5.34 as the patches indicate, - * but SLES10's 2.6.16.21-0.8-i586default doesn't seem to have this defined. - */ -#if defined(rwlock_is_locked) -# define os_rwlock_held(lock) rwlock_is_locked(lock) -#else -/* XXX Is there something we can come up with for this? */ -# define os_rwlock_held(lock) TRUE -#endif -#define os_read_lock(lock) read_lock(lock) -#define os_write_lock(lock) write_lock(lock) -#define os_read_unlock(lock) read_unlock(lock) -#define os_write_unlock(lock) write_unlock(lock) - -#define os_kmem_cache_create(name, size, align, ctor) \ - compat_kmem_cache_create(name, size, align, SLAB_HWCACHE_ALIGN, ctor) -#define os_kmem_cache_destroy(cache) kmem_cache_destroy(cache) -#define os_kmem_cache_alloc(cache) kmem_cache_alloc(cache, GFP_KERNEL) -#define os_kmem_cache_free(cache, elem) kmem_cache_free(cache, elem) - -#define os_completion_init(comp) init_completion(comp) -#define os_completion_destroy(comp) -/* - * XXX This should be made interruptible using - * wait_for_completion_interruptible(), and return a proper value. Callers - * would need to handle interruption, of course. - */ -#define os_wait_for_completion(comp) \ -({ \ - wait_for_completion(comp); \ - 0; \ - }) -#define os_complete_all(comp) complete_all(comp) - -#define os_atomic_dec_and_test(atomic) atomic_dec_and_test(atomic) -#define os_atomic_dec(atomic) atomic_dec(atomic) -#define os_atomic_set(atomic, val) atomic_set(atomic, val) -#define os_atomic_inc(atomic) atomic_inc(atomic) -#define os_atomic_read(atomic) atomic_read(atomic) - -#endif /* __OS_H__ */ diff --git a/open-vm-tools/modules/linux/vmblock/linux/super.c b/open-vm-tools/modules/linux/vmblock/linux/super.c deleted file mode 100644 index fb65c578c..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/super.c +++ /dev/null @@ -1,147 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * super.c -- - * - * Super operations for the file system portion of the vmblock driver. - * - */ - -#include "driver-config.h" -#include -#include - -#include "vmblockInt.h" -#include "filesystem.h" - -/* Super block operations */ -static struct inode *SuperOpAllocInode(struct super_block *sb); -static void SuperOpDestroyInode(struct inode *inode); -#ifdef VMW_STATFS_2618 -static int SuperOpStatfs(struct dentry *dentry, struct kstatfs *stat); -#else -static int SuperOpStatfs(struct super_block *sb, struct kstatfs *stat); -#endif - - -struct super_operations VMBlockSuperOps = { - .alloc_inode = SuperOpAllocInode, - .destroy_inode = SuperOpDestroyInode, - .statfs = SuperOpStatfs, -}; - - -/* - *---------------------------------------------------------------------------- - * - * SuperOpAllocInode -- - * - * Allocates an inode info from the cache. See function comment for Iget() - * for a complete explanation of how inode allocation works. - * - * Results: - * A pointer to the embedded inode on success, NULL on failure. - * - * Side effects: - * iinfo is initialized by InodeCacheCtor(). - * - *---------------------------------------------------------------------------- - */ - -static struct inode * -SuperOpAllocInode(struct super_block *sb) // IN: superblock of file system -{ - VMBlockInodeInfo *iinfo; - - iinfo = kmem_cache_alloc(VMBlockInodeCache, GFP_KERNEL); - if (!iinfo) { - Warning("SuperOpAllocInode: could not allocate iinfo\n"); - return NULL; - } - - /* The inode we give back to VFS is embedded within our inode info struct. */ - return &iinfo->inode; -} - - -/* - *---------------------------------------------------------------------------- - * - * SuperOpDestroyInode -- - * SuperOpClearInode -- - * - * Destroys the provided inode by freeing the inode info. In the embedded - * inode case, this includes the actual inode itself; in the non-embedded - * inode case, the inode is freed by the kernel. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -SuperOpDestroyInode(struct inode *inode) // IN: Inode to free -{ - kmem_cache_free(VMBlockInodeCache, INODE_TO_IINFO(inode)); -} - - -/* - *---------------------------------------------------------------------------- - * - * SuperOpStatfs -- - * - * Implements a null statfs. - * - * Results: - * Zero on success, negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -#ifdef VMW_STATFS_2618 -static int -SuperOpStatfs(struct dentry *dentry, - struct kstatfs *stat) -#else -static int -SuperOpStatfs(struct super_block *sb, - struct kstatfs *stat) -#endif -{ - if (!stat) { - return -EINVAL; - } - - stat->f_type = VMBLOCK_SUPER_MAGIC; - stat->f_bsize = 0; - stat->f_namelen = NAME_MAX; - stat->f_blocks = 0; - stat->f_bfree = 0; - stat->f_bavail = 0; - - return 0; -} diff --git a/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h b/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h deleted file mode 100644 index 76cc4a165..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h +++ /dev/null @@ -1,88 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * vmblockInt.h -- - * - * Definitions and prototypes for entire module. - * - * The module is split into two halves, a control half and a file system - * half, and the halves communicate through the blocking functionality in - * block.c. The control half creates a device node for a user space program - * (running as root) to add and delete blocks on files in the file system's - * namespace. The file system provides links to the contents of the - * directory it is redirecting to and blocks according to the file blocks set - * through the control half. - */ - -#ifndef __VMBLOCKINT_H__ -#define __VMBLOCKINT_H__ - -#include -#include - -#include "vmblock.h" -#include "vm_basic_types.h" -#include "vm_assert.h" - -#ifdef __KERNEL__ -#ifdef VMX86_DEVEL -extern int LOGLEVEL_THRESHOLD; -# define LOG(level, fmt, args...) \ - ((void) (LOGLEVEL_THRESHOLD >= (level) ? \ - printk(KERN_DEBUG "VMBlock: " fmt, ## args) : \ - 0) \ - ) -#else -# define LOG(level, fmt, args...) -#endif -#define Warning(fmt, args...) \ - printk(KERN_WARNING "VMBlock warning: " fmt, ## args) -/* - * Some kernel versions, bld-2.4.21-32.EL_x86_64-ia32e-RHEL3 and perhaps more, - * don't define __user in uaccess.h, so let's do it here so we don't have to - * ifdef all the __user annotations. - */ -#ifndef __user -#define __user -#endif -#endif /* __KERNEL__ */ - -#define VMBLOCK_CONTROL_MODE S_IRUSR | S_IFREG - -/* - * Our modules may be compatible with kernels built for different processors. - * This can cause problems, so we add a reference to the __alloc_pages symbol - * below since it is versioned per-processor and will cause modules to only - * load on kernels built for the same processor as our module. - * - * XXX This should go in driver-config.h, but vmmon's hostKernel.h is retarded. - */ -static const void *forceProcessorCheck __attribute__((unused)) = __alloc_pages; - - -/* - * Initialization and cleanup routines for control and file system halves of - * vmblock driver - */ -int VMBlockInitControlOps(void); -int VMBlockCleanupControlOps(void); -int VMBlockInitFileSystem(char const *root); -int VMBlockCleanupFileSystem(void); - -#endif /* __VMBLOCK_H__ */ diff --git a/open-vm-tools/modules/linux/vmblock/linux/vmblock_version.h b/open-vm-tools/modules/linux/vmblock/linux/vmblock_version.h deleted file mode 100644 index 765175c68..000000000 --- a/open-vm-tools/modules/linux/vmblock/linux/vmblock_version.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmblock_version.h -- - * - * Version definitions for the Linux vmblock driver. - */ - -#ifndef _VMBLOCK_VERSION_H_ -#define _VMBLOCK_VERSION_H_ - -#define VMBLOCK_DRIVER_VERSION 1.1.2.0 -#define VMBLOCK_DRIVER_VERSION_COMMAS 1,1,2,0 -#define VMBLOCK_DRIVER_VERSION_STRING "1.1.2.0" - -#endif /* _VMBLOCK_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vmci/COPYING b/open-vm-tools/modules/linux/vmci/COPYING deleted file mode 100644 index d511905c1..000000000 --- a/open-vm-tools/modules/linux/vmci/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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; either version 2 of the License, or - (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/open-vm-tools/modules/linux/vmci/Makefile b/open-vm-tools/modules/linux/vmci/Makefile deleted file mode 100644 index 3bbbaefe9..000000000 --- a/open-vm-tools/modules/linux/vmci/Makefile +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware kernel module Makefile to be distributed externally -#### - -#### -#### SRCROOT _must_ be a relative path. -#### -SRCROOT = . - -# -# open-vm-tools doesn't replicate shared source files for different modules; -# instead, files are kept in shared locations. So define a few useful macros -# to be able to handle both cases cleanly. -# -INCLUDE := -ifdef OVT_SOURCE_DIR -AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf -VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1) -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared -INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include -else -AUTOCONF_DIR := $(SRCROOT)/shared/autoconf -INCLUDE += -I$(SRCROOT)/shared -endif - - -VM_UNAME = $(shell uname -r) - -# Header directory for the running kernel -ifdef LINUXINCLUDE -HEADER_DIR = $(LINUXINCLUDE) -else -HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include -endif - -BUILD_DIR = $(HEADER_DIR)/.. - -DRIVER := vmci -PRODUCT := tools-source - -# Grep program -GREP = /bin/grep - -vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) -vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi) - -ifndef VM_KBUILD -VM_KBUILD := no -ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes) -VM_KBUILD := yes -endif -export VM_KBUILD -endif - -ifndef VM_KBUILD_SHOWN -ifeq ($(VM_KBUILD), no) -VM_DUMMY := $(shell echo >&2 "Using standalone build system.") -else -VM_DUMMY := $(shell echo >&2 "Using kernel build system.") -endif -VM_KBUILD_SHOWN := yes -export VM_KBUILD_SHOWN -endif - -ifneq ($(VM_KBUILD), no) - -VMCCVER := $(shell $(CC) -dumpversion) - -# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles... -ifeq ($(VERSION),) - -DRIVER_KO := $(DRIVER).ko - -.PHONY: $(DRIVER_KO) - -auto-build: $(DRIVER_KO) - cp -f $< $(SRCROOT)/../$(DRIVER).o - -# $(DRIVER_KO) is a phony target, so compare file times explicitly -$(DRIVER): $(DRIVER_KO) - if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi - -# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler -VM_CCVER := $(VMCCVER) -export VM_CCVER -VM_CC := $(CC) -export VM_CC - -MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES)) - -# -# Define a setup target that gets built before the actual driver. -# This target may not be used at all, but if it is then it will be defined -# in Makefile.kernel -# -prebuild:: ; -postbuild:: ; - -$(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) modules - $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild -endif - -vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \ - $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \ - -DKBUILD_BASENAME=\"$(DRIVER)\" \ - -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -CC_WARNINGS := -Wall -Wstrict-prototypes -CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD -ifdef VMX86_DEVEL -CC_OPTS += -DVMX86_DEVEL -endif -ifdef VMX86_DEBUG -CC_OPTS += -DVMX86_DEBUG -endif - -include $(SRCROOT)/Makefile.kernel - -else - -include $(SRCROOT)/Makefile.normal - -endif - -#.SILENT: diff --git a/open-vm-tools/modules/linux/vmci/Makefile.kernel b/open-vm-tools/modules/linux/vmci/Makefile.kernel deleted file mode 100644 index 8e6e7d0b3..000000000 --- a/open-vm-tools/modules/linux/vmci/Makefile.kernel +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 2007,2014 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 -# -########################################################## - -CC_OPTS += -DVMCI - -INCLUDE += -I$(SRCROOT)/shared -I$(SRCROOT)/common -I$(SRCROOT)/linux - -EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) - -obj-m += $(DRIVER).o - -$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, \ - $(wildcard $(SRCROOT)/linux/*.c $(SRCROOT)/common/*.c))) - -# -# In open-vm-tools, need to compile the common sources from the shared directory. -# -DRIVERLOG := driverLog.o -$(DRIVER)-y += $(DRIVERLOG) - -VMCI_PATH := $(shell cd $(SRCROOT) && pwd) -ifdef OVT_SOURCE_DIR -DRIVERLOG_PATH := $(OVT_SOURCE_DIR)/modules/linux/shared -else -DRIVERLOG_PATH := $(VMCI_PATH)/shared -endif - -$(addprefix $(VMCI_PATH)/,$(DRIVERLOG)): $(VMCI_PATH)/%.o: $(DRIVERLOG_PATH)/%.c - $(Q)$(rule_cc_o_c) - -clean: - rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ - Module.symvers Modules.symvers Module.markers modules.order \ - $(foreach dir,linux/ common/ \ - ./,$(addprefix $(dir),.*.cmd .*.o.flags *.o))) -ifneq ($(MODULEBUILDDIR),) - rm -f $(MODULEBUILDDIR)/VMwareVMCIModule.symvers -endif - -# -# If this build generated a Module.symvers, copy it to a public place where -# the vSockets build will be able to find it. -# -postbuild:: -ifeq ($(call vm_check_file,$(SRCROOT)/Module.symvers), yes) -ifneq ($(MODULEBUILDDIR),) - cp -f $(SRCROOT)/Module.symvers $(MODULEBUILDDIR)/VMwareVMCIModule.symvers -endif -endif diff --git a/open-vm-tools/modules/linux/vmci/Makefile.normal b/open-vm-tools/modules/linux/vmci/Makefile.normal deleted file mode 100644 index dda1844fb..000000000 --- a/open-vm-tools/modules/linux/vmci/Makefile.normal +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 2007 VMware, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation version 2 and no later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -########################################################## - -vm_check_build = $(shell if $(CC) $(CC_OPTS) $(INCLUDE) -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -#### -#### DESTDIR is where the module, object files, and dependencies are built -#### -DESTDIR := driver-$(VM_UNAME) - -#### -#### DRIVERNAME should be untouched unless you have a good reason to change -#### it. The form below is how the scripts expect it. -#### -DRIVERNAME := $(DRIVER)-xxx-$(VM_UNAME) - -ifneq (,$(filter x86_64%, $(shell $(CC) -dumpmachine))) -MACHINE := x86_64 -else -MACHINE := x386 -endif - -ifdef QUIET -ECHO := @true -else -ECHO := @echo -endif - -#### -#### You must compile with at least -O level of optimization -#### or the module won't load. -#### If desparate, I think that bringing in might -#### suffice. -#### -CC_WARNINGS := -Wall -Wstrict-prototypes -# Don't use -pipe or egcs-2.91.66 (shipped with RedHat) will die -CC_KFLAGS := -D__KERNEL__ -fno-strength-reduce -fno-omit-frame-pointer \ - -fno-common -DKBUILD_MODNAME=\"$(DRIVER)\" -CC_KFLAGS += $(call vm_check_gcc,-falign-loops=2 -falign-jumps=2 -falign-functions=2, \ - -malign-loops=2 -malign-jumps=2 -malign-functions=2) -CC_KFLAGS += $(call vm_check_gcc,-fno-strict-aliasing,) -ifeq ($(MACHINE),x86_64) -CC_KFLAGS += -mno-red-zone -mcmodel=kernel -else -# Gcc 3.0 deprecates -m486 --hpreg -CC_KFLAGS += -DCPU=586 $(call check_gcc,-march=i586,-m486) -endif - -CC_OPTS := -O2 -DMODULE -DVMCI $(GLOBAL_DEFS) $(CC_KFLAGS) $(CC_WARNINGS) - -INCLUDE := -I$(SRCROOT)/shared -I$(SRCROOT)/common -I$(SRCROOT)/linux \ - -I$(HEADER_DIR) - -INCLUDE += $(shell $(CC) $(INCLUDE) -E $(SRCROOT)/shared/autoconf/geninclude.c \ - | sed -n -e 's!^APATH!-I$(HEADER_DIR)/asm!p') - -ifdef OVT_SOURCE_PATH -DRIVERLOGPATH := $(OVT_SOURCE_DIR)/modules/linux/shared -else -DRIVERLOGPATH := $(SRCROOT)/shared -endif - -C_TARGETS_LINUX := driver.o vmciKernelIf.o -C_TARGETS_COMMON := vmciContext.o vmciDatagram.o vmciDriver.o \ - vmciHashtable.o vmciResource.o \ - vmciQueuePair.o vmciEvent.o vmciRoute.o - -C_TARGETS_LINUX_D := ${C_TARGETS_LINUX:.o=.d} -C_TARGETS_COMMON_D := ${C_TARGETS_COMMON:.o=.d} -C_TARGETS := $(C_TARGETS_LINUX) $(C_TARGETS_COMMON) driverLog.o - -#### -#### Make Targets are beneath here. -#### - -driver: setup deps - $(MAKE) -C $(DESTDIR) -f ../Makefile SRCROOT=../$(SRCROOT) $(DRIVER).o \ - INCLUDE_DEPS=1 - -setup: - @if [ -d $(DESTDIR) ] ; then true ; else mkdir $(DESTDIR); chmod 755 $(DESTDIR) ; fi - -$(DRIVER) $(DRIVER).o: $(DRIVERNAME) - cp -f $< $@ - -$(DRIVERNAME): $(C_TARGETS) - $(ECHO) "Building $(DRIVERNAME)" - ld -r -o $(DRIVERNAME) $(C_TARGETS) - -auto-build: - $(MAKE) driver QUIET=1 - cp -f $(DESTDIR)/$(DRIVERNAME) $(SRCROOT)/../$(DRIVER).o - -$(C_TARGETS_LINUX): %.o: $(SRCROOT)/linux/%.c - $(ECHO) "Compiling linux/$( $@ - -$(C_TARGETS_LINUX_D): %.d: $(SRCROOT)/linux/%.c - $(ECHO) "Dependencies for $( $@ - -driverLog.d: $(DRIVERLOGPATH)/driverLog.c - $(ECHO) "Dependencies for $( $@ - -deps: setup - $(MAKE) -C $(DESTDIR) -f ../Makefile SRCROOT=../$(SRCROOT) driver_deps - -driver_deps: ${C_TARGETS:.o=.d} - -ifdef INCLUDE_DEPS -include ${C_TARGETS:.o=.d} -endif - -.SILENT: diff --git a/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h b/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h deleted file mode 100644 index 8af33b472..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h +++ /dev/null @@ -1,150 +0,0 @@ -/********************************************************* - * 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 - * 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 - * - *********************************************************/ - -/* - * vmciCommonInt.h -- - * - * Struct definitions for VMCI internal common code. - */ - -#ifndef _VMCI_COMMONINT_H_ -#define _VMCI_COMMONINT_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vm_atomic.h" -#include "vmci_defs.h" -#include "vmci_call_defs.h" -#include "vmci_infrastructure.h" -#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 - * content is accessed while holding a spinlock. The pending datagram - * itself may be allocated from paged memory. We shadow the size of - * the datagram in the non-paged queue entry as this size is used - * while holding the same spinlock as above. - */ - -typedef struct DatagramQueueEntry { - VMCIListItem listItem; /* For queuing. */ - size_t dgSize; /* Size of datagram. */ - VMCIDatagram *dg; /* Pending datagram. */ -} 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; - Atomic_uint32 refCount; - VMCIList datagramQueue; /* Head of per VM queue. */ - uint32 pendingDatagrams; - size_t datagramQueueSize;/* Size of datagram queue in bytes. */ - int userVersion; /* - * Version of the code that created - * this context; e.g., VMX. - */ - VMCILock lock; /* - * Locks datagramQueue, inFilters, - * doorbellArray, pendingDoorbellArray - * and notifierArray. - */ - VMCIHandleArray *queuePairArray; /* - * QueuePairs attached to. The array of - * handles for queue pairs is accessed - * from the code for QP API, and there - * it is protected by the QP lock. It - * is also accessed from the context - * clean up path, which does not - * require a lock. VMCILock is not - * used to protect the QP array. - */ - VMCIHandleArray *doorbellArray; /* Doorbells created by context. */ - VMCIHandleArray *pendingDoorbellArray; /* Doorbells pending for context. */ - VMCIHandleArray *notifierArray; /* Contexts current context is subscribing to. */ - VMCIHost hostContext; - VMCIPrivilegeFlags privFlags; - VMCIHostUser user; - Bool validUser; -#ifdef VMKERNEL - Bool isQuiesced; /* Whether current VM is quiesced */ - VMCIId migrateCid; /* The migrate cid if it is migrating */ - VMCIMutex guestMemMutex; /* - * Coordinates guest memory - * 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. */ -# ifdef __linux__ - struct page *notifyPage; /* Page backing the notify UVA. */ -# endif -#endif -}; - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDenyInteraction -- - * - * Utilility function that checks whether two entities are allowed - * to interact. If one of them is restricted, the other one must - * be trusted. - * - * Result: - * TRUE if the two entities are not allowed to interact. FALSE otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static INLINE Bool -VMCIDenyInteraction(VMCIPrivilegeFlags partOne, // IN - VMCIPrivilegeFlags partTwo) // IN -{ - return (((partOne & VMCI_PRIVILEGE_FLAG_RESTRICTED) && - !(partTwo & VMCI_PRIVILEGE_FLAG_TRUSTED)) || - ((partTwo & VMCI_PRIVILEGE_FLAG_RESTRICTED) && - !(partOne & VMCI_PRIVILEGE_FLAG_TRUSTED))); -} - -#endif /* _VMCI_COMMONINT_H_ */ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.c b/open-vm-tools/modules/linux/vmci/common/vmciContext.c deleted file mode 100644 index 933d11fd1..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.c +++ /dev/null @@ -1,3042 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2012,2014-2016 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 - * - *********************************************************/ - -/* - * vmciContext.c -- - * - * Platform independent routines for VMCI calls. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciContext.h" -#include "vmciDatagram.h" -#include "vmciDoorbell.h" -#include "vmciDriver.h" -#include "vmciEvent.h" -#include "vmciKernelAPI.h" -#include "vmciQueuePair.h" -#if defined(_WIN32) -# include "kernelStubsSal.h" -#elif defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -#endif - -#define LGPFX "VMCIContext: " - -static void VMCIContextFreeContext(VMCIContext *context); -static Bool VMCIContextExists(VMCIId cid); -static int VMCIContextFireNotification(VMCIId contextID, - VMCIPrivilegeFlags privFlags); -#if defined(VMKERNEL) -static void VMCIContextReleaseGuestMemLocked(VMCIContext *context, - VMCIGuestMemID gid, - Bool powerOff); -static void VMCIContextInFilterCleanup(VMCIContext *context); -#endif - -/* - * List of current VMCI contexts. - */ - -static struct { - VMCIList head; - VMCILock lock; - VMCILock firingLock; -} contextList; - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextSignalNotify -- - * - * Sets the notify flag to TRUE. Assumes that the context lock is - * held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VMCIContextSignalNotify(VMCIContext *context) // IN: -{ -#ifndef VMX86_SERVER - if (context->notify) { - *context->notify = TRUE; - } -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextClearNotify -- - * - * Sets the notify flag to FALSE. Assumes that the context lock is - * held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VMCIContextClearNotify(VMCIContext *context) // IN: -{ -#ifndef VMX86_SERVER - if (context->notify) { - *context->notify = FALSE; - } -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextClearNotifyAndCall -- - * - * If nothing requires the attention of the guest, clears both - * notify flag and call. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE void -VMCIContextClearNotifyAndCall(VMCIContext *context) // IN: -{ - if (context->pendingDatagrams == 0 && - VMCIHandleArray_GetSize(context->pendingDoorbellArray) == 0) { - VMCIHost_ClearCall(&context->hostContext); - VMCIContextClearNotify(context); - } -} - - -#ifndef VMX86_SERVER -/* - *---------------------------------------------------------------------- - * - * VMCIContext_CheckAndSignalNotify -- - * - * Sets the context's notify flag iff datagrams are pending for this - * context. Called from VMCISetupNotify(). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_CheckAndSignalNotify(VMCIContext *context) // IN: -{ - VMCILockFlags flags; - - ASSERT(context); - VMCI_GrabLock(&context->lock, &flags); - if (context->pendingDatagrams) { - VMCIContextSignalNotify(context); - } - VMCI_ReleaseLock(&context->lock, flags); -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_Init -- - * - * Initializes the VMCI context module. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_Init(void) -{ - int err; - - VMCIList_Init(&contextList.head); - - err = VMCI_InitLock(&contextList.lock, "VMCIContextListLock", - VMCI_LOCK_RANK_CONTEXTLIST); - if (err < VMCI_SUCCESS) { - return err; - } - - err = VMCI_InitLock(&contextList.firingLock, "VMCIContextFiringLock", - VMCI_LOCK_RANK_CONTEXTFIRE); - if (err < VMCI_SUCCESS) { - VMCI_CleanupLock(&contextList.lock); - } - - return err; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_Exit -- - * - * Cleans up the contexts module. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_Exit(void) -{ - VMCI_CleanupLock(&contextList.firingLock); - VMCI_CleanupLock(&contextList.lock); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_InitContext -- - * - * Allocates and initializes a VMCI context. - * - * Results: - * Returns 0 on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_InitContext(VMCIId cid, // IN - VMCIPrivilegeFlags privFlags, // IN - uintptr_t eventHnd, // IN - int userVersion, // IN: User's vers no. - VMCIHostUser *user, // IN - VMCIContext **outContext) // OUT -{ - VMCILockFlags flags; - VMCIContext *context; - int result; - - if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid flag (flags=0x%x) for VMCI context.\n", - privFlags)); - return VMCI_ERROR_INVALID_ARGS; - } - - if (userVersion == 0) { - return VMCI_ERROR_INVALID_ARGS; - } - - context = VMCI_AllocKernelMem(sizeof *context, VMCI_MEMORY_NONPAGED); - if (context == NULL) { - VMCI_WARNING((LGPFX"Failed to allocate memory for VMCI context.\n")); - return VMCI_ERROR_NO_MEM; - } - memset(context, 0, sizeof *context); - - VMCIList_InitEntry(&context->listItem); - VMCIList_Init(&context->datagramQueue); - - context->userVersion = userVersion; - - context->queuePairArray = VMCIHandleArray_Create(0); - if (!context->queuePairArray) { - result = VMCI_ERROR_NO_MEM; - goto error; - } - - context->doorbellArray = VMCIHandleArray_Create(0); - if (!context->doorbellArray) { - result = VMCI_ERROR_NO_MEM; - goto error; - } - - context->pendingDoorbellArray = VMCIHandleArray_Create(0); - if (!context->pendingDoorbellArray) { - result = VMCI_ERROR_NO_MEM; - goto error; - } - - context->notifierArray = VMCIHandleArray_Create(0); - if (context->notifierArray == NULL) { - result = VMCI_ERROR_NO_MEM; - goto error; - } - - result = VMCI_InitLock(&context->lock, "VMCIContextLock", - VMCI_LOCK_RANK_CONTEXT); - if (result < VMCI_SUCCESS) { - goto error; - } - Atomic_Write(&context->refCount, 1); - -#if defined(VMKERNEL) - result = VMCIMutex_Init(&context->guestMemMutex, "VMCIGuestMem", - VMCI_SEMA_RANK_GUESTMEM); - if (result < VMCI_SUCCESS) { - VMCI_CleanupLock(&context->lock); - goto error; - } - context->curGuestMemID = INVALID_VMCI_GUEST_MEM_ID; - - context->inFilters = NULL; -#endif - - /* Inititialize host-specific VMCI context. */ - VMCIHost_InitContext(&context->hostContext, eventHnd); - - context->privFlags = privFlags; - - /* - * If we collide with an existing context we generate a new and use it - * instead. The VMX will determine if regeneration is okay. Since there - * isn't 4B - 16 VMs running on a given host, the below loop will terminate. - */ - VMCI_GrabLock(&contextList.lock, &flags); - ASSERT(cid != VMCI_INVALID_ID); - while (VMCIContextExists(cid)) { - - /* - * If the cid is below our limit and we collide we are creating duplicate - * contexts internally so we want to assert fail in that case. - */ - ASSERT(cid >= VMCI_RESERVED_CID_LIMIT); - - /* We reserve the lowest 16 ids for fixed contexts. */ - cid = MAX(cid, VMCI_RESERVED_CID_LIMIT-1) + 1; - if (cid == VMCI_INVALID_ID) { - cid = VMCI_RESERVED_CID_LIMIT; - } - } - ASSERT(!VMCIContextExists(cid)); - context->cid = cid; - context->validUser = user != NULL; - if (context->validUser) { - context->user = *user; - } - VMCIList_Insert(&context->listItem, &contextList.head); - VMCI_ReleaseLock(&contextList.lock, flags); - -#ifdef VMKERNEL - VMCIContext_SetFSRState(context, FALSE, VMCI_INVALID_ID, eventHnd, FALSE); -#endif - -#ifndef VMX86_SERVER - context->notify = NULL; -# ifdef __linux__ - context->notifyPage = NULL; -# endif -#endif - - *outContext = context; - return VMCI_SUCCESS; - -error: - if (context->notifierArray) { - VMCIHandleArray_Destroy(context->notifierArray); - } - if (context->queuePairArray) { - VMCIHandleArray_Destroy(context->queuePairArray); - } - if (context->doorbellArray) { - VMCIHandleArray_Destroy(context->doorbellArray); - } - if (context->pendingDoorbellArray) { - VMCIHandleArray_Destroy(context->pendingDoorbellArray); - } - VMCI_FreeKernelMem(context, sizeof *context); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_ReleaseContext -- - * - * Cleans up a VMCI context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_ReleaseContext(VMCIContext *context) // IN -{ - VMCILockFlags flags; - - /* Dequeue VMCI context. */ - - VMCI_GrabLock(&contextList.lock, &flags); - VMCIList_Remove(&context->listItem); - VMCI_ReleaseLock(&contextList.lock, flags); - - VMCIContext_Release(context); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIContextFreeContext -- - * - * Deallocates all parts of a context datastructure. This - * functions doesn't lock the context, because it assumes that - * the caller is holding the last reference to context. As paged - * memory may be freed as part of the call, the function must be - * called without holding any spinlocks as this is not allowed on - * Windows. - * - * Results: - * None. - * - * Side effects: - * Paged memory is freed. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIContextFreeContext(VMCIContext *context) // IN -{ - VMCIListItem *curr; - VMCIListItem *next; - DatagramQueueEntry *dqEntry; - VMCIHandle tempHandle; - - /* Fire event to all contexts interested in knowing this context is dying. */ - VMCIContextFireNotification(context->cid, context->privFlags); - - /* - * Cleanup all queue pair resources attached to context. If the VM dies - * without cleaning up, this code will make sure that no resources are - * leaked. - */ - - tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0); - while (!VMCI_HANDLE_EQUAL(tempHandle, VMCI_INVALID_HANDLE)) { - if (VMCIQPBroker_Detach(tempHandle, context) < VMCI_SUCCESS) { - /* - * When VMCIQPBroker_Detach() succeeds it removes the handle from the - * array. If detach fails, we must remove the handle ourselves. - */ - VMCIHandleArray_RemoveEntry(context->queuePairArray, tempHandle); - } - tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0); - } - - /* - * It is fine to destroy this without locking the datagramQueue, as - * this is the only thread having a reference to the context. - */ - - VMCIList_ScanSafe(curr, next, &context->datagramQueue) { - dqEntry = VMCIList_Entry(curr, DatagramQueueEntry, listItem); - VMCIList_Remove(curr); - ASSERT(dqEntry && dqEntry->dg); - ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg)); - VMCI_FreeKernelMem(dqEntry->dg, dqEntry->dgSize); - VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); - } - - VMCIHandleArray_Destroy(context->notifierArray); - VMCIHandleArray_Destroy(context->queuePairArray); - VMCIHandleArray_Destroy(context->doorbellArray); - VMCIHandleArray_Destroy(context->pendingDoorbellArray); - VMCI_CleanupLock(&context->lock); -#if defined(VMKERNEL) - VMCIContextInFilterCleanup(context); - VMCIMutex_Destroy(&context->guestMemMutex); -#endif - VMCIHost_ReleaseContext(&context->hostContext); -#ifndef VMX86_SERVER -# ifdef __linux__ - /* TODO Windows and Mac OS. */ - VMCIUnsetNotify(context); -# endif -#endif - VMCI_FreeKernelMem(context, sizeof *context); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_PendingDatagrams -- - * - * Returns the current number of pending datagrams. The call may - * also serve as a synchronization point for the datagram queue, - * as no enqueue operations can occur concurrently. - * - * Results: - * Length of datagram queue for the given context. - * - * Side effects: - * Locks datagram queue. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_PendingDatagrams(VMCIId cid, // IN - uint32 *pending) // OUT -{ - VMCIContext *context; - VMCILockFlags flags; - - context = VMCIContext_Get(cid); - if (context == NULL) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCI_GrabLock(&context->lock, &flags); - if (pending) { - *pending = context->pendingDatagrams; - } - VMCI_ReleaseLock(&context->lock, flags); - VMCIContext_Release(context); - - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_EnqueueDatagram -- - * - * Queues a VMCI datagram for the appropriate target VM - * context. - * - * Results: - * Size of enqueued data on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM - VMCIDatagram *dg, // IN: - Bool notify) // IN: -{ - DatagramQueueEntry *dqEntry; - VMCIContext *context; - VMCILockFlags flags; - VMCIHandle dgSrc; - size_t vmciDgSize; - - ASSERT(dg); - vmciDgSize = VMCI_DG_SIZE(dg); - ASSERT(vmciDgSize <= VMCI_MAX_DG_SIZE); - - /* Get the target VM's VMCI context. */ - context = VMCIContext_Get(cid); - if (context == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid context (ID=0x%x).\n", cid)); - return VMCI_ERROR_INVALID_ARGS; - } - - /* Allocate guest call entry and add it to the target VM's queue. */ - dqEntry = VMCI_AllocKernelMem(sizeof *dqEntry, VMCI_MEMORY_NONPAGED); - if (dqEntry == NULL) { - VMCI_WARNING((LGPFX"Failed to allocate memory for datagram.\n")); - VMCIContext_Release(context); - return VMCI_ERROR_NO_MEM; - } - dqEntry->dg = dg; - dqEntry->dgSize = vmciDgSize; - dgSrc = dg->src; - 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 - * exceed the VMCI_MAX_DATAGRAM_QUEUE_SIZE limit on the destination. If the - * pending datagram is from hypervisor, we allow it to be queued at the - * destination side provided we don't reach the - * VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE limit. - */ - if (context->datagramQueueSize + vmciDgSize >= - VMCI_MAX_DATAGRAM_QUEUE_SIZE && - (!VMCI_HANDLE_EQUAL(dgSrc, - VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_CONTEXT_RESOURCE_ID)) || - context->datagramQueueSize + vmciDgSize >= - VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE)) { - VMCI_ReleaseLock(&context->lock, flags); - VMCIContext_Release(context); - VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); - VMCI_DEBUG_LOG(10, (LGPFX"Context (ID=0x%x) receive queue is full.\n", - cid)); - return VMCI_ERROR_NO_RESOURCES; - } - - VMCIList_Insert(&dqEntry->listItem, &context->datagramQueue); - context->pendingDatagrams++; - context->datagramQueueSize += vmciDgSize; - - if (notify) { - VMCIContextSignalNotify(context); - VMCIHost_SignalCall(&context->hostContext); - } - - VMCI_ReleaseLock(&context->lock, flags); - VMCIContext_Release(context); - - return vmciDgSize; -} - -#undef VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextExists -- - * - * Internal helper to check if a context with the specified context - * ID exists. Assumes the contextList.lock is held. - * - * Results: - * TRUE if a context exists with the given cid. - * FALSE otherwise - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Bool -VMCIContextExists(VMCIId cid) // IN -{ - VMCIContext *context; - VMCIListItem *next; - Bool rv = FALSE; - - VMCIList_Scan(next, &contextList.head) { - context = VMCIList_Entry(next, VMCIContext, listItem); - if (context->cid == cid) { - rv = TRUE; - break; - } - } - return rv; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_Exists -- - * - * Verifies whether a context with the specified context ID exists. - * - * Results: - * TRUE if a context exists with the given cid. - * FALSE otherwise - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIContext_Exists(VMCIId cid) // IN -{ - VMCILockFlags flags; - Bool rv; - - VMCI_GrabLock(&contextList.lock, &flags); - rv = VMCIContextExists(cid); - VMCI_ReleaseLock(&contextList.lock, flags); - return rv; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_Get -- - * - * Retrieves VMCI context corresponding to the given cid. - * - * Results: - * VMCI context on success, NULL otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCIContext * -VMCIContext_Get(VMCIId cid) // IN -{ - VMCIContext *context = NULL; - VMCIListItem *next; - VMCILockFlags flags; - - if (cid == VMCI_INVALID_ID) { - return NULL; - } - - VMCI_GrabLock(&contextList.lock, &flags); - if (VMCIList_Empty(&contextList.head)) { - goto out; - } - - VMCIList_Scan(next, &contextList.head) { - context = VMCIList_Entry(next, VMCIContext, listItem); - if (context->cid == cid) { - /* - * At this point, we are sure that the reference count is - * larger already than zero. When starting the destruction of - * a context, we always remove it from the context list - * before decreasing the reference count. As we found the - * context here, it hasn't been destroyed yet. This means - * that we are not about to increase the reference count of - * something that is in the process of being destroyed. - */ - - Atomic_Inc(&context->refCount); - break; - } - } - -out: - VMCI_ReleaseLock(&contextList.lock, flags); - return (context && context->cid == cid) ? context : NULL; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_Release -- - * - * Releases the VMCI context. If this is the last reference to - * the context it will be deallocated. A context is created with - * a reference count of one, and on destroy, it is removed from - * the context list before its reference count is - * decremented. Thus, if we reach zero, we are sure that nobody - * else are about to increment it (they need the entry in the - * context list for that). This function musn't be called with a - * lock held. - * - * Results: - * None. - * - * Side effects: - * Paged memory may be deallocated. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_Release(VMCIContext *context) // IN -{ - uint32 refCount; - ASSERT(context); - refCount = Atomic_ReadDec32(&context->refCount); - if (refCount == 1) { - VMCIContextFreeContext(context); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_DequeueDatagram -- - * - * Dequeues the next datagram and returns it to caller. - * The caller passes in a pointer to the max size datagram - * it can handle and the datagram is only unqueued if the - * size is less than maxSize. If larger maxSize is set to - * the size of the datagram to give the caller a chance to - * set up a larger buffer for the guestcall. - * - * Results: - * On success: 0 if no more pending datagrams, otherwise the size of - * the next pending datagram. - * On failure: appropriate error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_DequeueDatagram(VMCIContext *context, // IN - size_t *maxSize, // IN/OUT: max size of datagram caller can handle. - VMCIDatagram **dg) // OUT: -{ - DatagramQueueEntry *dqEntry; - VMCIListItem *listItem; - VMCILockFlags flags; - int rv; - - ASSERT(context && dg); - - /* Dequeue the next datagram entry. */ - VMCI_GrabLock(&context->lock, &flags); - if (context->pendingDatagrams == 0) { - VMCIContextClearNotifyAndCall(context); - VMCI_ReleaseLock(&context->lock, flags); - VMCI_DEBUG_LOG(4, (LGPFX"No datagrams pending.\n")); - return VMCI_ERROR_NO_MORE_DATAGRAMS; - } - - listItem = VMCIList_First(&context->datagramQueue); - ASSERT (listItem != NULL); - - dqEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem); -#if defined(_WIN32) - _Analysis_assume_(dqEntry != NULL); -#endif - ASSERT(dqEntry->dg); - - /* Check size of caller's buffer. */ - if (*maxSize < dqEntry->dgSize) { - *maxSize = dqEntry->dgSize; - VMCI_ReleaseLock(&context->lock, flags); - VMCI_DEBUG_LOG(4, (LGPFX"Caller's buffer should be at least " - "(size=%u bytes).\n", (uint32)*maxSize)); - return VMCI_ERROR_NO_MEM; - } - - VMCIList_Remove(listItem); - context->pendingDatagrams--; - context->datagramQueueSize -= dqEntry->dgSize; - if (context->pendingDatagrams == 0) { - VMCIContextClearNotifyAndCall(context); - rv = VMCI_SUCCESS; - } else { - /* - * Return the size of the next datagram. - */ - DatagramQueueEntry *nextEntry; - - listItem = VMCIList_First(&context->datagramQueue); - ASSERT(listItem); - nextEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem); -#if defined(_WIN32) - _Analysis_assume_(nextEntry != NULL); -#endif - ASSERT(nextEntry && nextEntry->dg); - /* - * The following size_t -> int truncation is fine as the maximum size of - * a (routable) datagram is 68KB. - */ - rv = (int)nextEntry->dgSize; - } - VMCI_ReleaseLock(&context->lock, flags); - - /* Caller must free datagram. */ - ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg)); - *dg = dqEntry->dg; - dqEntry->dg = NULL; - VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); - - return rv; -} - - -#ifdef VMKERNEL -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SetFSRState -- - * - * Set the states related to FSR (quiesced state, migrateCid, - * active event handle). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_SetFSRState(VMCIContext *context, // IN - Bool isQuiesced, // IN - VMCIId migrateCid, // IN - uintptr_t eventHnd, // IN - Bool isLocked) // IN -{ - VMCILockFlags flags; - if (!context) { - return; - } - if (!isLocked) { - VMCI_GrabLock(&context->lock, &flags); - } - context->isQuiesced = isQuiesced; - context->migrateCid = migrateCid; - VMCIHost_SetActiveHnd(&context->hostContext, eventHnd); - if (!isLocked) { - VMCI_ReleaseLock(&context->lock, flags); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_FindAndUpdateSrcFSR -- - * - * Find the source context for fast-suspend-resume. If found, the - * source context's FSR state is changed to reflect the new active - * event handle. - * - * Results: - * If found, source context for fast-suspend-resume, NULL otherwise. - * - * Side effects: - * The source context reference count increased and the caller is - * supposed to release the context once it is done using it. - * - *---------------------------------------------------------------------- - */ - -VMCIContext * -VMCIContext_FindAndUpdateSrcFSR(VMCIId migrateCid, // IN - uintptr_t eventHnd, // IN - uintptr_t *srcEventHnd) // IN/OUT -{ - VMCIContext *contextSrc = VMCIContext_Get(migrateCid); - - if (contextSrc) { - VMCILockFlags flags; - - VMCI_GrabLock(&contextSrc->lock, &flags); - if (contextSrc->isQuiesced && contextSrc->migrateCid == migrateCid) { - if (srcEventHnd) { - *srcEventHnd = VMCIHost_GetActiveHnd(&contextSrc->hostContext); - ASSERT(*srcEventHnd != VMCI_INVALID_ID); - } - VMCIContext_SetFSRState(contextSrc, FALSE, VMCI_INVALID_ID, - eventHnd, TRUE); - VMCI_ReleaseLock(&contextSrc->lock, flags); - return contextSrc; - } - VMCI_ReleaseLock(&contextSrc->lock, flags); - VMCIContext_Release(contextSrc); - } - return NULL; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_IsActiveHnd -- - * - * Whether the curent event handle is the active handle. - * - * Results: - * TRUE if the event handle is active, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIContext_IsActiveHnd(VMCIContext *context, // IN - uintptr_t eventHnd) // IN -{ - VMCILockFlags flags; - Bool isActive; - - ASSERT(context); - VMCI_GrabLock(&context->lock, &flags); - isActive = VMCIHost_IsActiveHnd(&context->hostContext, eventHnd); - VMCI_ReleaseLock(&context->lock, flags); - return isActive; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_GetActiveHnd -- - * - * Returns the curent event handle. - * - * Results: - * The current active handle. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -uintptr_t -VMCIContext_GetActiveHnd(VMCIContext *context) // IN -{ - VMCILockFlags flags; - uintptr_t activeHnd; - - ASSERT(context); - VMCI_GrabLock(&context->lock, &flags); - activeHnd = VMCIHost_GetActiveHnd(&context->hostContext); - VMCI_ReleaseLock(&context->lock, flags); - return activeHnd; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SetInactiveHnd -- - * - * Set the handle to be the inactive one. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_SetInactiveHnd(VMCIContext *context, // IN - uintptr_t eventHnd) // IN -{ - VMCILockFlags flags; - - ASSERT(context); - VMCI_GrabLock(&context->lock, &flags); - VMCIHost_SetInactiveHnd(&context->hostContext, eventHnd); - VMCI_ReleaseLock(&context->lock, flags); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_RemoveHnd -- - * - * Remove the event handle from host context. - * - * Results: - * Whether the handle exists and removed, also number of handles - * before removal and number of handles after removal. - * - * Side effects: - * If this is active handle, the inactive handle becomes active. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIContext_RemoveHnd(VMCIContext *context, // IN - uintptr_t eventHnd, // IN - uint32 *numOld, // OUT - uint32 *numNew) // OUT -{ - VMCILockFlags flags; - uint32 numHandleOld, numHandleNew; - Bool ret; - - ASSERT(context); - VMCI_GrabLock(&context->lock, &flags); - numHandleOld = VMCIHost_NumHnds(&context->hostContext); - ret = VMCIHost_RemoveHnd(&context->hostContext, eventHnd); - numHandleNew = VMCIHost_NumHnds(&context->hostContext); - /* - * This is needed to prevent FSR to share this - * context while this context is being destroyed. - */ - if (ret && numHandleOld == 1 && numHandleNew == 1) { - context->migrateCid = VMCI_INVALID_ID; - } - VMCI_ReleaseLock(&context->lock, flags); - - if (numOld) { - *numOld = numHandleOld; - } - if (numNew) { - *numNew = numHandleNew; - } - return ret; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIContext_ClearDatagrams -- - * - * Clear pending datagrams. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIContext_ClearDatagrams(VMCIContext *context) // IN -{ - int retval; - VMCIDatagram *dg = NULL; - size_t size = VMCI_MAX_DG_SIZE; - uint32 pending; - - /* Drop all datagrams that are currently pending for given context. */ - if (context == NULL) { - return; - } - retval = VMCIContext_PendingDatagrams(context->cid, &pending); - if (retval != VMCI_SUCCESS) { - /* - * This shouldn't happen as we already verified that the context - * exists. - */ - - ASSERT(FALSE); - return; - } - - /* - * We drain the queue for any datagrams pending at the beginning of - * the loop. As datagrams may arrive at any point in time, we - * cannot guarantee that the queue is empty after this point. Only - * removing a fixed number of pending datagrams prevents us from - * looping forever. - */ - - while (pending > 0 && - VMCIContext_DequeueDatagram(context, &size, &dg) >= 0) { - ASSERT(dg); - VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg)); - --pending; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SetId -- - * - * Set the cid of given VMCI context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_SetId(VMCIContext *context, // IN - VMCIId cid) // IN: -{ - VMCILockFlags flags; - - if (!context) { - return; - } - VMCI_GrabLock(&context->lock, &flags); - context->cid = cid; - VMCI_ReleaseLock(&context->lock, flags); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextGenerateEvent -- - * - * Generates a VMCI event that only takes context ID as event data. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -VMCIContextGenerateEvent(VMCIId cid, // IN - VMCI_Event event) // IN -{ - VMCIEventMsg *eMsg; - VMCIEventPayload_Context *ePayload; - /* buf is only 48 bytes. */ - char buf[sizeof *eMsg + sizeof *ePayload]; - - eMsg = (VMCIEventMsg *)buf; - ePayload = VMCIEventMsgPayload(eMsg); - - eMsg->hdr.dst = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID, VMCI_EVENT_HANDLER); - eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_CONTEXT_RESOURCE_ID); - eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *ePayload - sizeof eMsg->hdr; - eMsg->eventData.event = event; - ePayload->contextID = cid; - - (void)VMCIEvent_Dispatch((VMCIDatagram *)eMsg); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_NotifyGuestPaused -- - * - * Notify subscribers of a execution state change of the VM - * with the given context ID. This will happen when a VM is - * quiesced/unquiesced. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_NotifyGuestPaused(VMCIId cid, // IN - Bool paused) // IN -{ - VMCIContextGenerateEvent(cid, paused ? VMCI_EVENT_GUEST_PAUSED : - VMCI_EVENT_GUEST_UNPAUSED); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_NotifyMemoryAccess -- - * - * Notify subscribers of a memory access change to the device. - * This can occur when the device is enabled/disabled/reset. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_NotifyMemoryAccess(VMCIId cid, // IN - Bool on) // IN -{ - VMCIContextGenerateEvent(cid, on ? VMCI_EVENT_MEM_ACCESS_ON : - VMCI_EVENT_MEM_ACCESS_OFF); -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_GetId -- - * - * Retrieves cid of given VMCI context. - * - * Results: - * VMCIId of context on success, VMCI_INVALID_ID otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCIId -VMCIContext_GetId(VMCIContext *context) // IN: -{ - if (!context) { - return VMCI_INVALID_ID; - } - ASSERT(context->cid != VMCI_INVALID_ID); - return context->cid; -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_context_get_priv_flags -- - * - * Retrieves the privilege flags of the given VMCI context ID. - * - * Results: - * Context's privilege flags. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_context_get_priv_flags) -VMCIPrivilegeFlags -vmci_context_get_priv_flags(VMCIId contextID) // IN -{ - if (VMCI_HostPersonalityActive()) { - VMCIPrivilegeFlags flags; - VMCIContext *context; - - context = VMCIContext_Get(contextID); - if (!context) { - return VMCI_LEAST_PRIVILEGE_FLAGS; - } - flags = context->privFlags; - VMCIContext_Release(context); - return flags; - } - return VMCI_NO_PRIVILEGE_FLAGS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_AddNotification -- - * - * Add remoteCID to list of contexts current contexts wants - * notifications from/about. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * As in VMCIHandleArray_AppendEntry(). - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_AddNotification(VMCIId contextID, // IN: - VMCIId remoteCID) // IN: -{ - int result = VMCI_ERROR_ALREADY_EXISTS; - VMCILockFlags flags; - VMCILockFlags firingFlags; - VMCIHandle notifierHandle; - VMCIContext *context = VMCIContext_Get(contextID); - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - - if (VMCI_CONTEXT_IS_VM(contextID) && VMCI_CONTEXT_IS_VM(remoteCID)) { - VMCI_DEBUG_LOG(4, (LGPFX"Context removed notifications for other VMs not " - "supported (src=0x%x, remote=0x%x).\n", - contextID, remoteCID)); - result = VMCI_ERROR_DST_UNREACHABLE; - goto out; - } - - if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) { - result = VMCI_ERROR_NO_ACCESS; - goto out; - } - - notifierHandle = VMCI_MAKE_HANDLE(remoteCID, VMCI_EVENT_HANDLER); - VMCI_GrabLock(&contextList.firingLock, &firingFlags); - VMCI_GrabLock(&context->lock, &flags); - if (!VMCIHandleArray_HasEntry(context->notifierArray, notifierHandle)) { - VMCIHandleArray_AppendEntry(&context->notifierArray, notifierHandle); - result = VMCI_SUCCESS; - } - VMCI_ReleaseLock(&context->lock, flags); - VMCI_ReleaseLock(&contextList.firingLock, firingFlags); -out: - VMCIContext_Release(context); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_RemoveNotification -- - * - * Remove remoteCID from current context's list of contexts it is - * interested in getting notifications from/about. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_RemoveNotification(VMCIId contextID, // IN: - VMCIId remoteCID) // IN: -{ - VMCILockFlags flags; - VMCILockFlags firingFlags; - VMCIContext *context = VMCIContext_Get(contextID); - VMCIHandle tmpHandle; - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - VMCI_GrabLock(&contextList.firingLock, &firingFlags); - VMCI_GrabLock(&context->lock, &flags); - tmpHandle = - VMCIHandleArray_RemoveEntry(context->notifierArray, - VMCI_MAKE_HANDLE(remoteCID, - VMCI_EVENT_HANDLER)); - VMCI_ReleaseLock(&context->lock, flags); - VMCI_ReleaseLock(&contextList.firingLock, firingFlags); - VMCIContext_Release(context); - - if (VMCI_HANDLE_EQUAL(tmpHandle, VMCI_INVALID_HANDLE)) { - return VMCI_ERROR_NOT_FOUND; - } - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextFireNotification -- - * - * Fire notification for all contexts interested in given cid. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VMCIContextFireNotification(VMCIId contextID, // IN - VMCIPrivilegeFlags privFlags) // IN -{ - uint32 i, arraySize; - VMCIListItem *next; - VMCILockFlags flags; - VMCILockFlags firingFlags; - VMCIHandleArray *subscriberArray; - VMCIHandle contextHandle = VMCI_MAKE_HANDLE(contextID, VMCI_EVENT_HANDLER); - - /* - * We create an array to hold the subscribers we find when scanning through - * all contexts. - */ - subscriberArray = VMCIHandleArray_Create(0); - if (subscriberArray == NULL) { - return VMCI_ERROR_NO_MEM; - } - - /* - * Scan all contexts to find who is interested in being notified about - * given contextID. We have a special firingLock that we use to synchronize - * across all notification operations. This avoids us having to take the - * context lock for each HasEntry call and it solves a lock ranking issue. - */ - VMCI_GrabLock(&contextList.firingLock, &firingFlags); - VMCI_GrabLock(&contextList.lock, &flags); - VMCIList_Scan(next, &contextList.head) { - VMCIContext *subCtx = VMCIList_Entry(next, VMCIContext, listItem); - - /* - * We only deliver notifications of the removal of contexts, if - * the two contexts are allowed to interact. - */ - - if (VMCIHandleArray_HasEntry(subCtx->notifierArray, contextHandle) && - !VMCIDenyInteraction(privFlags, subCtx->privFlags)) { - VMCIHandleArray_AppendEntry(&subscriberArray, - VMCI_MAKE_HANDLE(subCtx->cid, - VMCI_EVENT_HANDLER)); - } - } - VMCI_ReleaseLock(&contextList.lock, flags); - VMCI_ReleaseLock(&contextList.firingLock, firingFlags); - - /* Fire event to all subscribers. */ - arraySize = VMCIHandleArray_GetSize(subscriberArray); - for (i = 0; i < arraySize; i++) { - int result; - VMCIEventMsg *eMsg; - VMCIEventPayload_Context *evPayload; - char buf[sizeof *eMsg + sizeof *evPayload]; - - eMsg = (VMCIEventMsg *)buf; - - /* Clear out any garbage. */ - memset(eMsg, 0, sizeof *eMsg + sizeof *evPayload); - eMsg->hdr.dst = VMCIHandleArray_GetEntry(subscriberArray, i); - eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_CONTEXT_RESOURCE_ID); - eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *evPayload - - sizeof eMsg->hdr; - eMsg->eventData.event = VMCI_EVENT_CTX_REMOVED; - evPayload = VMCIEventMsgPayload(eMsg); - evPayload->contextID = contextID; - - result = VMCIDatagram_Dispatch(VMCI_HYPERVISOR_CONTEXT_ID, - (VMCIDatagram *)eMsg, FALSE); - if (result < VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to enqueue event datagram " - "(type=%d) for context (ID=0x%x).\n", - eMsg->eventData.event, eMsg->hdr.dst.context)); - /* We continue to enqueue on next subscriber. */ - } - } - VMCIHandleArray_Destroy(subscriberArray); - - return VMCI_SUCCESS; -} - -/* - *---------------------------------------------------------------------- - * - * VMCIContextDgHypervisorSaveStateSize -- - * - * Calculate the size for the hypervisor datagram checkpoint - * save data. - * - * The format is as follows: - * - * uint32 count - number of entries - * uint32 size - size of first entry - * char bytes[] - contents of first entry - * uint32 size - size of second entry - * char bytes[] - contents of second entry - * ... - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VMCIContextDgHypervisorSaveStateSize(VMCIContext *context, // IN - uint32 *bufSize, // IN/OUT - char **cptBufPtr) // UNUSED -{ - uint32 total; - VMCIListItem *iter; - - UNREFERENCED_PARAMETER(cptBufPtr); - - *bufSize = total = 0; - - VMCIList_Scan(iter, &context->datagramQueue) { - DatagramQueueEntry *dqEntry = - VMCIList_Entry(iter, DatagramQueueEntry, listItem); - - if (dqEntry->dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID) { - /* Size of the datagram followed by the contents of the datagram. */ - total += sizeof(uint32) + dqEntry->dgSize; - } - } - - if (total > 0) { - /* Don't forget the datagram count. */ - *bufSize = total + sizeof(uint32); - } - - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContextDgHypervisorSaveState -- - * - * Get the hypervisor datagram checkpoint save data. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VMCIContextDgHypervisorSaveState(VMCIContext *context, // IN - uint32 *bufSize, // IN/OUT - char **cptBufPtr) // OUT -{ - uint8 *p; - uint32 total; - uint32 count; - VMCIListItem *iter; - - /* Need at least the count field and the size of one entry. */ - if (*bufSize < sizeof(uint32) * 2) { - return VMCI_ERROR_INVALID_ARGS; - } - - p = VMCI_AllocKernelMem(*bufSize, VMCI_MEMORY_NONPAGED); - if (p == NULL) { - return VMCI_ERROR_NO_MEM; - } - - *cptBufPtr = (char *)p; - - /* Leave space for the datagram count at the start. */ - total = sizeof(uint32); - p += sizeof(uint32); - - count = 0; - VMCIList_Scan(iter, &context->datagramQueue) { - DatagramQueueEntry *dqEntry = - VMCIList_Entry(iter, DatagramQueueEntry, listItem); - - if (dqEntry->dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID) { - - /* - * VMX might have capped the amount of space we can use to checkpoint - * hypervisor datagrams. Respect that here. Those that are not written - * to the buffer will get dropped. - */ - - if (total + sizeof(uint32) + dqEntry->dgSize > *bufSize) { - break; - } - - total += sizeof(uint32) + dqEntry->dgSize; - - /* - * Write in the size of the datagram followed by the contents of the - * datagram itself. - */ - - *(uint32 *)p = dqEntry->dgSize; - p += sizeof(uint32); - - memcpy(p, dqEntry->dg, dqEntry->dgSize); - p += dqEntry->dgSize; - - count++; - } - } - - /* Now rollback and write the count at the start of the block. */ - *(uint32 *)(*cptBufPtr) = count; - - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_GetCheckpointState -- - * - * Get current context's checkpoint state of given type. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_GetCheckpointState(VMCIId contextID, // IN: - uint32 cptType, // IN: - uint32 *bufSize, // IN/OUT: - char **cptBufPtr) // OUT: -{ - int i, result; - VMCILockFlags flags; - uint32 arraySize, cptDataSize; - VMCIHandleArray *array; - VMCIContext *context; - char *cptBuf; - Bool getContextID; - - ASSERT(bufSize && cptBufPtr); - - context = VMCIContext_Get(contextID); - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - - VMCI_GrabLock(&context->lock, &flags); - if (cptType == VMCI_NOTIFICATION_CPT_STATE) { - ASSERT(context->notifierArray); - array = context->notifierArray; - getContextID = TRUE; - } else if (cptType == VMCI_WELLKNOWN_CPT_STATE) { - /* - * For compatibility with VMX'en with VM to VM communication, we - * always return zero wellknown handles. - */ - - *bufSize = 0; - *cptBufPtr = NULL; - result = VMCI_SUCCESS; - goto release; - } else if (cptType == VMCI_DOORBELL_CPT_STATE) { - ASSERT(context->doorbellArray); - array = context->doorbellArray; - getContextID = FALSE; - } else if (cptType == VMCI_DG_HYPERVISOR_SAVE_STATE_SIZE) { - result = VMCIContextDgHypervisorSaveStateSize(context, bufSize, cptBufPtr); - goto release; - } else if (cptType == VMCI_DG_HYPERVISOR_SAVE_STATE) { - result = VMCIContextDgHypervisorSaveState(context, bufSize, cptBufPtr); - goto release; - } else { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType)); - result = VMCI_ERROR_INVALID_ARGS; - goto release; - } - - arraySize = VMCIHandleArray_GetSize(array); - if (arraySize > 0) { - if (cptType == VMCI_DOORBELL_CPT_STATE) { - cptDataSize = arraySize * sizeof(VMCIDoorbellCptState); - } else { - cptDataSize = arraySize * sizeof(VMCIId); - } - if (*bufSize < cptDataSize) { - *bufSize = cptDataSize; - result = VMCI_ERROR_MORE_DATA; - goto release; - } - - cptBuf = VMCI_AllocKernelMem(cptDataSize, - VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC); - if (cptBuf == NULL) { - result = VMCI_ERROR_NO_MEM; - goto release; - } - - for (i = 0; i < arraySize; i++) { - VMCIHandle tmpHandle = VMCIHandleArray_GetEntry(array, i); - if (cptType == VMCI_DOORBELL_CPT_STATE) { -/* - * PreFAST thinks this might overflow on arraySize>=2. However, we've - * looked *very* carefully at this, tested PreFAST's assumptions, and - * concluded PreFAST is getting confused about the relationships between - * cptDataSize, arraySize, and i. - */ -#if defined(_WIN32) -#pragma warning(suppress: 6386) -#endif - ((VMCIDoorbellCptState *)cptBuf)[i].handle = tmpHandle; - } else { - ((VMCIId *)cptBuf)[i] = - getContextID ? tmpHandle.context : tmpHandle.resource; - } - } - *bufSize = cptDataSize; - *cptBufPtr = cptBuf; - } else { - *bufSize = 0; - *cptBufPtr = NULL; - } - result = VMCI_SUCCESS; - -release: - VMCI_ReleaseLock(&context->lock, flags); - VMCIContext_Release(context); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SetCheckpointState -- - * - * Set current context's checkpoint state of given type. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_SetCheckpointState(VMCIId contextID, // IN: - uint32 cptType, // IN: - uint32 bufSize, // IN: - char *cptBuf) // IN: -{ - uint32 i; - VMCIId currentID; - int result = VMCI_SUCCESS; - uint32 numIDs = bufSize / sizeof(VMCIId); - ASSERT(cptBuf); - - if (cptType == VMCI_WELLKNOWN_CPT_STATE && numIDs > 0) { - /* - * We would end up here if VMX with VM to VM communication - * attempts to restore a checkpoint with wellknown handles. - */ - - VMCI_WARNING((LGPFX"Attempt to restore checkpoint with obsolete " - "wellknown handles.\n")); - return VMCI_ERROR_OBSOLETE; - } - - if (cptType != VMCI_NOTIFICATION_CPT_STATE) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType)); - return VMCI_ERROR_INVALID_ARGS; - } - - for (i = 0; i < numIDs && result == VMCI_SUCCESS; i++) { - currentID = ((VMCIId *)cptBuf)[i]; - result = VMCIContext_AddNotification(contextID, currentID); - if (result != VMCI_SUCCESS) { - break; - } - } - if (result != VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to set cpt state (type=%d) (error=%d).\n", - cptType, result)); - } - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_ReceiveNotificationsGet -- - * - * Retrieves the specified context's pending notifications in the - * form of a handle array. The handle arrays returned are the - * actual data - not a copy and should not be modified by the - * caller. They must be released using - * VMCIContext_ReceiveNotificationsRelease. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_ReceiveNotificationsGet(VMCIId contextID, // IN - VMCIHandleArray **dbHandleArray, // OUT - VMCIHandleArray **qpHandleArray) // OUT -{ - VMCIContext *context; - VMCILockFlags flags; - int result = VMCI_SUCCESS; - - ASSERT(dbHandleArray && qpHandleArray); - - context = VMCIContext_Get(contextID); - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - VMCI_GrabLock(&context->lock, &flags); - - *dbHandleArray = context->pendingDoorbellArray; - context->pendingDoorbellArray = VMCIHandleArray_Create(0); - if (!context->pendingDoorbellArray) { - context->pendingDoorbellArray = *dbHandleArray; - *dbHandleArray = NULL; - result = VMCI_ERROR_NO_MEM; - } - *qpHandleArray = NULL; - - VMCI_ReleaseLock(&context->lock, flags); - VMCIContext_Release(context); - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_ReceiveNotificationsRelease -- - * - * Releases handle arrays with pending notifications previously - * retrieved using VMCIContext_ReceiveNotificationsGet. If the - * notifications were not successfully handed over to the guest, - * success must be false. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_ReceiveNotificationsRelease(VMCIId contextID, // IN - VMCIHandleArray *dbHandleArray, // IN - VMCIHandleArray *qpHandleArray, // IN - Bool success) // IN -{ - VMCIContext *context = VMCIContext_Get(contextID); - - if (context) { - VMCILockFlags flags; - - VMCI_GrabLock(&context->lock, &flags); - if (!success) { - VMCIHandle handle; - - /* - * New notifications may have been added while we were not - * holding the context lock, so we transfer any new pending - * doorbell notifications to the old array, and reinstate the - * old array. - */ - - handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray); - while (!VMCI_HANDLE_INVALID(handle)) { - ASSERT(VMCIHandleArray_HasEntry(context->doorbellArray, handle)); - if (!VMCIHandleArray_HasEntry(dbHandleArray, handle)) { - VMCIHandleArray_AppendEntry(&dbHandleArray, handle); - } - handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray); - } - VMCIHandleArray_Destroy(context->pendingDoorbellArray); - context->pendingDoorbellArray = dbHandleArray; - dbHandleArray = NULL; - } else { - VMCIContextClearNotifyAndCall(context); - } - VMCI_ReleaseLock(&context->lock, flags); - VMCIContext_Release(context); - } else { - /* - * The OS driver part is holding on to the context for the - * duration of the receive notification ioctl, so it should - * still be here. - */ - - ASSERT(FALSE); - } - - if (dbHandleArray) { - VMCIHandleArray_Destroy(dbHandleArray); - } - if (qpHandleArray) { - VMCIHandleArray_Destroy(qpHandleArray); - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_DoorbellCreate -- - * - * Registers that a new doorbell handle has been allocated by the - * context. Only doorbell handles registered can be notified. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherewise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_DoorbellCreate(VMCIId contextID, // IN - VMCIHandle handle) // IN -{ - VMCIContext *context; - VMCILockFlags flags; - int result; - - if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - context = VMCIContext_Get(contextID); - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - - VMCI_GrabLock(&context->lock, &flags); - if (!VMCIHandleArray_HasEntry(context->doorbellArray, handle)) { - VMCIHandleArray_AppendEntry(&context->doorbellArray, handle); - result = VMCI_SUCCESS; - } else { - result = VMCI_ERROR_DUPLICATE_ENTRY; - } - VMCI_ReleaseLock(&context->lock, flags); - - VMCIContext_Release(context); - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_DoorbellDestroy -- - * - * Unregisters a doorbell handle that was previously registered - * with VMCIContext_DoorbellCreate. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherewise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_DoorbellDestroy(VMCIId contextID, // IN - VMCIHandle handle) // IN -{ - VMCIContext *context; - VMCILockFlags flags; - VMCIHandle removedHandle; - - if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - context = VMCIContext_Get(contextID); - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - - VMCI_GrabLock(&context->lock, &flags); - removedHandle = VMCIHandleArray_RemoveEntry(context->doorbellArray, handle); - VMCIHandleArray_RemoveEntry(context->pendingDoorbellArray, handle); - VMCI_ReleaseLock(&context->lock, flags); - - VMCIContext_Release(context); - - if (VMCI_HANDLE_INVALID(removedHandle)) { - return VMCI_ERROR_NOT_FOUND; - } else { - return VMCI_SUCCESS; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_DoorbellDestroyAll -- - * - * Unregisters all doorbell handles that were previously - * registered with VMCIContext_DoorbellCreate. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherewise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_DoorbellDestroyAll(VMCIId contextID) // IN -{ - VMCIContext *context; - VMCILockFlags flags; - VMCIHandle removedHandle; - - if (contextID == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - context = VMCIContext_Get(contextID); - if (context == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - - VMCI_GrabLock(&context->lock, &flags); - do { - removedHandle = VMCIHandleArray_RemoveTail(context->doorbellArray); - } while(!VMCI_HANDLE_INVALID(removedHandle)); - do { - removedHandle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray); - } while(!VMCI_HANDLE_INVALID(removedHandle)); - VMCI_ReleaseLock(&context->lock, flags); - - VMCIContext_Release(context); - - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_NotifyDoorbell -- - * - * Registers a notification of a doorbell handle initiated by the - * specified source context. The notification of doorbells are - * subject to the same isolation rules as datagram delivery. To - * allow host side senders of notifications a finer granularity - * of sender rights than those assigned to the sending context - * itself, the host context is required to specify a different - * set of privilege flags that will override the privileges of - * the source context. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherewise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_NotifyDoorbell(VMCIId srcCID, // IN - VMCIHandle handle, // IN - VMCIPrivilegeFlags srcPrivFlags) // IN -{ - VMCIContext *dstContext; - VMCILockFlags flags; - int result; - - if (VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - /* Get the target VM's VMCI context. */ - dstContext = VMCIContext_Get(handle.context); - if (dstContext == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid context (ID=0x%x).\n", handle.context)); - return VMCI_ERROR_NOT_FOUND; - } - - if (srcCID != handle.context) { - VMCIPrivilegeFlags dstPrivFlags; - - if (VMCI_CONTEXT_IS_VM(srcCID) && VMCI_CONTEXT_IS_VM(handle.context)) { - VMCI_DEBUG_LOG(4, (LGPFX"Doorbell notification from VM to VM not " - "supported (src=0x%x, dst=0x%x).\n", - srcCID, handle.context)); - result = VMCI_ERROR_DST_UNREACHABLE; - goto out; - } - - result = VMCIDoorbellGetPrivFlags(handle, &dstPrivFlags); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to get privilege flags for destination " - "(handle=0x%x:0x%x).\n", handle.context, - handle.resource)); - goto out; - } - - if (srcCID != VMCI_HOST_CONTEXT_ID || - srcPrivFlags == VMCI_NO_PRIVILEGE_FLAGS) { - srcPrivFlags = vmci_context_get_priv_flags(srcCID); - } - - if (VMCIDenyInteraction(srcPrivFlags, dstPrivFlags)) { - result = VMCI_ERROR_NO_ACCESS; - goto out; - } - } - - if (handle.context == VMCI_HOST_CONTEXT_ID) { - result = VMCIDoorbellHostContextNotify(srcCID, handle); - } 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 { - if (!VMCIHandleArray_HasEntry(dstContext->pendingDoorbellArray, handle)) { - VMCIHandleArray_AppendEntry(&dstContext->pendingDoorbellArray, handle); - - VMCIContextSignalNotify(dstContext); -#if defined(VMKERNEL) - VMCIHost_SignalBitmap(&dstContext->hostContext); -#else - VMCIHost_SignalCall(&dstContext->hostContext); -#endif - } - result = VMCI_SUCCESS; - } - VMCI_ReleaseLock(&dstContext->lock, flags); - } - -out: - VMCIContext_Release(dstContext); - - return result; -} - - -#ifdef VMKERNEL - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SignalPendingDoorbells -- - * - * Signals the guest if any doorbell notifications are - * pending. This is used after the VMCI device is unquiesced to - * ensure that no pending notifications go unnoticed, since - * signals may not be fully processed while the device is - * quiesced. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_SignalPendingDoorbells(VMCIId contextID) -{ - VMCIContext *context; - VMCILockFlags flags; - Bool pending; - - context = VMCIContext_Get(contextID); - if (!context) { - ASSERT(FALSE); - return; - } - - VMCI_GrabLock(&context->lock, &flags); - pending = VMCIHandleArray_GetSize(context->pendingDoorbellArray) > 0; - VMCI_ReleaseLock(&context->lock, flags); - - if (pending) { - VMCIHost_SignalBitmapAlways(&context->hostContext); - } - - VMCIContext_Release(context); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SignalPendingDatagrams -- - * - * Signals the guest if any datagrams are pending. This is used - * after the VMCI device is unquiesced to ensure that no pending - * datagrams go unnoticed, since signals may not be fully - * processed while the device is quiesced. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_SignalPendingDatagrams(VMCIId contextID) -{ - Bool pending; - VMCIContext *context; - VMCILockFlags flags; - - context = VMCIContext_Get(contextID); - if (!context) { - ASSERT(FALSE); - return; - } - - VMCI_GrabLock(&context->lock, &flags); - pending = context->pendingDatagrams; - VMCI_ReleaseLock(&context->lock, flags); - - if (pending) { - VMCIHost_SignalCallAlways(&context->hostContext); - } - - VMCIContext_Release(context); -} - -#endif // defined(VMKERNEL) - - -/* - *---------------------------------------------------------------------- - * - * vmci_cid_2_host_vm_id -- - * - * Maps a context ID to the host specific (process/world) ID - * of the VM/VMX. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_cid_2_host_vm_id) -int -vmci_cid_2_host_vm_id(VMCIId contextID, // IN - void *hostVmID, // OUT - size_t hostVmIDLen) // IN -{ -#if defined(VMKERNEL) - VMCIContext *context; - VMCIHostVmID vmID; - int result; - - context = VMCIContext_Get(contextID); - if (!context) { - return VMCI_ERROR_NOT_FOUND; - } - - result = VMCIHost_ContextToHostVmID(&context->hostContext, &vmID); - if (result == VMCI_SUCCESS) { - if (sizeof vmID == hostVmIDLen) { - memcpy(hostVmID, &vmID, hostVmIDLen); - } else { - result = VMCI_ERROR_INVALID_ARGS; - } - } - - VMCIContext_Release(context); - - return result; -#else // !defined(VMKERNEL) - UNREFERENCED_PARAMETER(contextID); - UNREFERENCED_PARAMETER(hostVmID); - UNREFERENCED_PARAMETER(hostVmIDLen); - return VMCI_ERROR_UNAVAILABLE; -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_is_context_owner -- - * - * Determines whether a given host OS specific representation of - * user is the owner of the VM/VMX. - * - * Results: - * Linux: 1 (true) if hostUser is owner, 0 (false) otherwise. - * Other: VMCI_SUCCESS if the hostUser is owner, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_is_context_owner) -#if defined(__linux__) && !defined(VMKERNEL) -int -vmci_is_context_owner(VMCIId contextID, // IN - VMCIHostUser uid) // IN -{ - int isOwner = 0; - - if (VMCI_HostPersonalityActive()) { - VMCIContext *context = VMCIContext_Get(contextID); - if (context) { - if (context->validUser) { - if (VMCIHost_CompareUser(&uid, - &context->user) == VMCI_SUCCESS) { - isOwner = 1; - } - } - VMCIContext_Release(context); - } - } - - return isOwner; -} -#else // !linux || VMKERNEL -int -vmci_is_context_owner(VMCIId contextID, // IN - void *hostUser) // IN -{ - if (VMCI_HostPersonalityActive()) { - VMCIContext *context; - VMCIHostUser *user = (VMCIHostUser *)hostUser; - int retval; - - if (vmkernel) { - return VMCI_ERROR_UNAVAILABLE; - } - - if (!hostUser) { - return VMCI_ERROR_INVALID_ARGS; - } - - context = VMCIContext_Get(contextID); - if (!context) { - return VMCI_ERROR_NOT_FOUND; - } - - if (context->validUser) { - retval = VMCIHost_CompareUser(user, &context->user); - } else { - retval = VMCI_ERROR_UNAVAILABLE; - } - VMCIContext_Release(context); - - return retval; - } - return VMCI_ERROR_UNAVAILABLE; -} -#endif // !linux || VMKERNEL - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_SupportsHostQP -- - * - * Can host QPs be connected to this user process. The answer is - * FALSE unless a sufficient version number has previously been set - * by this caller. - * - * Results: - * TRUE if context supports host queue pairs, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIContext_SupportsHostQP(VMCIContext *context) // IN: Context structure -{ -#ifdef VMKERNEL - return TRUE; -#else - if (!context || context->userVersion < VMCI_VERSION_HOSTQP) { - return FALSE; - } - return TRUE; -#endif -} - - - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_QueuePairCreate -- - * - * Registers that a new queue pair handle has been allocated by - * the context. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherewise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_QueuePairCreate(VMCIContext *context, // IN: Context structure - VMCIHandle handle) // IN -{ - int result; - - if (context == NULL || VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) { - VMCIHandleArray_AppendEntry(&context->queuePairArray, handle); - result = VMCI_SUCCESS; - } else { - result = VMCI_ERROR_DUPLICATE_ENTRY; - } - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_QueuePairDestroy -- - * - * Unregisters a queue pair handle that was previously registered - * with VMCIContext_QueuePairCreate. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherewise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIContext_QueuePairDestroy(VMCIContext *context, // IN: Context structure - VMCIHandle handle) // IN -{ - VMCIHandle removedHandle; - - if (context == NULL || VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - removedHandle = VMCIHandleArray_RemoveEntry(context->queuePairArray, handle); - - if (VMCI_HANDLE_INVALID(removedHandle)) { - return VMCI_ERROR_NOT_FOUND; - } else { - return VMCI_SUCCESS; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_QueuePairExists -- - * - * Determines whether a given queue pair handle is registered - * with the given context. - * - * Results: - * TRUE, if queue pair is registered with context. FALSE, otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIContext_QueuePairExists(VMCIContext *context, // IN: Context structure - VMCIHandle handle) // IN -{ - Bool result; - - if (context == NULL || VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIHandleArray_HasEntry(context->queuePairArray, handle); - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_RegisterGuestMem -- - * - * Tells the context that guest memory is available for - * access. This should only be used when unquiescing the VMCI - * device of a guest. - * - * Results: - * None. - * - * Side effects: - * Notifies host side endpoints of queue pairs that the queue pairs - * can be accessed. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_RegisterGuestMem(VMCIContext *context, // IN: Context structure - VMCIGuestMemID gid) // IN: Reference to guest -{ -#ifdef VMKERNEL - uint32 numQueuePairs; - uint32 cur; - - VMCIMutex_Acquire(&context->guestMemMutex); - - if (context->curGuestMemID != INVALID_VMCI_GUEST_MEM_ID) { - if (context->curGuestMemID != gid) { - /* - * The guest memory has been registered with a different guest - * memory ID. This is possible if we attempt to continue the - * execution of the source VMX following a failed FSR. - */ - - VMCIContextReleaseGuestMemLocked(context, context->curGuestMemID, - FALSE); - } else { - /* - * When unquiescing the device during a restore sync not part - * of an FSR, we will already have registered the guest - * memory when creating the device, so we don't need to do it - * again. Also, there are no active queue pairs at this - * point, so nothing to do. - */ - - ASSERT(VMCIHandleArray_GetSize(context->queuePairArray) == 0); - goto out; - } - } - context->curGuestMemID = gid; - - /* - * It is safe to access the queue pair array here, since no changes - * to the queuePairArray can take place until after the unquiescing - * is complete. - */ - - numQueuePairs = VMCIHandleArray_GetSize(context->queuePairArray); - for (cur = 0; cur < numQueuePairs; cur++) { - VMCIHandle handle; - handle = VMCIHandleArray_GetEntry(context->queuePairArray, cur); - if (!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) { - int res; - - res = VMCIQPBroker_Map(handle, context, NULL); - if (res < VMCI_SUCCESS) { - VMCI_WARNING(("Failed to map guest memory for queue pair " - "(handle=0x%x:0x%x, res=%d).\n", - handle.context, handle.resource, res)); - } - } - } - -out: - VMCIMutex_Release(&context->guestMemMutex); -#else - UNREFERENCED_PARAMETER(context); - UNREFERENCED_PARAMETER(gid); -#endif -} - - -#ifdef VMKERNEL -/* - *---------------------------------------------------------------------- - * - * VMCIContextReleaseGuestMemLocked -- - * - * A version of VMCIContext_ReleaseGuestMem that assumes that the - * guest mem lock is already held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -VMCIContextReleaseGuestMemLocked(VMCIContext *context, // IN: Context structure - VMCIGuestMemID gid, // IN: Reference to guest - Bool powerOff) // IN: Device going away -{ - uint32 numQueuePairs; - uint32 cur; - - if (powerOff) { - VMCIContext_NotifyMemoryAccess(context->cid, FALSE); - } - - /* - * It is safe to access the queue pair array here, since no changes - * to the queuePairArray can take place when the the quiescing - * has been initiated, or when the device is being cleaned up. - */ - - numQueuePairs = VMCIHandleArray_GetSize(context->queuePairArray); - for (cur = 0; cur < numQueuePairs; cur++) { - VMCIHandle handle; - handle = VMCIHandleArray_GetEntry(context->queuePairArray, cur); - if (!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) { - int res; - - res = VMCIQPBroker_Unmap(handle, context, gid); - if (res < VMCI_SUCCESS) { - VMCI_WARNING(("Failed to unmap guest memory for queue pair " - "(handle=0x%x:0x%x, res=%d).\n", - handle.context, handle.resource, res)); - } - } - } -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * VMCIContext_ReleaseGuestMem -- - * - * Releases all the contexts references to guest memory, if the - * caller identified by the gid was the last one to register the - * guest memory. This should only be used when quiescing or - * cleaning up the VMCI device of a guest. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIContext_ReleaseGuestMem(VMCIContext *context, // IN: Context structure - VMCIGuestMemID gid, // IN: Reference to guest - Bool powerOff) // IN: Device is going away -{ -#ifdef VMKERNEL - VMCIMutex_Acquire(&context->guestMemMutex); - - if (context->curGuestMemID == gid) { - /* - * In the case of an FSR, we may have multiple VMX'en - * registering and releasing guest memory concurrently. The - * common case is that the source will clean up its device state - * after a successful FSR, where the destination may already - * have registered guest memory. So we only release guest - * memory, if this is the same gid, that registered the memory. - */ - - VMCIContextReleaseGuestMemLocked(context, gid, powerOff); - context->curGuestMemID = INVALID_VMCI_GUEST_MEM_ID; - } - - VMCIMutex_Release(&context->guestMemMutex); -#else - UNREFERENCED_PARAMETER(context); - UNREFERENCED_PARAMETER(gid); - UNREFERENCED_PARAMETER(powerOff); -#endif -} - -#if defined(VMKERNEL) -/* - *---------------------------------------------------------------------- - * - * VMCIContext_RevalidateMappings -- - * - * Updates the mappings for all QPs. Should only be called with the VMCI - * device lock held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIContext_RevalidateMappings(VMCIContext *context) // IN: Context structure -{ - uint32 numQueuePairs; - uint32 cur; - - numQueuePairs = VMCIHandleArray_GetSize(context->queuePairArray); - for (cur = 0; cur < numQueuePairs; cur++) { - VMCIHandle handle; - - handle = VMCIHandleArray_GetEntry(context->queuePairArray, cur); - if (!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) { - int res = VMCIQPBroker_Revalidate(handle, context); - - if (res < VMCI_SUCCESS) { - VMCI_WARNING(("Failed to revalidate guest mappings for queue " - " pair (handle=0x%x:0x%x, res=%d).\n", - handle.context, handle.resource, res)); - /* - * I have not seen these errors but I do not think they should be - * considered fatal. - */ - if (res != VMCI_ERROR_NOT_FOUND && - res != VMCI_ERROR_QUEUEPAIR_NOTATTACHED) { - return FALSE; - } - } - } - } - - return TRUE; -} - - -/* - *---------------------------------------------------------------------- - * - * 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; - } -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_Uuid2ContextId -- - * - * Given a running VM's UUID, retrieve the VM's VMCI context ID. - * The given UUID is local to the host; it is _not_ the UUID - * handed out by VC. It comes from the "bios.uuid" field in the - * VMX file. We walk the context list and try to match the given - * UUID against each context. If we get a match, we return the - * contexts's VMCI ID. - * - * Results: - * VMCI_SUCCESS if found and *contextID contains the CID. - * VMCI_ERROR_INVALID_ARGS for bad parameters. - * VMCI_ERROR_NOT_FOUND if no match. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCI_Uuid2ContextId(const char *uuidString, // IN - VMCIId *contextID) // OUT -{ - int err; - VMCIListItem *next; - VMCILockFlags flags; - - if (!uuidString || *uuidString == '\0' || !contextID) { - return VMCI_ERROR_INVALID_ARGS; - } - - err = VMCI_ERROR_NOT_FOUND; - - VMCI_GrabLock(&contextList.lock, &flags); - VMCIList_Scan(next, &contextList.head) { - VMCIContext *context = VMCIList_Entry(next, VMCIContext, listItem); - if (VMCIHost_ContextHasUuid(&context->hostContext, uuidString) == - VMCI_SUCCESS) { - *contextID = context->cid; - err = VMCI_SUCCESS; - break; - } - } - VMCI_ReleaseLock(&contextList.lock, flags); - - return err; -} -#endif // VMKERNEL diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.h b/open-vm-tools/modules/linux/vmci/common/vmciContext.h deleted file mode 100644 index 2149193bc..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.h +++ /dev/null @@ -1,124 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2013,2015 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 - * - *********************************************************/ - -/* - * vmciContext.h -- - * - * VMCI state to enable sending calls between VMs. - */ - -#ifndef _VMCI_CONTEXT_H_ -#define _VMCI_CONTEXT_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" -#include "vmci_call_defs.h" -#include "vmci_handle_array.h" -#include "vmci_infrastructure.h" -#include "vmci_kernel_if.h" -#include "vmciCommonInt.h" - -#define MAX_QUEUED_GUESTCALLS_PER_VM 100 - -typedef struct VMCIContext VMCIContext; - -int VMCIContext_Init(void); -void VMCIContext_Exit(void); -int VMCIContext_InitContext(VMCIId cid, VMCIPrivilegeFlags flags, - uintptr_t eventHnd, int version, - VMCIHostUser *user, VMCIContext **context); -#ifdef VMKERNEL -void VMCIContext_SetFSRState(VMCIContext *context, - Bool isQuiesced, - VMCIId migrateCid, - uintptr_t eventHnd, - Bool isLocked); -VMCIContext *VMCIContext_FindAndUpdateSrcFSR(VMCIId migrateCid, - uintptr_t eventHnd, - uintptr_t *srcEventHnd); -Bool VMCIContext_IsActiveHnd(VMCIContext *context, uintptr_t eventHnd); -uintptr_t VMCIContext_GetActiveHnd(VMCIContext *context); -void VMCIContext_SetInactiveHnd(VMCIContext *context, uintptr_t eventHnd); -Bool VMCIContext_RemoveHnd(VMCIContext *context, - uintptr_t eventHnd, - uint32 *numOld, - uint32 *numNew); -void VMCIContext_ClearDatagrams(VMCIContext *context); -void VMCIContext_SetId(VMCIContext *context, VMCIId cid); -void VMCIContext_NotifyGuestPaused(VMCIId cid, Bool paused); -void VMCIContext_NotifyMemoryAccess(VMCIId cid, Bool on); -Bool VMCIContext_RevalidateMappings(VMCIContext *context); -#endif -Bool VMCIContext_SupportsHostQP(VMCIContext *context); -void VMCIContext_ReleaseContext(VMCIContext *context); -int VMCIContext_EnqueueDatagram(VMCIId cid, VMCIDatagram *dg, Bool notify); -int VMCIContext_DequeueDatagram(VMCIContext *context, size_t *maxSize, - VMCIDatagram **dg); -int VMCIContext_PendingDatagrams(VMCIId cid, uint32 *pending); -VMCIContext *VMCIContext_Get(VMCIId cid); -void VMCIContext_Release(VMCIContext *context); -Bool VMCIContext_Exists(VMCIId cid); - -VMCIId VMCIContext_GetId(VMCIContext *context); -int VMCIContext_AddNotification(VMCIId contextID, VMCIId remoteCID); -int VMCIContext_RemoveNotification(VMCIId contextID, VMCIId remoteCID); -int VMCIContext_GetCheckpointState(VMCIId contextID, uint32 cptType, - uint32 *numCIDs, char **cptBufPtr); -int VMCIContext_SetCheckpointState(VMCIId contextID, uint32 cptType, - uint32 numCIDs, char *cptBuf); -void VMCIContext_RegisterGuestMem(VMCIContext *context, VMCIGuestMemID gid); -void VMCIContext_ReleaseGuestMem(VMCIContext *context, VMCIGuestMemID gid, - Bool powerOff); - -int VMCIContext_QueuePairCreate(VMCIContext *context, VMCIHandle handle); -int VMCIContext_QueuePairDestroy(VMCIContext *context, VMCIHandle handle); -Bool VMCIContext_QueuePairExists(VMCIContext *context, VMCIHandle handle); - -#ifndef VMX86_SERVER -void VMCIContext_CheckAndSignalNotify(VMCIContext *context); -# ifdef __linux__ -/* TODO Windows and Mac OS. */ -void VMCIUnsetNotify(VMCIContext *context); -# endif -#endif - -int VMCIContext_DoorbellCreate(VMCIId contextID, VMCIHandle handle); -int VMCIContext_DoorbellDestroy(VMCIId contextID, VMCIHandle handle); -int VMCIContext_DoorbellDestroyAll(VMCIId contextID); -int VMCIContext_NotifyDoorbell(VMCIId cid, VMCIHandle handle, - VMCIPrivilegeFlags srcPrivFlags); - -int VMCIContext_ReceiveNotificationsGet(VMCIId contextID, - VMCIHandleArray **dbHandleArray, - VMCIHandleArray **qpHandleArray); -void VMCIContext_ReceiveNotificationsRelease(VMCIId contextID, - VMCIHandleArray *dbHandleArray, - VMCIHandleArray *qpHandleArray, - Bool success); -#if defined(VMKERNEL) -void VMCIContext_SignalPendingDoorbells(VMCIId contextID); -void VMCIContext_SignalPendingDatagrams(VMCIId contextID); -int VMCIContext_FilterSet(VMCIId cid, VMCIFilterState *filterState); -int VMCI_Uuid2ContextId(const char *uuidString, VMCIId *contextID); -#endif // VMKERNEL -#endif // _VMCI_CONTEXT_H_ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c b/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c deleted file mode 100644 index 7fd7674aa..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c +++ /dev/null @@ -1,970 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2011,2014 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 - * - *********************************************************/ - -/* - * vmciDatagram.c -- - * - * This file implements the VMCI Simple Datagram API on the host. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciContext.h" -#include "vmciDatagram.h" -#include "vmciDriver.h" -#include "vmciEvent.h" -#include "vmciHashtable.h" -#include "vmciKernelAPI.h" -#include "vmciResource.h" -#include "vmciRoute.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -#endif - -#define LGPFX "VMCIDatagram: " - - -/* - * DatagramEntry describes the datagram entity. It is used for datagram - * entities created only on the host. - */ -typedef struct DatagramEntry { - VMCIResource resource; - uint32 flags; - Bool runDelayed; - VMCIDatagramRecvCB recvCB; - void *clientData; - VMCIEvent destroyEvent; - VMCIPrivilegeFlags privFlags; -} DatagramEntry; - -typedef struct VMCIDelayedDatagramInfo { - Bool inDGHostQueue; - DatagramEntry *entry; - VMCIDatagram msg; -} VMCIDelayedDatagramInfo; - - -static Atomic_uint32 delayedDGHostQueueSize; - -static int VMCIDatagramGetPrivFlagsInt(VMCIId contextID, VMCIHandle handle, - VMCIPrivilegeFlags *privFlags); -static void DatagramFreeCB(void *resource); -static int DatagramReleaseCB(void *clientData); - - -/*------------------------------ Helper functions ----------------------------*/ - -/* - *------------------------------------------------------------------------------ - * - * DatagramFreeCB -- - * Callback to free datagram structure when resource is no longer used, - * ie. the reference count reached 0. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -static void -DatagramFreeCB(void *clientData) -{ - DatagramEntry *entry = (DatagramEntry *)clientData; - ASSERT(entry); - VMCI_SignalEvent(&entry->destroyEvent); - - /* - * The entry is freed in VMCIDatagram_DestroyHnd, who is waiting for the - * above signal. - */ -} - - -/* - *------------------------------------------------------------------------------ - * - * DatagramReleaseCB -- - * - * Callback to release the resource reference. It is called by the - * VMCI_WaitOnEvent function before it blocks. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -DatagramReleaseCB(void *clientData) -{ - DatagramEntry *entry = (DatagramEntry *)clientData; - ASSERT(entry); - VMCIResource_Release(&entry->resource); - return 0; -} - - -/* - *------------------------------------------------------------------------------ - * - * DatagramCreateHnd -- - * - * Internal function to create a datagram entry given a handle. - * - * Results: - * VMCI_SUCCESS if created, negative errno value otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -DatagramCreateHnd(VMCIId resourceID, // IN: - uint32 flags, // IN: - VMCIPrivilegeFlags privFlags, // IN: - VMCIDatagramRecvCB recvCB, // IN: - void *clientData, // IN: - VMCIHandle *outHandle) // OUT: - -{ - int result; - VMCIId contextID; - VMCIHandle handle; - DatagramEntry *entry; - - ASSERT(recvCB != NULL); - ASSERT(outHandle != NULL); - ASSERT(!(privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS)); - - if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) { - return VMCI_ERROR_INVALID_ARGS; - } else { - if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) { - contextID = VMCI_INVALID_ID; - } else { - contextID = vmci_get_context_id(); - if (contextID == VMCI_INVALID_ID) { - return VMCI_ERROR_NO_RESOURCES; - } - } - - if (resourceID == VMCI_INVALID_ID) { - resourceID = VMCIResource_GetID(contextID); - if (resourceID == VMCI_INVALID_ID) { - return VMCI_ERROR_NO_HANDLE; - } - } - - handle = VMCI_MAKE_HANDLE(contextID, resourceID); - } - - entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED); - if (entry == NULL) { - VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n")); - return VMCI_ERROR_NO_MEM; - } - - if (!VMCI_CanScheduleDelayedWork()) { - if (flags & VMCI_FLAG_DG_DELAYED_CB) { - VMCI_FreeKernelMem(entry, sizeof *entry); - return VMCI_ERROR_INVALID_ARGS; - } - entry->runDelayed = FALSE; - } else { - entry->runDelayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? TRUE : FALSE; - } - - entry->flags = flags; - entry->recvCB = recvCB; - entry->clientData = clientData; - VMCI_CreateEvent(&entry->destroyEvent); - entry->privFlags = privFlags; - - /* Make datagram resource live. */ - result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DATAGRAM, - handle, DatagramFreeCB, entry); - if (result != VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n", - handle.context, handle.resource)); - VMCI_DestroyEvent(&entry->destroyEvent); - VMCI_FreeKernelMem(entry, sizeof *entry); - return result; - } - *outHandle = handle; - - return VMCI_SUCCESS; -} - - -/*------------------------------ Init functions ----------------------------*/ - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagram_Init -- - * - * Initialize Datagram API, ie. register the API functions with their - * corresponding vectors. - * - * Result: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDatagram_Init(void) -{ - Atomic_Write(&delayedDGHostQueueSize, 0); - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagram_Exit -- - * - * Cleanup Datagram API. - * - * Result: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIDatagram_Exit(void) -{ -} - - -/*------------------------------ Public API functions ------------------------*/ - -/* - *------------------------------------------------------------------------------ - * - * vmci_datagram_create_handle -- - * - * Creates a host context datagram endpoint and returns a handle to it. - * - * Results: - * VMCI_SUCCESS if created, negative errno value otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_datagram_create_handle) -int -vmci_datagram_create_handle( - VMCIId resourceID, // IN: Optional, generated if VMCI_INVALID_ID - uint32 flags, // IN: - VMCIDatagramRecvCB recvCB, // IN: - void *clientData, // IN: - VMCIHandle *outHandle) // OUT: newly created handle -{ - if (outHandle == NULL) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (recvCB == NULL) { - VMCI_DEBUG_LOG(4, - (LGPFX"Client callback needed when creating datagram.\n")); - return VMCI_ERROR_INVALID_ARGS; - } - - return DatagramCreateHnd(resourceID, flags, VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS, - recvCB, clientData, outHandle); -} - - -/* - *------------------------------------------------------------------------------ - * - * vmci_datagram_create_handle_priv -- - * - * Creates a host context datagram endpoint and returns a handle to it. - * - * Results: - * VMCI_SUCCESS if created, negative errno value otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_datagram_create_handle_priv) -int -vmci_datagram_create_handle_priv( - VMCIId resourceID, // IN: Optional, generated if VMCI_INVALID_ID - uint32 flags, // IN: - VMCIPrivilegeFlags privFlags, // IN: - VMCIDatagramRecvCB recvCB, // IN: - void *clientData, // IN: - VMCIHandle *outHandle) // OUT: newly created handle -{ - if (outHandle == NULL) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (recvCB == NULL) { - VMCI_DEBUG_LOG(4, - (LGPFX"Client callback needed when creating datagram.\n")); - return VMCI_ERROR_INVALID_ARGS; - } - - if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) { - return VMCI_ERROR_INVALID_ARGS; - } - - return DatagramCreateHnd(resourceID, flags, privFlags, recvCB, clientData, - outHandle); -} - - -/* - *------------------------------------------------------------------------------ - * - * vmci_datagram_destroy_handle -- - * - * Destroys a handle. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_datagram_destroy_handle) -int -vmci_datagram_destroy_handle(VMCIHandle handle) // IN -{ - DatagramEntry *entry; - VMCIResource *resource = VMCIResource_Get(handle, - VMCI_RESOURCE_TYPE_DATAGRAM); - if (resource == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy datagram (handle=0x%x:0x%x).\n", - handle.context, handle.resource)); - return VMCI_ERROR_NOT_FOUND; - } - entry = RESOURCE_CONTAINER(resource, DatagramEntry, resource); - - VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DATAGRAM); - - /* - * We now wait on the destroyEvent and release the reference we got - * above. - */ - VMCI_WaitOnEvent(&entry->destroyEvent, DatagramReleaseCB, entry); - - /* - * We know that we are now the only reference to the above entry so - * can safely free it. - */ - VMCI_DestroyEvent(&entry->destroyEvent); - VMCI_FreeKernelMem(entry, sizeof *entry); - - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagramGetPrivFlagsInt -- - * - * Internal utilility function with the same purpose as - * VMCIDatagram_GetPrivFlags that also takes a contextID. - * - * Result: - * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDatagramGetPrivFlagsInt(VMCIId contextID, // IN - VMCIHandle handle, // IN - VMCIPrivilegeFlags *privFlags) // OUT -{ - ASSERT(privFlags); - ASSERT(contextID != VMCI_INVALID_ID); - - if (contextID == VMCI_HOST_CONTEXT_ID) { - DatagramEntry *srcEntry; - VMCIResource *resource; - - resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DATAGRAM); - if (resource == NULL) { - return VMCI_ERROR_INVALID_ARGS; - } - srcEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource); - *privFlags = srcEntry->privFlags; - VMCIResource_Release(resource); - } else if (contextID == VMCI_HYPERVISOR_CONTEXT_ID) { - *privFlags = VMCI_MAX_PRIVILEGE_FLAGS; - } else { - *privFlags = vmci_context_get_priv_flags(contextID); - } - - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagram_GetPrivFlags -- - * - * Utilility function that retrieves the privilege flags - * associated with a given datagram handle. For hypervisor and - * guest endpoints, the privileges are determined by the context - * ID, but for host endpoints privileges are associated with the - * complete handle. - * - * Result: - * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDatagram_GetPrivFlags(VMCIHandle handle, // IN - VMCIPrivilegeFlags *privFlags) // OUT -{ - if (privFlags == NULL || handle.context == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - return VMCIDatagramGetPrivFlagsInt(handle.context, handle, privFlags); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDatagramDelayedDispatchCB -- - * - * Calls the specified callback in a delayed context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIDatagramDelayedDispatchCB(void *data) // IN -{ - Bool inDGHostQueue; - VMCIDelayedDatagramInfo *dgInfo = (VMCIDelayedDatagramInfo *)data; - - ASSERT(data); - - dgInfo->entry->recvCB(dgInfo->entry->clientData, &dgInfo->msg); - - VMCIResource_Release(&dgInfo->entry->resource); - - inDGHostQueue = dgInfo->inDGHostQueue; - VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dgInfo->msg.payloadSize); - - if (inDGHostQueue) { - Atomic_Dec(&delayedDGHostQueueSize); - } -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagramDispatchAsHost -- - * - * Dispatch datagram as a host, to the host or other vm context. This - * function cannot dispatch to hypervisor context handlers. This should - * have been handled before we get here by VMCIDatagramDispatch. - * - * Result: - * Number of bytes sent on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDatagramDispatchAsHost(VMCIId contextID, // IN: - VMCIDatagram *dg) // IN: -{ - int retval; - size_t dgSize; - VMCIPrivilegeFlags srcPrivFlags; - - ASSERT(dg); - ASSERT(VMCI_HostPersonalityActive()); - - dgSize = VMCI_DG_SIZE(dg); - - if (contextID == VMCI_HOST_CONTEXT_ID && - dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID) { - VMCI_DEBUG_LOG(4, (LGPFX"Host cannot talk to hypervisor\n")); - return VMCI_ERROR_DST_UNREACHABLE; - } - - ASSERT(dg->dst.context != VMCI_HYPERVISOR_CONTEXT_ID); - - /* Chatty. */ - // VMCI_DEBUG_LOG(10, (LGPFX"Sending from (handle=0x%x:0x%x) to " - // "(handle=0x%x:0x%x) (size=%u bytes).\n", - // dg->src.context, dg->src.resource, - // dg->dst.context, dg->dst.resource, (uint32)dgSize)); - - /* - * Check that source handle matches sending context. - */ - if (dg->src.context != contextID) { - VMCI_DEBUG_LOG(4, (LGPFX"Sender context (ID=0x%x) is not owner of src " - "datagram entry (handle=0x%x:0x%x).\n", - contextID, dg->src.context, dg->src.resource)); - return VMCI_ERROR_NO_ACCESS; - } - - /* - * Get hold of privileges of sending endpoint. - */ - - retval = VMCIDatagramGetPrivFlagsInt(contextID, dg->src, &srcPrivFlags); - if (retval != VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Couldn't get privileges (handle=0x%x:0x%x).\n", - dg->src.context, dg->src.resource)); - return retval; - } - - /* Determine if we should route to host or guest destination. */ - if (dg->dst.context == VMCI_HOST_CONTEXT_ID) { - /* Route to host datagram entry. */ - DatagramEntry *dstEntry; - VMCIResource *resource; - - if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID && - dg->dst.resource == VMCI_EVENT_HANDLER) { - return VMCIEvent_Dispatch(dg); - } - - resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM); - if (resource == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Sending to invalid destination " - "(handle=0x%x:0x%x).\n", - dg->dst.context, dg->dst.resource)); - return VMCI_ERROR_INVALID_RESOURCE; - } - dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource); - if (VMCIDenyInteraction(srcPrivFlags, dstEntry->privFlags)) { - VMCIResource_Release(resource); - return VMCI_ERROR_NO_ACCESS; - } - ASSERT(dstEntry->recvCB); - - /* - * If a VMCI datagram destined for the host is also sent by the - * host, we always run it delayed. This ensures that no locks - * are held when the datagram callback runs. - */ - - if (dstEntry->runDelayed || - (dg->src.context == VMCI_HOST_CONTEXT_ID && - VMCI_CanScheduleDelayedWork())) { - VMCIDelayedDatagramInfo *dgInfo; - - if (Atomic_ReadInc32(&delayedDGHostQueueSize) == - VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) { - Atomic_Dec(&delayedDGHostQueueSize); - VMCIResource_Release(resource); - return VMCI_ERROR_NO_MEM; - } - - dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize, - (VMCI_MEMORY_ATOMIC | - VMCI_MEMORY_NONPAGED)); - if (NULL == dgInfo) { - Atomic_Dec(&delayedDGHostQueueSize); - VMCIResource_Release(resource); - return VMCI_ERROR_NO_MEM; - } - - dgInfo->inDGHostQueue = TRUE; - dgInfo->entry = dstEntry; - memcpy(&dgInfo->msg, dg, dgSize); - - retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo); - if (retval < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram " - "(result=%d).\n", retval)); - VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize); - VMCIResource_Release(resource); - Atomic_Dec(&delayedDGHostQueueSize); - return retval; - } - } else { - retval = dstEntry->recvCB(dstEntry->clientData, dg); - VMCIResource_Release(resource); - if (retval < VMCI_SUCCESS) { - return retval; - } - } - } else { - /* - * Route to destination VM context. - */ - - VMCIDatagram *newDG; - - if (contextID != dg->dst.context) { - if (VMCIDenyInteraction(srcPrivFlags, - vmci_context_get_priv_flags(dg->dst.context))) { - VMCI_DEBUG_LOG(4, (LGPFX"Interaction denied (%X/%X - %X/%X)\n", - contextID, srcPrivFlags, - dg->dst.context, - vmci_context_get_priv_flags(dg->dst.context))); - return VMCI_ERROR_NO_ACCESS; - } else if (VMCI_CONTEXT_IS_VM(contextID)) { - /* - * If the sending context is a VM, it cannot reach another VM. - */ - - VMCI_DEBUG_LOG(4, (LGPFX"Datagram communication between VMs not " - "supported (src=0x%x, dst=0x%x).\n", - contextID, dg->dst.context)); - return VMCI_ERROR_DST_UNREACHABLE; - } - } - - /* We make a copy to enqueue. */ - newDG = VMCI_AllocKernelMem(dgSize, VMCI_MEMORY_NORMAL); - if (newDG == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"No memory for datagram\n")); - return VMCI_ERROR_NO_MEM; - } - memcpy(newDG, dg, dgSize); - retval = VMCIContext_EnqueueDatagram(dg->dst.context, newDG, TRUE); - if (retval < VMCI_SUCCESS) { - VMCI_FreeKernelMem(newDG, dgSize); - VMCI_DEBUG_LOG(4, (LGPFX"Enqueue failed\n")); - return retval; - } - } - - /* The datagram is freed when the context reads it. */ - - /* Chatty. */ - // VMCI_DEBUG_LOG(10, (LGPFX"Sent datagram (size=%u bytes).\n", - // (uint32)dgSize)); - - /* - * We currently truncate the size to signed 32 bits. This doesn't - * matter for this handler as it only support 4Kb messages. - */ - - return (int)dgSize; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagramDispatchAsGuest -- - * - * Dispatch datagram as a guest, down through the VMX and potentially to - * the host. - * - * Result: - * Number of bytes sent on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDatagramDispatchAsGuest(VMCIDatagram *dg) -{ -#if defined(VMKERNEL) - VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); - return VMCI_ERROR_DST_UNREACHABLE; -#else // VMKERNEL - int retval; - VMCIResource *resource; - - resource = VMCIResource_Get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM); - if (NULL == resource) { - return VMCI_ERROR_NO_HANDLE; - } - - retval = VMCI_SendDatagram(dg); - VMCIResource_Release(resource); - return retval; -#endif // VMKERNEL -} - - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagram_Dispatch -- - * - * Dispatch datagram. This will determine the routing for the datagram - * and dispatch it accordingly. - * - * Result: - * Number of bytes sent on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDatagram_Dispatch(VMCIId contextID, - VMCIDatagram *dg, - Bool fromGuest) -{ - int retval; - VMCIRoute route; - - ASSERT(dg); - ASSERT_ON_COMPILE(sizeof(VMCIDatagram) == 24); - - if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) { - VMCI_DEBUG_LOG(4, (LGPFX"Payload (size=%"FMT64"u bytes) too big to " - "send.\n", dg->payloadSize)); - return VMCI_ERROR_INVALID_ARGS; - } - - retval = VMCI_Route(&dg->src, &dg->dst, fromGuest, &route); - if (retval < VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to route datagram (src=0x%x, dst=0x%x, " - "err=%d)\n.", dg->src.context, dg->dst.context, - retval)); - return retval; - } - - if (VMCI_ROUTE_AS_HOST == route) { - if (VMCI_INVALID_ID == contextID) { - contextID = VMCI_HOST_CONTEXT_ID; - } - return VMCIDatagramDispatchAsHost(contextID, dg); - } - - if (VMCI_ROUTE_AS_GUEST == route) { - return VMCIDatagramDispatchAsGuest(dg); - } - - VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route)); - return VMCI_ERROR_DST_UNREACHABLE; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDatagram_InvokeGuestHandler -- - * - * Invoke the handler for the given datagram. This is intended to be - * called only when acting as a guest and receiving a datagram from the - * virtual device. - * - * Result: - * VMCI_SUCCESS on success, other error values on failure. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN -{ -#if defined(VMKERNEL) - VMCI_WARNING((LGPFX"Cannot dispatch within guest in VMKERNEL.\n")); - return VMCI_ERROR_DST_UNREACHABLE; -#else // VMKERNEL - int retval; - VMCIResource *resource; - DatagramEntry *dstEntry; - - ASSERT(dg); - - if (dg->payloadSize > VMCI_MAX_DG_PAYLOAD_SIZE) { - VMCI_DEBUG_LOG(4, (LGPFX"Payload (size=%"FMT64"u bytes) too large to " - "deliver.\n", dg->payloadSize)); - return VMCI_ERROR_PAYLOAD_TOO_LARGE; - } - - resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM); - if (NULL == resource) { - VMCI_DEBUG_LOG(4, (LGPFX"destination (handle=0x%x:0x%x) doesn't exist.\n", - dg->dst.context, dg->dst.resource)); - return VMCI_ERROR_NO_HANDLE; - } - - dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource); - if (dstEntry->runDelayed) { - VMCIDelayedDatagramInfo *dgInfo; - - dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize, - (VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED)); - if (NULL == dgInfo) { - VMCIResource_Release(resource); - retval = VMCI_ERROR_NO_MEM; - goto exit; - } - - dgInfo->inDGHostQueue = FALSE; - dgInfo->entry = dstEntry; - memcpy(&dgInfo->msg, dg, VMCI_DG_SIZE(dg)); - - retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo); - if (retval < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram " - "(result=%d).\n", retval)); - VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize); - VMCIResource_Release(resource); - dgInfo = NULL; - goto exit; - } - } else { - dstEntry->recvCB(dstEntry->clientData, dg); - VMCIResource_Release(resource); - retval = VMCI_SUCCESS; - } - -exit: - return retval; -#endif // VMKERNEL -} - - -/* - *------------------------------------------------------------------------------ - * - * vmci_datagram_send -- - * - * Sends the payload to the destination datagram handle. - * - * Results: - * Returns number of bytes sent if success, or error code if failure. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_datagram_send) -int -vmci_datagram_send(VMCIDatagram *msg) // IN -{ - if (msg == NULL) { - return VMCI_ERROR_INVALID_ARGS; - } - - return VMCIDatagram_Dispatch(VMCI_INVALID_ID, msg, FALSE); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDatagram_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIDatagram_Sync(void) -{ - VMCIResource_Sync(); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDatagram_CheckHostCapabilities -- - * - * Verify that the host supports the resources we need. - * None are required for datagrams since they are implicitly supported. - * - * Results: - * TRUE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCIDatagram_CheckHostCapabilities(void) -{ - return TRUE; -} diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.h b/open-vm-tools/modules/linux/vmci/common/vmciDatagram.h deleted file mode 100644 index ad7ff457f..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.h +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * vmciDatagram.h -- - * - * Internal functions in the VMCI Simple Datagram API. - */ - -#ifndef _VMCI_DATAGRAM_H_ -#define _VMCI_DATAGRAM_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmciContext.h" -#include "vmci_call_defs.h" -#ifndef VMX86_SERVER -#include "vmci_iocontrols.h" -#endif // !VMX86_SERVER - -#define VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE 256 - -/* Init functions. */ -int VMCIDatagram_Init(void); -void VMCIDatagram_Exit(void); - -/* Datagram API for non-public use. */ -int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *dg, Bool fromGuest); -int VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg); -int VMCIDatagram_GetPrivFlags(VMCIHandle handle, VMCIPrivilegeFlags *privFlags); - -/* Misc. */ -void VMCIDatagram_Sync(void); -Bool VMCIDatagram_CheckHostCapabilities(void); - -#endif // _VMCI_DATAGRAM_H_ - - diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c b/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c deleted file mode 100644 index ed1c74fb2..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c +++ /dev/null @@ -1,1245 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciDoorbell.c -- - * - * This file implements the VMCI doorbell API on the host. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciDatagram.h" -#include "vmciDoorbell.h" -#include "vmciDriver.h" -#include "vmciKernelAPI.h" -#include "vmciResource.h" -#include "vmciRoute.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -#endif - -#define LGPFX "VMCIDoorbell: " - -#if !defined(__APPLE__) - -#define VMCI_DOORBELL_INDEX_TABLE_SIZE 64 -#define VMCI_DOORBELL_HASH(_idx) \ - VMCI_HashId((_idx), VMCI_DOORBELL_INDEX_TABLE_SIZE) - - -/* - * DoorbellEntry describes the a doorbell notification handle allocated by the - * host. - */ - -typedef struct VMCIDoorbellEntry { - VMCIResource resource; - uint32 idx; - VMCIListItem idxListItem; - VMCIPrivilegeFlags privFlags; - Bool isDoorbell; - Bool runDelayed; - VMCICallback notifyCB; - void *clientData; - VMCIEvent destroyEvent; - Atomic_uint32 active; // Only used by guest personality -} VMCIDoorbellEntry; - -typedef struct VMCIDoorbellIndexTable { - VMCILock lock; - VMCIList entries[VMCI_DOORBELL_INDEX_TABLE_SIZE]; -} VMCIDoorbellIndexTable; - - -/* The VMCI index table keeps track of currently registered doorbells. */ -static VMCIDoorbellIndexTable vmciDoorbellIT; - - -/* - * The maxNotifyIdx is one larger than the currently known bitmap index in - * use, and is used to determine how much of the bitmap needs to be scanned. - */ - -static uint32 maxNotifyIdx; - -/* - * The notifyIdxCount is used for determining whether there are free entries - * within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx). - */ - -static uint32 notifyIdxCount; - -/* - * The lastNotifyIdxReserved is used to track the last index handed out - in - * the case where multiple handles share a notification index, we hand out - * indexes round robin based on lastNotifyIdxReserved. - */ - -static uint32 lastNotifyIdxReserved; - -/* This is a one entry cache used to by the index allocation. */ -static uint32 lastNotifyIdxReleased = PAGE_SIZE; - - -static void VMCIDoorbellFreeCB(void *clientData); -static int VMCIDoorbellReleaseCB(void *clientData); -static void VMCIDoorbellDelayedDispatchCB(void *data); - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbell_Init -- - * - * General init code. - * - * Result: - * VMCI_SUCCESS on success, lock allocation error otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDoorbell_Init(void) -{ - uint32 bucket; - - for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); ++bucket) { - VMCIList_Init(&vmciDoorbellIT.entries[bucket]); - } - - return VMCI_InitLock(&vmciDoorbellIT.lock, "VMCIDoorbellIndexTableLock", - VMCI_LOCK_RANK_DOORBELL); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbell_Exit -- - * - * General init code. - * - * Result: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIDoorbell_Exit(void) -{ - VMCI_CleanupLock(&vmciDoorbellIT.lock); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellFreeCB -- - * - * Callback to free doorbell entry structure when resource is no longer used, - * ie. the reference count reached 0. The entry is freed in - * VMCIDoorbell_Destroy(), which is waiting on the signal that gets fired - * here. - * - * Result: - * None. - * - * Side effects: - * Signals VMCI event. - * - *------------------------------------------------------------------------------ - */ - -static void -VMCIDoorbellFreeCB(void *clientData) // IN -{ - VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData; - ASSERT(entry); - VMCI_SignalEvent(&entry->destroyEvent); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellReleaseCB -- - * - * Callback to release the resource reference. It is called by the - * VMCI_WaitOnEvent function before it blocks. - * - * Result: - * Always 0. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDoorbellReleaseCB(void *clientData) // IN: doorbell entry -{ - VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData; - ASSERT(entry); - VMCIResource_Release(&entry->resource); - return 0; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellGetPrivFlags -- - * - * Utility function that retrieves the privilege flags associated - * with a given doorbell handle. For guest endpoints, the - * privileges are determined by the context ID, but for host - * endpoints privileges are associated with the complete - * handle. Hypervisor endpoints are not yet supported. - * - * Result: - * VMCI_SUCCESS on success, - * VMCI_ERROR_NOT_FOUND if handle isn't found, - * VMCI_ERROR_INVALID_ARGS if handle is invalid. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDoorbellGetPrivFlags(VMCIHandle handle, // IN - VMCIPrivilegeFlags *privFlags) // OUT -{ - if (privFlags == NULL || handle.context == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (handle.context == VMCI_HOST_CONTEXT_ID) { - VMCIDoorbellEntry *entry; - VMCIResource *resource; - - resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL); - if (resource == NULL) { - return VMCI_ERROR_NOT_FOUND; - } - entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource); - *privFlags = entry->privFlags; - VMCIResource_Release(resource); - } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) { - /* Hypervisor endpoints for notifications are not supported (yet). */ - return VMCI_ERROR_INVALID_ARGS; - } else { - *privFlags = vmci_context_get_priv_flags(handle.context); - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoorbellIndexTableFind -- - * - * Find doorbell entry by bitmap index. - * - * Results: - * Entry if found, NULL if not. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static VMCIDoorbellEntry * -VMCIDoorbellIndexTableFind(uint32 idx) // IN -{ - uint32 bucket = VMCI_DOORBELL_HASH(idx); - VMCIListItem *iter; - - ASSERT(VMCI_GuestPersonalityActive()); - - VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) { - VMCIDoorbellEntry *cur = - VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem); - - ASSERT(cur); - - if (idx == cur->idx) { - return cur; - } - } - - return NULL; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellIndexTableAdd -- - * - * Add the given entry to the index table. This will hold() the entry's - * resource so that the entry is not deleted before it is removed from the - * table. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static void -VMCIDoorbellIndexTableAdd(VMCIDoorbellEntry *entry) // IN/OUT -{ - uint32 bucket; - uint32 newNotifyIdx; - VMCILockFlags flags; - - ASSERT(entry); - ASSERT(VMCI_GuestPersonalityActive()); - - VMCIResource_Hold(&entry->resource); - - VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags); - - /* - * Below we try to allocate an index in the notification bitmap with "not - * too much" sharing between resources. If we use less that the full bitmap, - * we either add to the end if there are no unused flags within the - * currently used area, or we search for unused ones. If we use the full - * bitmap, we allocate the index round robin. - */ - - if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) { - if (lastNotifyIdxReleased < maxNotifyIdx && - !VMCIDoorbellIndexTableFind(lastNotifyIdxReleased)) { - newNotifyIdx = lastNotifyIdxReleased; - lastNotifyIdxReleased = PAGE_SIZE; - } else { - Bool reused = FALSE; - newNotifyIdx = lastNotifyIdxReserved; - if (notifyIdxCount + 1 < maxNotifyIdx) { - do { - if (!VMCIDoorbellIndexTableFind(newNotifyIdx)) { - reused = TRUE; - break; - } - newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx; - } while(newNotifyIdx != lastNotifyIdxReleased); - } - if (!reused) { - newNotifyIdx = maxNotifyIdx; - maxNotifyIdx++; - } - } - } else { - newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE; - } - lastNotifyIdxReserved = newNotifyIdx; - notifyIdxCount++; - - entry->idx = newNotifyIdx; - bucket = VMCI_DOORBELL_HASH(entry->idx); - VMCIList_Insert(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]); - - VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellIndexTableRemove -- - * - * Remove the given entry from the index table. This will release() the - * entry's resource. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static void -VMCIDoorbellIndexTableRemove(VMCIDoorbellEntry *entry) // IN/OUT -{ - VMCILockFlags flags; - - ASSERT(entry); - ASSERT(VMCI_GuestPersonalityActive()); - - VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags); - - VMCIList_Remove(&entry->idxListItem); - - notifyIdxCount--; - if (entry->idx == maxNotifyIdx - 1) { - /* - * If we delete an entry with the maximum known notification index, we - * take the opportunity to prune the current max. As there might be other - * unused indices immediately below, we lower the maximum until we hit an - * index in use. - */ - - while (maxNotifyIdx > 0 && - !VMCIDoorbellIndexTableFind(maxNotifyIdx - 1)) { - maxNotifyIdx--; - } - } - lastNotifyIdxReleased = entry->idx; - - VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags); - - VMCIResource_Release(&entry->resource); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellLink -- - * - * Creates a link between the given doorbell handle and the given - * index in the bitmap in the device backend. - * - * Results: - * VMCI_SUCCESS if success, appropriate error code otherwise. - * - * Side effects: - * Notification state is created in hypervisor. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDoorbellLink(VMCIHandle handle, // IN - Bool isDoorbell, // IN - uint32 notifyIdx) // IN -{ -#if defined(VMKERNEL) - VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); - return VMCI_ERROR_DST_UNREACHABLE; -#else // VMKERNEL - VMCIId resourceID; - VMCIDoorbellLinkMsg linkMsg; - - ASSERT(!VMCI_HANDLE_INVALID(handle)); - ASSERT(VMCI_GuestPersonalityActive()); - - if (isDoorbell) { - resourceID = VMCI_DOORBELL_LINK; - } else { - ASSERT(FALSE); - return VMCI_ERROR_UNAVAILABLE; - } - - linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID); - linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE; - linkMsg.handle = handle; - linkMsg.notifyIdx = notifyIdx; - - return VMCI_SendDatagram((VMCIDatagram *)&linkMsg); -#endif // VMKERNEL -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellUnlink -- - * - * Unlinks the given doorbell handle from an index in the bitmap in - * the device backend. - * - * Results: - * VMCI_SUCCESS if success, appropriate error code otherwise. - * - * Side effects: - * Notification state is destroyed in hypervisor. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDoorbellUnlink(VMCIHandle handle, // IN - Bool isDoorbell) // IN -{ -#if defined(VMKERNEL) - VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); - return VMCI_ERROR_DST_UNREACHABLE; -#else // VMKERNEL - VMCIId resourceID; - VMCIDoorbellUnlinkMsg unlinkMsg; - - ASSERT(!VMCI_HANDLE_INVALID(handle)); - ASSERT(VMCI_GuestPersonalityActive()); - - if (isDoorbell) { - resourceID = VMCI_DOORBELL_UNLINK; - } else { - ASSERT(FALSE); - return VMCI_ERROR_UNAVAILABLE; - } - - unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID); - unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE; - unlinkMsg.handle = handle; - - return VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg); -#endif // VMKERNEL -} - - -/* - *------------------------------------------------------------------------------ - * - * vmci_doorbell_create -- - * - * Creates a doorbell with the given callback. If the handle is - * VMCI_INVALID_HANDLE, a free handle will be assigned, if - * possible. The callback can be run immediately (potentially with - * locks held - the default) or delayed (in a kernel thread) by - * specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution - * is selected, a given callback may not be run if the kernel is - * unable to allocate memory for the delayed execution (highly - * unlikely). - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_doorbell_create) -int -vmci_doorbell_create(VMCIHandle *handle, // IN/OUT - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - VMCICallback notifyCB, // IN - void *clientData) // IN -{ - VMCIDoorbellEntry *entry; - VMCIHandle newHandle; - int result; - - if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB || - privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) { - return VMCI_ERROR_INVALID_ARGS; - } - - entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED); - if (entry == NULL) { - VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n")); - return VMCI_ERROR_NO_MEM; - } - - if (!VMCI_CanScheduleDelayedWork() && (flags & VMCI_FLAG_DELAYED_CB)) { - result = VMCI_ERROR_INVALID_ARGS; - goto freeMem; - } - - if (VMCI_HANDLE_INVALID(*handle)) { - VMCIId contextID = vmci_get_context_id(); - VMCIId resourceID = VMCIResource_GetID(contextID); - if (resourceID == VMCI_INVALID_ID) { - result = VMCI_ERROR_NO_HANDLE; - goto freeMem; - } - newHandle = VMCI_MAKE_HANDLE(contextID, resourceID); - } else { - Bool validContext; - - /* - * Validate the handle. We must do both of the checks below - * because we can be acting as both a host and a guest at the - * same time. We always allow the host context ID, since the - * host functionality is in practice always there with the - * unified driver. - */ - - validContext = FALSE; - if (VMCI_HOST_CONTEXT_ID == handle->context) { - validContext = TRUE; - } - if (VMCI_GuestPersonalityActive() && - vmci_get_context_id() == handle->context) { - validContext = TRUE; - } - - if (!validContext || VMCI_INVALID_ID == handle->resource) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument (handle=0x%x:0x%x).\n", - handle->context, handle->resource)); - result = VMCI_ERROR_INVALID_ARGS; - goto freeMem; - } - - newHandle = *handle; - } - - entry->idx = 0; - VMCIList_Init(&entry->idxListItem); - entry->privFlags = privFlags; - entry->isDoorbell = TRUE; - entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE; - entry->notifyCB = notifyCB; - entry->clientData = clientData; - Atomic_Write(&entry->active, 0); - VMCI_CreateEvent(&entry->destroyEvent); - - result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DOORBELL, - newHandle, VMCIDoorbellFreeCB, entry); - if (result != VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n", - newHandle.context, newHandle.resource)); - if (result == VMCI_ERROR_DUPLICATE_ENTRY) { - result = VMCI_ERROR_ALREADY_EXISTS; - } - goto destroy; - } - - if (VMCI_GuestPersonalityActive()) { - VMCIDoorbellIndexTableAdd(entry); - result = VMCIDoorbellLink(newHandle, entry->isDoorbell, entry->idx); - if (VMCI_SUCCESS != result) { - goto destroyResource; - } - Atomic_Write(&entry->active, 1); - } - - if (VMCI_HANDLE_INVALID(*handle)) { - *handle = newHandle; - } - - return result; - -destroyResource: - VMCIDoorbellIndexTableRemove(entry); - VMCIResource_Remove(newHandle, VMCI_RESOURCE_TYPE_DOORBELL); -destroy: - VMCI_DestroyEvent(&entry->destroyEvent); -freeMem: - VMCI_FreeKernelMem(entry, sizeof *entry); - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * vmci_doorbell_destroy -- - * - * Destroys a doorbell previously created with - * vmci_doorbell_create. This operation may block waiting for a - * callback to finish. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * May block. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_doorbell_destroy) -int -vmci_doorbell_destroy(VMCIHandle handle) // IN -{ - VMCIDoorbellEntry *entry; - VMCIResource *resource; - - if (VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL); - if (resource == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy doorbell (handle=0x%x:0x%x).\n", - handle.context, handle.resource)); - return VMCI_ERROR_NOT_FOUND; - } - entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource); - - if (VMCI_GuestPersonalityActive()) { - int result; - - VMCIDoorbellIndexTableRemove(entry); - - result = VMCIDoorbellUnlink(handle, entry->isDoorbell); - if (VMCI_SUCCESS != result) { - - /* - * The only reason this should fail would be an inconsistency between - * guest and hypervisor state, where the guest believes it has an - * active registration whereas the hypervisor doesn't. One case where - * this may happen is if a doorbell is unregistered following a - * hibernation at a time where the doorbell state hasn't been restored - * on the hypervisor side yet. Since the handle has now been removed - * in the guest, we just print a warning and return success. - */ - - VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by " - "hypervisor (error=%d).\n", - entry->isDoorbell ? "doorbell" : "queuepair", - handle.context, handle.resource, result)); - } - } - - /* - * Now remove the resource from the table. It might still be in use - * after this, in a callback or still on the delayed work queue. - */ - - VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DOORBELL); - - /* - * We now wait on the destroyEvent and release the reference we got - * above. - */ - - VMCI_WaitOnEvent(&entry->destroyEvent, VMCIDoorbellReleaseCB, entry); - - /* - * We know that we are now the only reference to the above entry so - * can safely free it. - */ - - VMCI_DestroyEvent(&entry->destroyEvent); - VMCI_FreeKernelMem(entry, sizeof *entry); - - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellNotifyAsGuest -- - * - * Notify another guest or the host. We send a datagram down to the - * host via the hypervisor with the notification info. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * May do a hypercall. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIDoorbellNotifyAsGuest(VMCIHandle handle, // IN - VMCIPrivilegeFlags privFlags) // IN -{ -#if defined(VMKERNEL) - VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n")); - return VMCI_ERROR_DST_UNREACHABLE; -#else // VMKERNEL - VMCIDoorbellNotifyMsg notifyMsg; - - UNREFERENCED_PARAMETER(privFlags); - - ASSERT(VMCI_GuestPersonalityActive()); - - notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_DOORBELL_NOTIFY); - notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE; - notifyMsg.handle = handle; - - return VMCI_SendDatagram((VMCIDatagram *)¬ifyMsg); -#endif // VMKERNEL -} - - -/* - *------------------------------------------------------------------------------ - * - * vmci_doorbell_notify -- - * - * Generates a notification on the doorbell identified by the - * handle. For host side generation of notifications, the caller - * can specify what the privilege of the calling side is. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * May do a hypercall. - * - *------------------------------------------------------------------------------ - */ - -VMCI_EXPORT_SYMBOL(vmci_doorbell_notify) -int -vmci_doorbell_notify(VMCIHandle dst, // IN - VMCIPrivilegeFlags privFlags) // IN -{ - int retval; - VMCIRoute route; - VMCIHandle src; - - if (VMCI_HANDLE_INVALID(dst) || (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS)) { - return VMCI_ERROR_INVALID_ARGS; - } - - src = VMCI_INVALID_HANDLE; - retval = VMCI_Route(&src, &dst, FALSE, &route); - if (retval < VMCI_SUCCESS) { - return retval; - } - - if (VMCI_ROUTE_AS_HOST == route) { - return VMCIContext_NotifyDoorbell(VMCI_HOST_CONTEXT_ID, dst, privFlags); - } - - if (VMCI_ROUTE_AS_GUEST == route) { - return VMCIDoorbellNotifyAsGuest(dst, privFlags); - } - - VMCI_WARNING((LGPFX"Unknown route (%d) for doorbell.\n", route)); - return VMCI_ERROR_DST_UNREACHABLE; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellDelayedDispatchCB -- - * - * Calls the specified callback in a delayed context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static void -VMCIDoorbellDelayedDispatchCB(void *data) // IN -{ - VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)data; - - ASSERT(data); - - entry->notifyCB(entry->clientData); - - VMCIResource_Release(&entry->resource); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbellHostContextNotify -- - * - * Dispatches a doorbell notification to the host context. - * - * Results: - * VMCI_SUCCESS on success. Appropriate error code otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIDoorbellHostContextNotify(VMCIId srcCID, // IN - VMCIHandle handle) // IN -{ - VMCIDoorbellEntry *entry; - VMCIResource *resource; - int result; - - UNREFERENCED_PARAMETER(srcCID); - - ASSERT(VMCI_HostPersonalityActive()); - - if (VMCI_HANDLE_INVALID(handle)) { - VMCI_DEBUG_LOG(4, - (LGPFX"Notifying an invalid doorbell (handle=0x%x:0x%x).\n", - handle.context, handle.resource)); - return VMCI_ERROR_INVALID_ARGS; - } - - resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL); - if (resource == NULL) { - VMCI_DEBUG_LOG(4, - (LGPFX"Notifying an unknown doorbell (handle=0x%x:0x%x).\n", - handle.context, handle.resource)); - return VMCI_ERROR_NOT_FOUND; - } - entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource); - - if (entry->runDelayed) { - result = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, entry); - if (result < VMCI_SUCCESS) { - /* - * If we failed to schedule the delayed work, we need to - * release the resource immediately. Otherwise, the resource - * will be released once the delayed callback has been - * completed. - */ - - VMCI_DEBUG_LOG(10, (LGPFX"Failed to schedule delayed doorbell " - "notification (result=%d).\n", result)); - VMCIResource_Release(resource); - } - } else { - entry->notifyCB(entry->clientData); - VMCIResource_Release(resource); - result = VMCI_SUCCESS; - } - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbell_Hibernate -- - * - * When a guest leaves hibernation, the device driver state is out of sync - * with the device state, since the driver state has doorbells registered - * that aren't known to the device. This function takes care of - * reregistering any doorbells. In case an error occurs during - * reregistration (this is highly unlikely since 1) it succeeded the first - * time 2) the device driver is the only source of doorbell registrations), - * we simply log the error. The doorbell can still be destroyed using - * VMCIDoorbell_Destroy. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIDoorbell_Hibernate(Bool enterHibernate) -{ - uint32 bucket; - VMCIListItem *iter; - VMCILockFlags flags; - - if (!VMCI_GuestPersonalityActive() || enterHibernate) { - return; - } - - VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags); - - for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); bucket++) { - VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) { - int result; - VMCIHandle h; - VMCIDoorbellEntry *cur; - - cur = VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem); - h = VMCIResource_Handle(&cur->resource); - result = VMCIDoorbellLink(h, cur->isDoorbell, cur->idx); - if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) { - VMCI_WARNING((LGPFX"Failed to reregister doorbell " - "(handle=0x%x:0x%x) of resource %s to index " - "(error=%d).\n", - h.context, h.resource, - cur->isDoorbell ? "doorbell" : "queue pair", result)); - } - } - } - - VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIDoorbell_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIDoorbell_Sync(void) -{ - VMCILockFlags flags; - VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags); - VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags); - VMCIResource_Sync(); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCI_RegisterNotificationBitmap -- - * - * Register the notification bitmap with the host. - * - * Results: - * TRUE if the bitmap is registered successfully with the device, FALSE - * otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -Bool -VMCI_RegisterNotificationBitmap(PPN bitmapPPN) -{ - int result; - VMCINotifyBitmapSetMsg bitmapSetMsg; - - /* - * Do not ASSERT() on the guest device here. This function can get called - * during device initialization, so the ASSERT() will fail even though - * the device is (almost) up. - */ - - bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_SET_NOTIFY_BITMAP); - bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE; - bitmapSetMsg.bitmapPPN = bitmapPPN; - - result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg); - if (result != VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as " - "notification bitmap (error=%d).\n", - bitmapPPN, result)); - return FALSE; - } - return TRUE; -} - - -/* - *------------------------------------------------------------------------- - * - * VMCIDoorbellFireEntries -- - * - * Executes or schedules the handlers for a given notify index. - * - * Result: - * Notification hash entry if found. NULL otherwise. - * - * Side effects: - * Whatever the side effects of the handlers are. - * - *------------------------------------------------------------------------- - */ - -static void -VMCIDoorbellFireEntries(uint32 notifyIdx) // IN -{ - uint32 bucket = VMCI_DOORBELL_HASH(notifyIdx); - VMCIListItem *iter; - VMCILockFlags flags; - - ASSERT(VMCI_GuestPersonalityActive()); - - VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags); - - VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) { - VMCIDoorbellEntry *cur = - VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem); - - ASSERT(cur); - - if (cur->idx == notifyIdx && Atomic_Read(&cur->active) == 1) { - ASSERT(cur->notifyCB); - if (cur->runDelayed) { - int err; - - VMCIResource_Hold(&cur->resource); - err = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, cur); - if (err != VMCI_SUCCESS) { - VMCIResource_Release(&cur->resource); - goto out; - } - } else { - cur->notifyCB(cur->clientData); - } - } - } - -out: - VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCI_ScanNotificationBitmap -- - * - * Scans the notification bitmap, collects pending notifications, - * resets the bitmap and invokes appropriate callbacks. - * - * Results: - * None. - * - * Side effects: - * May schedule tasks, allocate memory and run callbacks. - * - *------------------------------------------------------------------------------ - */ - -void -VMCI_ScanNotificationBitmap(uint8 *bitmap) -{ - uint32 idx; - - ASSERT(bitmap); - ASSERT(VMCI_GuestPersonalityActive()); - - for (idx = 0; idx < maxNotifyIdx; idx++) { - if (bitmap[idx] & 0x1) { - bitmap[idx] &= ~1; - VMCIDoorbellFireEntries(idx); - } - } -} - - -#else // __APPLE__ - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify/ - * VMCIDoorbellHostContextNotify/VMCIDoorbellGetPrivFlags/ - * VMCIDoorbell_Init/VMCIDoorbell_Exit -- - * - * The doorbell functions have yet to be implemented for Solaris - * and Mac OS X guest drivers. - * - * Results: - * VMCI_ERROR_UNAVAILABLE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create) -int -VMCIDoorbell_Create(VMCIHandle *handle, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - VMCICallback notifyCB, // IN - void *clientData) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy) -int -VMCIDoorbell_Destroy(VMCIHandle handle) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify) -int -VMCIDoorbell_Notify(VMCIHandle handle, // IN - VMCIPrivilegeFlags privFlags) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -int -VMCIDoorbellHostContextNotify(VMCIId srcCID, // IN - VMCIHandle handle) // IN -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -int -VMCIDoorbellGetPrivFlags(VMCIHandle handle, // IN - VMCIPrivilegeFlags *privFlags) // OUT -{ - return VMCI_ERROR_UNAVAILABLE; -} - - -int -VMCIDoorbell_Init(void) -{ - return VMCI_SUCCESS; -} - - -void -VMCIDoorbell_Exit(void) -{ -} - -#endif // __APPLE__ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.h b/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.h deleted file mode 100644 index ec6cb7c1a..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.h +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************* - * Copyright (C) 2010-2013 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciDoorbell.h -- - * - * Internal functions in the VMCI Doorbell API. - */ - -#ifndef VMCI_DOORBELL_H -#define VMCI_DOORBELL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_kernel_if.h" -#include "vmci_defs.h" - -int VMCIDoorbell_Init(void); -void VMCIDoorbell_Exit(void); -void VMCIDoorbell_Hibernate(Bool enterHibernation); -void VMCIDoorbell_Sync(void); - -int VMCIDoorbellHostContextNotify(VMCIId srcCID, VMCIHandle handle); -int VMCIDoorbellGetPrivFlags(VMCIHandle handle, VMCIPrivilegeFlags *privFlags); - -Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN); -void VMCI_ScanNotificationBitmap(uint8 *bitmap); - -#endif // VMCI_DOORBELL_H diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDriver.c b/open-vm-tools/modules/linux/vmci/common/vmciDriver.c deleted file mode 100644 index cd8cab9b8..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciDriver.c +++ /dev/null @@ -1,691 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * vmciDriver.c -- - * - * VMCI initialization and ioctl handling. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciContext.h" -#include "vmciDatagram.h" -#include "vmciDoorbell.h" -#include "vmciDriver.h" -#include "vmciEvent.h" -#include "vmciHashtable.h" -#include "vmciKernelAPI.h" -#include "vmciQueuePair.h" -#include "vmciResource.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -#endif - -#define LGPFX "VMCI: " - -static VMCIId ctxUpdateSubID = VMCI_INVALID_ID; -static VMCIContext *hostContext; -static Atomic_uint32 vmContextID = { VMCI_INVALID_ID }; - - -/* - *---------------------------------------------------------------------- - * - * VMCI_HostInit -- - * - * Initializes the host driver specific components of VMCI. - * - * Results: - * VMCI_SUCCESS if successful, appropriate error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCI_HostInit(void) -{ - int result; - - /* - * In theory, it is unsafe to pass an eventHnd of -1 to platforms which use - * it (VMKernel/Windows/Mac OS at the time of this writing). In practice we - * are fine though, because the event is never used in the case of the host - * context. - */ - result = VMCIContext_InitContext(VMCI_HOST_CONTEXT_ID, - VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS, - VMCI_HOST_CONTEXT_INVALID_EVENT, - VMCI_VERSION, NULL, &hostContext); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize VMCIContext (result=%d).\n", - result)); - goto errorExit; - } - - result = VMCIQPBroker_Init(); - if (result < VMCI_SUCCESS) { - goto hostContextExit; - } - - VMCI_DEBUG_LOG(0, (LGPFX"host components initialized.\n")); - return VMCI_SUCCESS; - -hostContextExit: - VMCIContext_ReleaseContext(hostContext); -errorExit: - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_HostCleanup -- - * - * Cleans up the host specific components of the VMCI module. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCI_HostCleanup(void) -{ - VMCIContext_ReleaseContext(hostContext); - VMCIQPBroker_Exit(); -} - - -#if defined(__APPLE__) || defined(VMKERNEL) -/* Windows has its own implementation of this, and Linux doesn't need one. */ -/* - *---------------------------------------------------------------------- - * - * vmci_device_get -- - * - * Verifies that a valid VMCI device is present, and indicates - * the callers intention to use the device until it calls - * VMCI_DeviceRelease(). - * - * Results: - * TRUE if a valid VMCI device is present, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_device_get) -Bool -vmci_device_get(uint32 *apiVersion, // IN/OUT - VMCI_DeviceShutdownFn *deviceShutdownCB, // UNUSED - void *userData, // UNUSED - void **deviceRegistration) // OUT -{ - if (NULL != deviceRegistration) { - *deviceRegistration = NULL; - } - - if (*apiVersion > VMCI_KERNEL_API_VERSION) { - *apiVersion = VMCI_KERNEL_API_VERSION; - return FALSE; - } - - if (!VMCI_DeviceEnabled()) { - return FALSE; - } - - return TRUE; -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_device_release -- - * - * Indicates that the caller is done using the VMCI device. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_device_release) -void -vmci_device_release(void *deviceRegistration) // UNUSED -{ -} -#endif // __APPLE__ || VMKERNEL - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUtilCidUpdate -- - * - * Gets called with the new context id if updated or resumed. - * - * Results: - * Context id. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIUtilCidUpdate(VMCIId subID, // IN: - VMCI_EventData *eventData, // IN: - void *clientData) // IN: -{ - VMCIEventPayload_Context *evPayload = VMCIEventDataPayload(eventData); - - UNREFERENCED_PARAMETER(clientData); - - if (subID != ctxUpdateSubID) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid subscriber (ID=0x%x).\n", subID)); - return; - } - if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid event data.\n")); - return; - } - VMCI_LOG((LGPFX"Updating context from (ID=0x%x) to (ID=0x%x) on event " - "(type=%d).\n", Atomic_Read(&vmContextID), evPayload->contextID, - eventData->event)); - Atomic_Write(&vmContextID, evPayload->contextID); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUtil_Init -- - * - * Subscribe to context id update event. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIUtil_Init(void) -{ - /* - * We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can update the - * internal context id when needed. - */ - if (vmci_event_subscribe(VMCI_EVENT_CTX_ID_UPDATE, -#if !defined(__linux__) || defined(VMKERNEL) - VMCI_FLAG_EVENT_NONE, -#endif // !linux || VMKERNEL - VMCIUtilCidUpdate, NULL, - &ctxUpdateSubID) < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to subscribe to event (type=%d).\n", - VMCI_EVENT_CTX_ID_UPDATE)); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUtil_Exit -- - * - * Cleanup - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIUtil_Exit(void) -{ - if (vmci_event_unsubscribe(ctxUpdateSubID) < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to unsubscribe to event (type=%d) with " - "subscriber (ID=0x%x).\n", VMCI_EVENT_CTX_ID_UPDATE, - ctxUpdateSubID)); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUtil_CheckHostCapabilities -- - * - * Verify that the host supports the hypercalls we need. If it does not, - * try to find fallback hypercalls and use those instead. - * - * Results: - * TRUE if required hypercalls (or fallback hypercalls) are - * supported by the host, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -#define VMCI_UTIL_NUM_RESOURCES 1 - -static Bool -VMCIUtilCheckHostCapabilities(void) -{ - int result; - VMCIResourcesQueryMsg *msg; - uint32 msgSize = sizeof(VMCIResourcesQueryHdr) + - VMCI_UTIL_NUM_RESOURCES * sizeof(VMCI_Resource); - VMCIDatagram *checkMsg = VMCI_AllocKernelMem(msgSize, VMCI_MEMORY_NONPAGED); - - if (checkMsg == NULL) { - VMCI_WARNING((LGPFX"Check host: Insufficient memory.\n")); - return FALSE; - } - - checkMsg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_RESOURCES_QUERY); - checkMsg->src = VMCI_ANON_SRC_HANDLE; - checkMsg->payloadSize = msgSize - VMCI_DG_HEADERSIZE; - msg = (VMCIResourcesQueryMsg *)VMCI_DG_PAYLOAD(checkMsg); - - msg->numResources = VMCI_UTIL_NUM_RESOURCES; - msg->resources[0] = VMCI_GET_CONTEXT_ID; - - result = VMCI_SendDatagram(checkMsg); - VMCI_FreeKernelMem(checkMsg, msgSize); - - /* We need the vector. There are no fallbacks. */ - return (result == 0x1); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_CheckHostCapabilities -- - * - * Tell host which guestcalls we support and let each API check - * that the host supports the hypercalls it needs. If a hypercall - * is not supported, the API can check for a fallback hypercall, - * or fail the check. - * - * Results: - * TRUE if successful, FALSE otherwise. - * - * Side effects: - * Fallback mechanisms may be enabled in the API and vmmon. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCI_CheckHostCapabilities(void) -{ - Bool result = VMCIEvent_CheckHostCapabilities(); - result &= VMCIDatagram_CheckHostCapabilities(); - result &= VMCIUtilCheckHostCapabilities(); - - 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; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_ReadDatagramsFromPort -- - * - * Reads datagrams from the data in port and dispatches them. We - * always start reading datagrams into only the first page of the - * datagram buffer. If the datagrams don't fit into one page, we - * use the maximum datagram buffer size for the remainder of the - * invocation. This is a simple heuristic for not penalizing - * small datagrams. - * - * This function assumes that it has exclusive access to the data - * in port for the duration of the call. - * - * Results: - * No result. - * - * Side effects: - * Datagram handlers may be invoked. - * - *---------------------------------------------------------------------- - */ - -void -VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, // IN - VMCIIoPort dgInPort, // IN - uint8 *dgInBuffer, // IN - size_t dgInBufferSize) // IN -{ - VMCIDatagram *dg; - size_t currentDgInBufferSize = PAGE_SIZE; - size_t remainingBytes; - - ASSERT(dgInBufferSize >= PAGE_SIZE); - - VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize); - dg = (VMCIDatagram *)dgInBuffer; - remainingBytes = currentDgInBufferSize; - - while (dg->dst.resource != VMCI_INVALID_ID || remainingBytes > PAGE_SIZE) { - size_t dgInSize; - - /* - * When the input buffer spans multiple pages, a datagram can - * start on any page boundary in the buffer. - */ - - if (dg->dst.resource == VMCI_INVALID_ID) { - ASSERT(remainingBytes > PAGE_SIZE); - dg = (VMCIDatagram *)ROUNDUP((uintptr_t)dg + 1, PAGE_SIZE); - ASSERT((uint8 *)dg < dgInBuffer + currentDgInBufferSize); - remainingBytes = (size_t)(dgInBuffer + currentDgInBufferSize - (uint8 *)dg); - continue; - } - - dgInSize = VMCI_DG_SIZE_ALIGNED(dg); - - if (dgInSize <= dgInBufferSize) { - int result; - - /* - * If the remaining bytes in the datagram buffer doesn't - * contain the complete datagram, we first make sure we have - * enough room for it and then we read the reminder of the - * datagram and possibly any following datagrams. - */ - - if (dgInSize > remainingBytes) { - - if (remainingBytes != currentDgInBufferSize) { - - /* - * We move the partial datagram to the front and read - * the reminder of the datagram and possibly following - * calls into the following bytes. - */ - - memmove(dgInBuffer, dgInBuffer + currentDgInBufferSize - remainingBytes, - remainingBytes); - - dg = (VMCIDatagram *)dgInBuffer; - } - - if (currentDgInBufferSize != dgInBufferSize) { - currentDgInBufferSize = dgInBufferSize; - } - - VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer + remainingBytes, - currentDgInBufferSize - remainingBytes); - } - - /* We special case event datagrams from the hypervisor. */ - if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID && - dg->dst.resource == VMCI_EVENT_HANDLER) { - result = VMCIEvent_Dispatch(dg); - } else { - result = VMCIDatagram_InvokeGuestHandler(dg); - } - if (result < VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Datagram with resource (ID=0x%x) failed " - "(err=%d).\n", dg->dst.resource, result)); - } - - /* On to the next datagram. */ - dg = (VMCIDatagram *)((uint8 *)dg + dgInSize); - } else { - size_t bytesToSkip; - - /* - * Datagram doesn't fit in datagram buffer of maximal size. We drop it. - */ - - VMCI_DEBUG_LOG(4, (LGPFX"Failed to receive datagram (size=%"FMTSZ"u bytes).\n", - dgInSize)); - - bytesToSkip = dgInSize - remainingBytes; - if (currentDgInBufferSize != dgInBufferSize) { - currentDgInBufferSize = dgInBufferSize; - } - for (;;) { - VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize); - if (bytesToSkip <= currentDgInBufferSize) { - break; - } - bytesToSkip -= currentDgInBufferSize; - } - dg = (VMCIDatagram *)(dgInBuffer + bytesToSkip); - } - - remainingBytes = (size_t) (dgInBuffer + currentDgInBufferSize - (uint8 *)dg); - - if (remainingBytes < VMCI_DG_HEADERSIZE) { - /* Get the next batch of datagrams. */ - - VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize); - dg = (VMCIDatagram *)dgInBuffer; - remainingBytes = currentDgInBufferSize; - } - } -} - - -/* - *---------------------------------------------------------------------------- - * - * vmci_get_context_id -- - * - * Returns the current context ID. Note that since this is accessed only - * from code running in the host, this always returns the host context ID. - * - * Results: - * Context ID. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_get_context_id) -VMCIId -vmci_get_context_id(void) -{ - if (VMCI_GuestPersonalityActive()) { - if (Atomic_Read(&vmContextID) == VMCI_INVALID_ID) { - uint32 result; - VMCIDatagram getCidMsg; - getCidMsg.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_GET_CONTEXT_ID); - getCidMsg.src = VMCI_ANON_SRC_HANDLE; - getCidMsg.payloadSize = 0; - result = VMCI_SendDatagram(&getCidMsg); - Atomic_Write(&vmContextID, result); - } - return Atomic_Read(&vmContextID); - } else if (VMCI_HostPersonalityActive()) { - return VMCI_HOST_CONTEXT_ID; - } - return VMCI_INVALID_ID; -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_version -- - * - * Returns the version of the VMCI driver. - * - * Results: - * Returns a version number. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_version) -uint32 -vmci_version(void) -{ - return VMCI_VERSION; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_SharedInit -- - * - * Initializes VMCI components shared between guest and host - * driver. This registers core hypercalls. - * - * Results: - * VMCI_SUCCESS if successful, appropriate error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCI_SharedInit(void) -{ - int result; - - result = VMCIResource_Init(); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize VMCIResource (result=%d).\n", - result)); - goto errorExit; - } - - result = VMCIContext_Init(); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize VMCIContext (result=%d).\n", - result)); - goto resourceExit; - } - - result = VMCIDatagram_Init(); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize VMCIDatagram (result=%d).\n", - result)); - goto contextExit; - } - - result = VMCIEvent_Init(); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize VMCIEvent (result=%d).\n", - result)); - goto datagramExit; - } - - result = VMCIDoorbell_Init(); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to initialize VMCIDoorbell (result=%d).\n", - result)); - goto eventExit; - } - - VMCI_DEBUG_LOG(0, (LGPFX"shared components initialized.\n")); - return VMCI_SUCCESS; - -eventExit: - VMCIEvent_Exit(); -datagramExit: - VMCIDatagram_Exit(); -contextExit: - VMCIContext_Exit(); -resourceExit: - VMCIResource_Exit(); -errorExit: - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_SharedCleanup -- - * - * Cleans up VMCI components shared between guest and host - * driver. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCI_SharedCleanup(void) -{ - VMCIDoorbell_Exit(); - VMCIEvent_Exit(); - VMCIDatagram_Exit(); - VMCIContext_Exit(); - VMCIResource_Exit(); -} diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDriver.h b/open-vm-tools/modules/linux/vmci/common/vmciDriver.h deleted file mode 100644 index 8514f1c7d..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciDriver.h +++ /dev/null @@ -1,98 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2013 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 - * - *********************************************************/ - -/* - * vmciDriver.h -- - * - * VMCI host driver interface. - */ - -#ifndef _VMCI_DRIVER_H_ -#define _VMCI_DRIVER_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciContext.h" - -/* - * A few macros to encapsulate logging in common code. The macros - * result in LOG/LOGThrottled on vmkernel and Log on hosted. - */ - -#ifdef _WIN32 -# include "vmciLog.h" -#else // _WIN32 -#if defined(VMKERNEL) && !defined(VMKERNEL_OFFSET_CHECKER) - /* - * LOGLEVEL_MODULE is defined in another header that gets included into the - * dummy file used by the offsetchecker, which causes it to barf on the - * redefinition. - */ -# define LOGLEVEL_MODULE_LEN 0 -# define LOGLEVEL_MODULE VMCIVMK -# include "log.h" -# ifdef VMX86_LOG -# define _VMCILOG(_args...) LOG(i, _args) -# define VMCI_DEBUG_LOG(_level, _args) \ - do { \ - int i = _level; \ - _VMCILOG _args ; \ - } while(FALSE) -# else // VMX86_LOG -# define VMCI_DEBUG_LOG(_level, _args) -# endif // VMX86_LOG -#else // VMKERNEL -# define VMCI_DEBUG_LEVEL 4 -# define VMCI_DEBUG_LOG(_level, _args) \ - do { \ - if (_level < VMCI_DEBUG_LEVEL) { \ - Log _args ; \ - } \ - } while(FALSE) -#endif // VMKERNEL -#define VMCI_LOG(_args) Log _args -#define VMCI_WARNING(_args) Warning _args -#endif // _WIN32 - - -int VMCI_SharedInit(void); -void VMCI_SharedCleanup(void); -int VMCI_HostInit(void); -void VMCI_HostCleanup(void); -VMCIId VMCI_GetContextID(void); -int VMCI_SendDatagram(VMCIDatagram *dg); - -void VMCIUtil_Init(void); -void VMCIUtil_Exit(void); -Bool VMCI_CheckHostCapabilities(void); -void VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, VMCIIoPort dgInPort, - uint8 *dgInBuffer, size_t dgInBufferSize); -Bool VMCI_DeviceEnabled(void); -#if defined(_WIN64) -int VMCIDoSendDatagram(unsigned int dgSize, ULONG *dataPort, ULONG *resultPort, - VMCIDatagram *dg); -#endif // _WIN64 - - -#endif // _VMCI_DRIVER_H_ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciEvent.c b/open-vm-tools/modules/linux/vmci/common/vmciEvent.c deleted file mode 100644 index 8a5a4b447..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciEvent.c +++ /dev/null @@ -1,803 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2016 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 - * - *********************************************************/ - -/* - * vmciEvent.c -- - * - * VMCI Event code for host and guests. - */ - -#include "vmci_kernel_if.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciEvent.h" -#include "vmciKernelAPI.h" -#if defined(_WIN32) -# include "kernelStubsSal.h" -#endif -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -# include "vmciDriver.h" -#else -# include "vmciDriver.h" -#endif - -#define LGPFX "VMCIEvent: " - -#define EVENT_MAGIC 0xEABE0000 - -typedef struct VMCISubscription { - VMCIId id; - int refCount; - Bool runDelayed; - VMCIEvent destroyEvent; - VMCI_Event event; - VMCI_EventCB callback; - void *callbackData; - VMCIListItem subscriberListItem; -} VMCISubscription; - - -static VMCISubscription *VMCIEventFind(VMCIId subID); -static int VMCIEventDeliver(VMCIEventMsg *eventMsg); -static int VMCIEventRegisterSubscription(VMCISubscription *sub, - VMCI_Event event, - uint32 flags, - VMCI_EventCB callback, - void *callbackData); -static VMCISubscription *VMCIEventUnregisterSubscription(VMCIId subID); - -static VMCIList subscriberArray[VMCI_EVENT_MAX]; -static VMCILock subscriberLock; - -typedef struct VMCIDelayedEventInfo { - VMCISubscription *sub; - uint8 eventPayload[sizeof(VMCIEventData_Max)]; -} VMCIDelayedEventInfo; - -typedef struct VMCIEventRef { - VMCISubscription *sub; - VMCIListItem listItem; -} VMCIEventRef; - -/* - *---------------------------------------------------------------------- - * - * VMCIEvent_Init -- - * - * General init code. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIEvent_Init(void) -{ - int i; - - for (i = 0; i < VMCI_EVENT_MAX; i++) { - VMCIList_Init(&subscriberArray[i]); - } - - return VMCI_InitLock(&subscriberLock, "VMCIEventSubscriberLock", - VMCI_LOCK_RANK_EVENT); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIEvent_Exit -- - * - * General exit code. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIEvent_Exit(void) -{ - VMCIListItem *iter, *iter2; - VMCI_Event e; - - /* We free all memory at exit. */ - for (e = 0; e < VMCI_EVENT_MAX; e++) { - VMCIList_ScanSafe(iter, iter2, &subscriberArray[e]) { - VMCISubscription *cur; - - /* - * We should never get here because all events should have been - * unregistered before we try to unload the driver module. - * Also, delayed callbacks could still be firing so this cleanup - * would not be safe. - * Still it is better to free the memory than not ... so we - * leave this code in just in case.... - * - */ - ASSERT(FALSE); - - cur = VMCIList_Entry(iter, VMCISubscription, subscriberListItem); - VMCI_FreeKernelMem(cur, sizeof *cur); - } - } - VMCI_CleanupLock(&subscriberLock); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIEvent_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * TRUE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIEvent_Sync(void) -{ - VMCILockFlags lockFlags; - VMCI_GrabLock_BH(&subscriberLock, &lockFlags); - VMCI_ReleaseLock_BH(&subscriberLock, lockFlags); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIEvent_CheckHostCapabilities -- - * - * Verify that the host supports the hypercalls we need. If it does not, - * try to find fallback hypercalls and use those instead. - * - * Results: - * TRUE if required hypercalls (or fallback hypercalls) are - * supported by the host, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCIEvent_CheckHostCapabilities(void) -{ - /* VMCIEvent does not require any hypercalls. */ - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIEventGet -- - * - * Gets a reference to the given VMCISubscription. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIEventGet(VMCISubscription *entry) // IN -{ - ASSERT(entry); - - entry->refCount++; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIEventRelease -- - * - * Releases the given VMCISubscription. - * - * Results: - * None. - * - * Side effects: - * Fires the destroy event if the reference count has gone to zero. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIEventRelease(VMCISubscription *entry) // IN -{ - ASSERT(entry); - ASSERT(entry->refCount > 0); - - entry->refCount--; - if (entry->refCount == 0) { - VMCI_SignalEvent(&entry->destroyEvent); - } -} - - - /* - *------------------------------------------------------------------------------ - * - * EventReleaseCB -- - * - * Callback to release the event entry reference. It is called by the - * VMCI_WaitOnEvent function before it blocks. - * - * Result: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -EventReleaseCB(void *clientData) // IN -{ - VMCILockFlags flags; - VMCISubscription *sub = (VMCISubscription *)clientData; - - ASSERT(sub); - - VMCI_GrabLock_BH(&subscriberLock, &flags); - VMCIEventRelease(sub); - VMCI_ReleaseLock_BH(&subscriberLock, flags); - - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIEventFind -- - * - * Find entry. Assumes lock is held. - * - * Results: - * Entry if found, NULL if not. - * - * Side effects: - * Increments the VMCISubscription refcount if an entry is found. - * - *----------------------------------------------------------------------------- - */ - -static VMCISubscription * -VMCIEventFind(VMCIId subID) // IN -{ - VMCIListItem *iter; - VMCI_Event e; - - for (e = 0; e < VMCI_EVENT_MAX; e++) { - VMCIList_Scan(iter, &subscriberArray[e]) { - VMCISubscription *cur = - VMCIList_Entry(iter, VMCISubscription, subscriberListItem); - if (cur->id == subID) { - VMCIEventGet(cur); - return cur; - } - } - } - return NULL; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIEventDelayedDispatchCB -- - * - * Calls the specified callback in a delayed context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -VMCIEventDelayedDispatchCB(void *data) // IN -{ - VMCIDelayedEventInfo *eventInfo; - VMCISubscription *sub; - VMCI_EventData *ed; - VMCILockFlags flags; - - eventInfo = (VMCIDelayedEventInfo *)data; - - ASSERT(eventInfo); - ASSERT(eventInfo->sub); - - sub = eventInfo->sub; - ed = (VMCI_EventData *)eventInfo->eventPayload; - - sub->callback(sub->id, ed, sub->callbackData); - - VMCI_GrabLock_BH(&subscriberLock, &flags); - VMCIEventRelease(sub); - VMCI_ReleaseLock_BH(&subscriberLock, flags); - - VMCI_FreeKernelMem(eventInfo, sizeof *eventInfo); -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCIEventDeliver -- - * - * Actually delivers the events to the subscribers. - * - * Results: - * None. - * - * Side effects: - * The callback function for each subscriber is invoked. - * - *---------------------------------------------------------------------------- - */ - -static int -VMCIEventDeliver(VMCIEventMsg *eventMsg) // IN -{ - int err = VMCI_SUCCESS; - VMCIListItem *iter; - VMCILockFlags flags; - - VMCIList noDelayList; - VMCIList_Init(&noDelayList); - - ASSERT(eventMsg); - - VMCI_GrabLock_BH(&subscriberLock, &flags); - VMCIList_Scan(iter, &subscriberArray[eventMsg->eventData.event]) { - VMCISubscription *cur = VMCIList_Entry(iter, VMCISubscription, - subscriberListItem); - ASSERT(cur && cur->event == eventMsg->eventData.event); -#if defined(_WIN32) - _Analysis_assume_(cur != NULL); -#endif - - if (cur->runDelayed) { - VMCIDelayedEventInfo *eventInfo; - if ((eventInfo = VMCI_AllocKernelMem(sizeof *eventInfo, - (VMCI_MEMORY_ATOMIC | - VMCI_MEMORY_NONPAGED))) == NULL) { - err = VMCI_ERROR_NO_MEM; - goto out; - } - - VMCIEventGet(cur); - - memset(eventInfo, 0, sizeof *eventInfo); - memcpy(eventInfo->eventPayload, VMCI_DG_PAYLOAD(eventMsg), - (size_t)eventMsg->hdr.payloadSize); - eventInfo->sub = cur; - err = VMCI_ScheduleDelayedWork(VMCIEventDelayedDispatchCB, - eventInfo); - if (err != VMCI_SUCCESS) { - VMCIEventRelease(cur); - VMCI_FreeKernelMem(eventInfo, sizeof *eventInfo); - goto out; - } - - } else { - VMCIEventRef *eventRef; - - /* - * To avoid possible lock rank voilation when holding - * subscriberLock, we construct a local list of - * subscribers and release subscriberLock before - * invokes the callbacks. This is similar to delayed - * callbacks, but callbacks is invoked right away here. - */ - if ((eventRef = VMCI_AllocKernelMem(sizeof *eventRef, - (VMCI_MEMORY_ATOMIC | - VMCI_MEMORY_NONPAGED))) == NULL) { - err = VMCI_ERROR_NO_MEM; - goto out; - } - - VMCIEventGet(cur); - eventRef->sub = cur; - VMCIList_InitEntry(&eventRef->listItem); - VMCIList_Insert(&eventRef->listItem, &noDelayList); - } - } - -out: - VMCI_ReleaseLock_BH(&subscriberLock, flags); - - if (!VMCIList_Empty(&noDelayList)) { - VMCI_EventData *ed; - VMCIListItem *iter2; - -/* - * The below ScanSafe macro makes the analyzer think iter might be NULL and - * then dereferenced. - */ -#if defined(_WIN32) -#pragma warning(suppress: 28182) -#endif - VMCIList_ScanSafe(iter, iter2, &noDelayList) { - VMCIEventRef *eventRef = VMCIList_Entry(iter, VMCIEventRef, - listItem); - VMCISubscription *cur = eventRef->sub; - uint8 eventPayload[sizeof(VMCIEventData_Max)]; - - /* We set event data before each callback to ensure isolation. */ - memset(eventPayload, 0, sizeof eventPayload); - memcpy(eventPayload, VMCI_DG_PAYLOAD(eventMsg), - (size_t)eventMsg->hdr.payloadSize); - ed = (VMCI_EventData *)eventPayload; - cur->callback(cur->id, ed, cur->callbackData); - - VMCI_GrabLock_BH(&subscriberLock, &flags); - VMCIEventRelease(cur); - VMCI_ReleaseLock_BH(&subscriberLock, flags); - VMCI_FreeKernelMem(eventRef, sizeof *eventRef); - } - } - - return err; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIEvent_Dispatch -- - * - * Dispatcher for the VMCI_EVENT_RECEIVE datagrams. Calls all - * subscribers for given event. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -VMCIEvent_Dispatch(VMCIDatagram *msg) // IN -{ - VMCIEventMsg *eventMsg = (VMCIEventMsg *)msg; - - ASSERT(msg && - msg->src.context == VMCI_HYPERVISOR_CONTEXT_ID && - msg->dst.resource == VMCI_EVENT_HANDLER); - - if (msg->payloadSize < sizeof(VMCI_Event) || - msg->payloadSize > sizeof(VMCIEventData_Max)) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (!VMCI_EVENT_VALID(eventMsg->eventData.event)) { - return VMCI_ERROR_EVENT_UNKNOWN; - } - - VMCIEventDeliver(eventMsg); - - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIEventRegisterSubscription -- - * - * Initialize and add subscription to subscriber list. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -VMCIEventRegisterSubscription(VMCISubscription *sub, // IN - VMCI_Event event, // IN - uint32 flags, // IN - VMCI_EventCB callback, // IN - void *callbackData) // IN -{ -# define VMCI_EVENT_MAX_ATTEMPTS 10 - static VMCIId subscriptionID = 0; - VMCILockFlags lockFlags; - uint32 attempts = 0; - int result; - Bool success; - - ASSERT(sub); - - if (!VMCI_EVENT_VALID(event) || callback == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to subscribe to event (type=%d) " - "(callback=%p) (data=%p).\n", - event, callback, callbackData)); - return VMCI_ERROR_INVALID_ARGS; - } - - if (vmkernel) { - /* - * In the vmkernel we defer delivery of events to a helper world. This - * makes the event delivery more consistent across hosts and guests with - * regard to which locks are held. Memory access and guest paused events - * are an exception to this, since clients need to know immediately that - * the device memory is disabled (if we delay such events, then clients - * may be notified too late). - */ - if (VMCI_EVENT_MEM_ACCESS_ON == event || - VMCI_EVENT_MEM_ACCESS_OFF == event || - VMCI_EVENT_GUEST_PAUSED == event || - VMCI_EVENT_GUEST_UNPAUSED == event) { - /* - * Client must expect to get such events synchronously, and should - * perform its locking accordingly. If it can't handle this, then - * fail. - */ - if (flags & VMCI_FLAG_EVENT_DELAYED_CB) { - return VMCI_ERROR_INVALID_ARGS; - } - sub->runDelayed = FALSE; - } else { - sub->runDelayed = TRUE; - } - } else if (!VMCI_CanScheduleDelayedWork()) { - /* - * If the platform doesn't support delayed work callbacks then don't - * allow registration for them. - */ - if (flags & VMCI_FLAG_EVENT_DELAYED_CB) { - return VMCI_ERROR_INVALID_ARGS; - } - sub->runDelayed = FALSE; - } else { - /* - * The platform supports delayed work callbacks. Honor the requested - * flags - */ - sub->runDelayed = (flags & VMCI_FLAG_EVENT_DELAYED_CB) ? TRUE : FALSE; - } - - sub->refCount = 1; - sub->event = event; - sub->callback = callback; - sub->callbackData = callbackData; - VMCIList_InitEntry(&sub->subscriberListItem); - - VMCI_GrabLock_BH(&subscriberLock, &lockFlags); - - /* Check if creation of a new event is allowed. */ - if (!VMCI_CanCreate()) { - result = VMCI_ERROR_UNAVAILABLE; - goto exit; - } - - for (success = FALSE, attempts = 0; - success == FALSE && attempts < VMCI_EVENT_MAX_ATTEMPTS; - attempts++) { - VMCISubscription *existingSub = NULL; - - /* - * We try to get an id a couple of time before claiming we are out of - * resources. - */ - sub->id = ++subscriptionID; - - /* Test for duplicate id. */ - existingSub = VMCIEventFind(sub->id); - if (existingSub == NULL) { - /* We succeeded if we didn't find a duplicate. */ - success = TRUE; - } else { - VMCIEventRelease(existingSub); - } - } - - if (success) { - VMCI_CreateEvent(&sub->destroyEvent); - VMCIList_Insert(&sub->subscriberListItem, &subscriberArray[event]); - result = VMCI_SUCCESS; - } else { - result = VMCI_ERROR_NO_RESOURCES; - } - -exit: - VMCI_ReleaseLock_BH(&subscriberLock, lockFlags); - return result; -# undef VMCI_EVENT_MAX_ATTEMPTS -} - - - -/* - *---------------------------------------------------------------------- - * - * VMCIEventUnregisterSubscription -- - * - * Remove subscription from subscriber list. - * - * Results: - * VMCISubscription when found, NULL otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static VMCISubscription * -VMCIEventUnregisterSubscription(VMCIId subID) // IN -{ - VMCILockFlags flags; - VMCISubscription *s; - - VMCI_GrabLock_BH(&subscriberLock, &flags); - s = VMCIEventFind(subID); - if (s != NULL) { - VMCIEventRelease(s); - VMCIList_Remove(&s->subscriberListItem); - } - VMCI_ReleaseLock_BH(&subscriberLock, flags); - - if (s != NULL) { - VMCI_WaitOnEvent(&s->destroyEvent, EventReleaseCB, s); - VMCI_DestroyEvent(&s->destroyEvent); - } - - return s; -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_event_subscribe -- - * - * Subscribe to given event. The callback specified can be fired - * in different contexts depending on what flag is specified while - * registering. If flags contains VMCI_FLAG_EVENT_NONE then the - * callback is fired with the subscriber lock held (and BH context - * on the guest). If flags contain VMCI_FLAG_EVENT_DELAYED_CB then - * the callback is fired with no locks held in thread context. - * This is useful because other VMCIEvent functions can be called, - * but it also increases the chances that an event will be dropped. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_event_subscribe) -int -vmci_event_subscribe(VMCI_Event event, // IN -#if !defined(__linux__) || defined(VMKERNEL) - uint32 flags, // IN -#endif // !linux || VMKERNEL - VMCI_EventCB callback, // IN - void *callbackData, // IN - VMCIId *subscriptionID) // OUT -{ - int retval; -#if defined(__linux__) && !defined(VMKERNEL) - uint32 flags = VMCI_FLAG_EVENT_NONE; -#endif // linux && !VMKERNEL - VMCISubscription *s = NULL; - - if (subscriptionID == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid subscription (NULL).\n")); - return VMCI_ERROR_INVALID_ARGS; - } - - s = VMCI_AllocKernelMem(sizeof *s, VMCI_MEMORY_NONPAGED); - if (s == NULL) { - return VMCI_ERROR_NO_MEM; - } - - retval = VMCIEventRegisterSubscription(s, event, flags, - callback, callbackData); - if (retval < VMCI_SUCCESS) { - VMCI_FreeKernelMem(s, sizeof *s); - return retval; - } - - *subscriptionID = s->id; - return retval; -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_event_unsubscribe -- - * - * Unsubscribe to given event. Removes it from list and frees it. - * Will return callbackData if requested by caller. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_event_unsubscribe) -int -vmci_event_unsubscribe(VMCIId subID) // IN -{ - VMCISubscription *s; - - /* - * Return subscription. At this point we know noone else is accessing - * the subscription so we can free it. - */ - s = VMCIEventUnregisterSubscription(subID); - if (s == NULL) { - return VMCI_ERROR_NOT_FOUND; - - } - VMCI_FreeKernelMem(s, sizeof *s); - - return VMCI_SUCCESS; -} diff --git a/open-vm-tools/modules/linux/vmci/common/vmciEvent.h b/open-vm-tools/modules/linux/vmci/common/vmciEvent.h deleted file mode 100644 index 720b50dae..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciEvent.h +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciEvent.h -- - * - * Event code for the vmci guest driver - */ - -#ifndef __VMCI_EVENT_H__ -#define __VMCI_EVENT_H__ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" -#include "vmci_call_defs.h" - -int VMCIEvent_Init(void); -void VMCIEvent_Exit(void); -void VMCIEvent_Sync(void); -int VMCIEvent_Dispatch(VMCIDatagram *msg); -Bool VMCIEvent_CheckHostCapabilities(void); - -#endif //__VMCI_EVENT_H__ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciHashtable.c b/open-vm-tools/modules/linux/vmci/common/vmciHashtable.c deleted file mode 100644 index b7b577d98..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciHashtable.c +++ /dev/null @@ -1,607 +0,0 @@ -/********************************************************* - * 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 - * 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 - * - *********************************************************/ - -/* - * vmciHashtable.c -- - * - * Implementation of the VMCI Hashtable. - * TODO: Look into what is takes to use lib/misc/hashTable.c instead of - * our own implementation. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciDriver.h" -#include "vmciHashtable.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -#endif - -#define LGPFX "VMCIHashTable: " - -#define VMCI_HASHTABLE_HASH(_h, _sz) \ - VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(_h), (_sz)) - -static int HashTableUnlinkEntry(VMCIHashTable *table, VMCIHashEntry *entry); -static Bool VMCIHashTableEntryExistsLocked(VMCIHashTable *table, - VMCIHandle handle); - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_Create -- - * XXX Factor out the hashtable code to be shared amongst host and guest. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCIHashTable * -VMCIHashTable_Create(int size) -{ - VMCIHashTable *table = VMCI_AllocKernelMem(sizeof *table, - VMCI_MEMORY_NONPAGED); - if (table == NULL) { - return NULL; - } - - table->entries = VMCI_AllocKernelMem(sizeof *table->entries * size, - VMCI_MEMORY_NONPAGED); - if (table->entries == NULL) { - VMCI_FreeKernelMem(table, sizeof *table); - return NULL; - } - memset(table->entries, 0, sizeof *table->entries * size); - table->size = size; - if (VMCI_InitLock(&table->lock, "VMCIHashTableLock", - VMCI_LOCK_RANK_HASHTABLE) < VMCI_SUCCESS) { - VMCI_FreeKernelMem(table->entries, sizeof *table->entries * size); - VMCI_FreeKernelMem(table, sizeof *table); - return NULL; - } - - return table; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_Destroy -- - * This function should be called at module exit time. - * We rely on the module ref count to insure that no one is accessing any - * hash table entries at this point in time. Hence we should be able to just - * remove all entries from the hash table. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIHashTable_Destroy(VMCIHashTable *table) -{ - VMCILockFlags flags; -#if 0 - DEBUG_ONLY(int i;) - DEBUG_ONLY(int leakingEntries = 0;) -#endif - - ASSERT(table); - - VMCI_GrabLock_BH(&table->lock, &flags); -#if 0 -#ifdef VMX86_DEBUG - for (i = 0; i < table->size; i++) { - VMCIHashEntry *head = table->entries[i]; - while (head) { - leakingEntries++; - head = head->next; - } - } - if (leakingEntries) { - VMCI_WARNING((LGPFX"Leaking entries (%d) for hash table (%p).\n", - leakingEntries, table)); - } -#endif // VMX86_DEBUG -#endif - VMCI_FreeKernelMem(table->entries, sizeof *table->entries * table->size); - table->entries = NULL; - VMCI_ReleaseLock_BH(&table->lock, flags); - VMCI_CleanupLock(&table->lock); - VMCI_FreeKernelMem(table, sizeof *table); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_InitEntry -- - * Initializes a hash entry; - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ -void -VMCIHashTable_InitEntry(VMCIHashEntry *entry, // IN - VMCIHandle handle) // IN -{ - ASSERT(entry); - entry->handle = handle; - entry->refCount = 0; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_AddEntry -- - * XXX Factor out the hashtable code to be shared amongst host and guest. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIHashTable_AddEntry(VMCIHashTable *table, // IN - VMCIHashEntry *entry) // IN -{ - int idx; - VMCILockFlags flags; - - ASSERT(entry); - ASSERT(table); - - VMCI_GrabLock_BH(&table->lock, &flags); - - /* Check if creation of a new hashtable entry is allowed. */ - if (!VMCI_CanCreate()) { - VMCI_ReleaseLock_BH(&table->lock, flags); - return VMCI_ERROR_UNAVAILABLE; - } - - if (VMCIHashTableEntryExistsLocked(table, entry->handle)) { - VMCI_DEBUG_LOG(4, (LGPFX"Entry (handle=0x%x:0x%x) already exists.\n", - entry->handle.context, entry->handle.resource)); - VMCI_ReleaseLock_BH(&table->lock, flags); - return VMCI_ERROR_DUPLICATE_ENTRY; - } - - idx = VMCI_HASHTABLE_HASH(entry->handle, table->size); - ASSERT(idx < table->size); - - /* New entry is added to top/front of hash bucket. */ - entry->refCount++; - entry->next = table->entries[idx]; - table->entries[idx] = entry; - VMCI_ReleaseLock_BH(&table->lock, flags); - - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_RemoveEntry -- - * XXX Factor out the hashtable code to shared amongst API and perhaps - * host and guest. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIHashTable_RemoveEntry(VMCIHashTable *table, // IN - VMCIHashEntry *entry) // IN -{ - int result; - VMCILockFlags flags; - - ASSERT(table); - ASSERT(entry); - - VMCI_GrabLock_BH(&table->lock, &flags); - - /* First unlink the entry. */ - result = HashTableUnlinkEntry(table, entry); - if (result != VMCI_SUCCESS) { - /* We failed to find the entry. */ - goto done; - } - - /* Decrement refcount and check if this is last reference. */ - entry->refCount--; - if (entry->refCount == 0) { - result = VMCI_SUCCESS_ENTRY_DEAD; - goto done; - } - - done: - VMCI_ReleaseLock_BH(&table->lock, flags); - - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTableGetEntryLocked -- - * - * Looks up an entry in the hash table, that is already locked. - * - * Result: - * If the element is found, a pointer to the element is returned. - * Otherwise NULL is returned. - * - * Side effects: - * The reference count of the returned element is increased. - * - *------------------------------------------------------------------------------ - */ - -static VMCIHashEntry * -VMCIHashTableGetEntryLocked(VMCIHashTable *table, // IN - VMCIHandle handle) // IN -{ - VMCIHashEntry *cur = NULL; - int idx; - - ASSERT(!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)); - ASSERT(table); - - idx = VMCI_HASHTABLE_HASH(handle, table->size); - - cur = table->entries[idx]; - while (TRUE) { - if (cur == NULL) { - break; - } - - if (VMCI_HANDLE_TO_RESOURCE_ID(cur->handle) == - VMCI_HANDLE_TO_RESOURCE_ID(handle)) { - if ((VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) == - VMCI_HANDLE_TO_CONTEXT_ID(handle)) || - (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(cur->handle))) { - cur->refCount++; - break; - } - } - cur = cur->next; - } - - return cur; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_GetEntry -- - * XXX Factor out the hashtable code to shared amongst API and perhaps - * host and guest. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCIHashEntry * -VMCIHashTable_GetEntry(VMCIHashTable *table, // IN - VMCIHandle handle) // IN -{ - VMCIHashEntry *entry; - VMCILockFlags flags; - - if (VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) { - return NULL; - } - - ASSERT(table); - - VMCI_GrabLock_BH(&table->lock, &flags); - entry = VMCIHashTableGetEntryLocked(table, handle); - VMCI_ReleaseLock_BH(&table->lock, flags); - - return entry; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_HoldEntry -- - * - * Hold the given entry. This will increment the entry's reference count. - * This is like a GetEntry() but without having to lookup the entry by - * handle. - * - * Result: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIHashTable_HoldEntry(VMCIHashTable *table, // IN - VMCIHashEntry *entry) // IN/OUT -{ - VMCILockFlags flags; - - ASSERT(table); - ASSERT(entry); - - VMCI_GrabLock_BH(&table->lock, &flags); - entry->refCount++; - VMCI_ReleaseLock_BH(&table->lock, flags); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTableReleaseEntryLocked -- - * - * Releases an element previously obtained with - * VMCIHashTableGetEntryLocked. - * - * Result: - * If the entry is removed from the hash table, VMCI_SUCCESS_ENTRY_DEAD - * is returned. Otherwise, VMCI_SUCCESS is returned. - * - * Side effects: - * The reference count of the entry is decreased and the entry is removed - * from the hash table on 0. - * - *------------------------------------------------------------------------------ - */ - -static int -VMCIHashTableReleaseEntryLocked(VMCIHashTable *table, // IN - VMCIHashEntry *entry) // IN -{ - int result = VMCI_SUCCESS; - - ASSERT(table); - ASSERT(entry); - - entry->refCount--; - /* Check if this is last reference and report if so. */ - if (entry->refCount == 0) { - - /* - * Remove entry from hash table if not already removed. This could have - * happened already because VMCIHashTable_RemoveEntry was called to unlink - * it. We ignore if it is not found. Datagram handles will often have - * RemoveEntry called, whereas SharedMemory regions rely on ReleaseEntry - * to unlink the entry, since the creator does not call RemoveEntry when - * it detaches. - */ - - HashTableUnlinkEntry(table, entry); - result = VMCI_SUCCESS_ENTRY_DEAD; - } - - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_ReleaseEntry -- - * XXX Factor out the hashtable code to shared amongst API and perhaps - * host and guest. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIHashTable_ReleaseEntry(VMCIHashTable *table, // IN - VMCIHashEntry *entry) // IN -{ - VMCILockFlags flags; - int result; - - ASSERT(table); - VMCI_GrabLock_BH(&table->lock, &flags); - result = VMCIHashTableReleaseEntryLocked(table, entry); - VMCI_ReleaseLock_BH(&table->lock, flags); - - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTable_EntryExists -- - * XXX Factor out the hashtable code to shared amongst API and perhaps - * host and guest. - * - * Result: - * TRUE if handle already in hashtable. FALSE otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -Bool -VMCIHashTable_EntryExists(VMCIHashTable *table, // IN - VMCIHandle handle) // IN -{ - Bool exists; - VMCILockFlags flags; - - ASSERT(table); - - VMCI_GrabLock_BH(&table->lock, &flags); - exists = VMCIHashTableEntryExistsLocked(table, handle); - VMCI_ReleaseLock_BH(&table->lock, flags); - - return exists; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIHashTableEntryExistsLocked -- - * - * Unlocked version of VMCIHashTable_EntryExists. - * - * Result: - * TRUE if handle already in hashtable. FALSE otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static Bool -VMCIHashTableEntryExistsLocked(VMCIHashTable *table, // IN - VMCIHandle handle) // IN - -{ - VMCIHashEntry *entry; - int idx; - - ASSERT(table); - - idx = VMCI_HASHTABLE_HASH(handle, table->size); - - entry = table->entries[idx]; - while (entry) { - if (VMCI_HANDLE_TO_RESOURCE_ID(entry->handle) == - VMCI_HANDLE_TO_RESOURCE_ID(handle)) { - if ((VMCI_HANDLE_TO_CONTEXT_ID(entry->handle) == - VMCI_HANDLE_TO_CONTEXT_ID(handle)) || - (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(handle)) || - (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(entry->handle))) { - return TRUE; - } - } - entry = entry->next; - } - - return FALSE; -} - - -/* - *------------------------------------------------------------------------------ - * - * HashTableUnlinkEntry -- - * XXX Factor out the hashtable code to shared amongst API and perhaps - * host and guest. - * Assumes caller holds table lock. - * - * Result: - * None. - * - *------------------------------------------------------------------------------ - */ - -static int -HashTableUnlinkEntry(VMCIHashTable *table, // IN - VMCIHashEntry *entry) // IN -{ - int result; - VMCIHashEntry *prev, *cur; - int idx; - - idx = VMCI_HASHTABLE_HASH(entry->handle, table->size); - - prev = NULL; - cur = table->entries[idx]; - while (TRUE) { - if (cur == NULL) { - result = VMCI_ERROR_NOT_FOUND; - break; - } - if (VMCI_HANDLE_EQUAL(cur->handle, entry->handle)) { - ASSERT(cur == entry); - - /* Remove entry and break. */ - if (prev) { - prev->next = cur->next; - } else { - table->entries[idx] = cur->next; - } - cur->next = NULL; - result = VMCI_SUCCESS; - break; - } - prev = cur; - cur = cur->next; - } - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHashTable_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIHashTable_Sync(VMCIHashTable *table) -{ - VMCILockFlags flags; - ASSERT(table); - VMCI_GrabLock_BH(&table->lock, &flags); - VMCI_ReleaseLock_BH(&table->lock, flags); -} diff --git a/open-vm-tools/modules/linux/vmci/common/vmciHashtable.h b/open-vm-tools/modules/linux/vmci/common/vmciHashtable.h deleted file mode 100644 index ea7d10653..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciHashtable.h +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2013 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 - * - *********************************************************/ - -/* - * vmciHashtable.h -- - * - * Hash table for use in the APIs. - */ - -#ifndef _VMCI_HASHTABLE_H_ -#define _VMCI_HASHTABLE_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_kernel_if.h" -#include "vmci_defs.h" - -typedef struct VMCIHashEntry { - VMCIHandle handle; - int refCount; - struct VMCIHashEntry *next; -} VMCIHashEntry; - -typedef struct VMCIHashTable { - VMCIHashEntry **entries; - int size; // Number of buckets in above array. - VMCILock lock; -} VMCIHashTable; - -VMCIHashTable *VMCIHashTable_Create(int size); -void VMCIHashTable_Destroy(VMCIHashTable *table); -void VMCIHashTable_InitEntry(VMCIHashEntry *entry, VMCIHandle handle); -int VMCIHashTable_AddEntry(VMCIHashTable *table, VMCIHashEntry *entry); -int VMCIHashTable_RemoveEntry(VMCIHashTable *table, VMCIHashEntry *entry); -VMCIHashEntry *VMCIHashTable_GetEntry(VMCIHashTable *table, VMCIHandle handle); -void VMCIHashTable_HoldEntry(VMCIHashTable *table, VMCIHashEntry *entry); -int VMCIHashTable_ReleaseEntry(VMCIHashTable *table, VMCIHashEntry *entry); -Bool VMCIHashTable_EntryExists(VMCIHashTable *table, VMCIHandle handle); -void VMCIHashTable_Sync(VMCIHashTable *table); - -#endif // _VMCI_HASHTABLE_H_ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciQPair.c b/open-vm-tools/modules/linux/vmci/common/vmciQPair.c deleted file mode 100644 index 3c891fead..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciQPair.c +++ /dev/null @@ -1,1448 +0,0 @@ -/********************************************************* - * Copyright (C) 2010-2016 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 - * - *********************************************************/ - -/* - * vmciQPair.c -- - * - * This file implements Queue accessor methods. - * - * VMCIQPair is a new interface that hides the queue pair internals. - * Rather than access each queue in a pair directly, operations are now - * performed on the queue as a whole. This is simpler and less - * error-prone, and allows for future queue pair features to be added - * under the hood with no change to the client code. - * - * This also helps in a particular case on Windows hosts, where the memory - * allocated by the client (e.g., VMX) will disappear when the client does - * (e.g., abnormal termination). The kernel can't lock user memory into - * its address space indefinitely. By guarding access to the queue - * contents we can correctly handle the case where the client disappears. - * - * On code style: - * - * + This entire file started its life as a cut-and-paste of the - * static INLINE functions in bora/public/vmci_queue_pair.h. - * From there, new copies of the routines were made named - * without the prefix VMCI, without the underscore (the one - * that followed VMCIQueue_). The no-underscore versions of - * the routines require that the mutexes are held. - * - * + The code -always- uses the xyzLocked() version of any given - * routine even when the wrapped function is a one-liner. The - * reason for this decision was to ensure that we didn't have - * copies of logic lying around that needed to be maintained. - * - * + Note that we still pass around 'const VMCIQueue *'s. - * - * + Note that mutex is a field within VMCIQueue. We skirt the - * issue of passing around a const VMCIQueue, even though the - * mutex field (__mutex, specifically) will get modified by not - * ever referring to the mutex -itself- except during - * initialization. Beyond that, the code only passes the - * pointer to the mutex, which is also a member of VMCIQueue, - * obviously, and which doesn't change after initialization. - * This eliminates having to redefine all the functions that - * are currently taking const VMCIQueue's so that these - * functions are compatible with those definitions. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_handle_array.h" -#include "vmci_defs.h" -#include "vmciKernelAPI.h" -#include "vmciQueue.h" -#include "vmciQueuePair.h" -#include "vmciRoute.h" - - -/* - * VMCIQPair - * - * This structure is opaque to the clients. - */ - -struct VMCIQPair { - VMCIHandle handle; - VMCIQueue *produceQ; - VMCIQueue *consumeQ; - uint64 produceQSize; - uint64 consumeQSize; - VMCIId peer; - uint32 flags; - VMCIPrivilegeFlags privFlags; - Bool guestEndpoint; - uint32 blocked; - VMCIEvent event; -}; - -static int VMCIQPairMapQueueHeaders(VMCIQueue *produceQ, VMCIQueue *consumeQ, - Bool canBlock); -static int VMCIQPairGetQueueHeaders(const VMCIQPair *qpair, - VMCIQueueHeader **produceQHeader, - VMCIQueueHeader **consumeQHeader); -static int VMCIQPairWakeupCB(void *clientData); -static int VMCIQPairReleaseMutexCB(void *clientData); -static Bool VMCIQPairWaitForReadyQueue(VMCIQPair *qpair); - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairLock -- - * - * Helper routine that will lock the QPair before subsequent operations. - * - * Results: - * VMCI_SUCCESS if lock acquired. VMCI_ERROR_WOULD_BLOCK if queue mutex - * couldn't be acquired and qpair isn't allowed to block. - * - * Side effects: - * May block. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VMCIQPairLock(const VMCIQPair *qpair) // IN -{ -#if !defined VMX86_VMX - return VMCI_AcquireQueueMutex(qpair->produceQ, - !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); -#else - return VMCI_SUCCESS -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairUnlock -- - * - * Helper routine that will unlock the QPair after various operations. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQPairUnlock(const VMCIQPair *qpair) // IN -{ -#if !defined VMX86_VMX - VMCI_ReleaseQueueMutex(qpair->produceQ); -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairHeaderLock -- - * - * Helper routine that will lock the queue pair header before subsequent - * operations. If the queue pair is non blocking, a spinlock will be used. - * Otherwise, a regular mutex locking the complete queue pair will be used. - * - * Results: - * None. - * - * Side effects: - * May block. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQPairLockHeader(const VMCIQPair *qpair) // IN -{ -#if !defined VMX86_VMX - if (qpair->flags & VMCI_QPFLAG_NONBLOCK) { - VMCI_LockQueueHeader(qpair->produceQ); - } else { - (void)VMCI_AcquireQueueMutex(qpair->produceQ, - !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - } -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairUnlockHeader -- - * - * Helper routine that unlocks the queue pair header after calling - * VMCIQPairHeaderLock. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VMCIQPairUnlockHeader(const VMCIQPair *qpair) // IN -{ -#if !defined VMX86_VMX - if (qpair->flags & VMCI_QPFLAG_NONBLOCK) { - VMCI_UnlockQueueHeader(qpair->produceQ); - } else { - VMCI_ReleaseQueueMutex(qpair->produceQ); - } -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueAddProducerTail() -- - * - * Helper routine to increment the Producer Tail. - * - * Results: - * VMCI_ERROR_NOT_FOUND if the vmmWorld registered with the queue - * cannot be found. Otherwise VMCI_SUCCESS. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VMCIQueueAddProducerTail(VMCIQueue *queue, // IN/OUT - size_t add, // IN - uint64 queueSize) // IN -{ - VMCIQueueHeader_AddProducerTail(queue->qHeader, add, queueSize); - return VMCI_QueueHeaderUpdated(queue); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueueAddConsumerHead() -- - * - * Helper routine to increment the Consumer Head. - * - * Results: - * VMCI_ERROR_NOT_FOUND if the vmmWorld registered with the queue - * cannot be found. Otherwise VMCI_SUCCESS. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VMCIQueueAddConsumerHead(VMCIQueue *queue, // IN/OUT - size_t add, // IN - uint64 queueSize) // IN -{ - VMCIQueueHeader_AddConsumerHead(queue->qHeader, add, queueSize); - return VMCI_QueueHeaderUpdated(queue); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairGetQueueHeaders -- - * - * Helper routine that will retrieve the produce and consume - * headers of a given queue pair. If the guest memory of the - * queue pair is currently not available, the saved queue headers - * will be returned, if these are available. - * - * Results: - * VMCI_SUCCESS if either current or saved queue headers are found. - * Appropriate error code otherwise. - * - * Side effects: - * May block. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPairGetQueueHeaders(const VMCIQPair *qpair, // IN - VMCIQueueHeader **produceQHeader, // OUT - VMCIQueueHeader **consumeQHeader) // OUT -{ - int result; - - result = VMCIQPairMapQueueHeaders(qpair->produceQ, qpair->consumeQ, - !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_SUCCESS) { - *produceQHeader = qpair->produceQ->qHeader; - *consumeQHeader = qpair->consumeQ->qHeader; - } else if (qpair->produceQ->savedHeader && qpair->consumeQ->savedHeader) { - ASSERT(!qpair->guestEndpoint); - *produceQHeader = qpair->produceQ->savedHeader; - *consumeQHeader = qpair->consumeQ->savedHeader; - result = VMCI_SUCCESS; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairMapQueueHeaders -- - * - * The queue headers may not be mapped at all times. If a queue is - * currently not mapped, it will be attempted to do so. - * - * Results: - * VMCI_SUCCESS if queues were validated, appropriate error code otherwise. - * - * Side effects: - * May attempt to map in guest memory. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPairMapQueueHeaders(VMCIQueue *produceQ, // IN - VMCIQueue *consumeQ, // IN - Bool canBlock) // IN -{ - int result; - - if (NULL == produceQ->qHeader || NULL == consumeQ->qHeader) { - if (canBlock) { - result = VMCIHost_MapQueues(produceQ, consumeQ, 0); - } else { - result = VMCI_ERROR_QUEUEPAIR_NOT_READY; - } - if (result < VMCI_SUCCESS) { - if (produceQ->savedHeader && consumeQ->savedHeader) { - return VMCI_ERROR_QUEUEPAIR_NOT_READY; - } else { - return VMCI_ERROR_QUEUEPAIR_NOTATTACHED; - } - } - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairWakeupCB -- - * - * Callback from VMCI queue pair broker indicating that a queue - * pair that was previously not ready, now either is ready or - * gone forever. - * - * Results: - * VMCI_SUCCESS always. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPairWakeupCB(void *clientData) -{ - VMCIQPair *qpair = (VMCIQPair *)clientData; - ASSERT(qpair); - - VMCIQPairLock(qpair); - while (qpair->blocked > 0) { - qpair->blocked--; - VMCI_SignalEvent(&qpair->event); - } - VMCIQPairUnlock(qpair); - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairReleaseMutexCB -- - * - * Callback from VMCI_WaitOnEvent releasing the queue pair mutex - * protecting the queue pair header state. - * - * Results: - * 0 always. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPairReleaseMutexCB(void *clientData) -{ - VMCIQPair *qpair = (VMCIQPair *)clientData; - ASSERT(qpair); - VMCIQPairUnlock(qpair); - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPairWaitForReadyQueue -- - * - * Makes the calling thread wait for the queue pair to become - * ready for host side access. - * - * Results: - * TRUE when thread is woken up after queue pair state change. - * FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static Bool -VMCIQPairWaitForReadyQueue(VMCIQPair *qpair) -{ - if (UNLIKELY(qpair->guestEndpoint)) { - ASSERT(FALSE); - return FALSE; - } - if (qpair->flags & VMCI_QPFLAG_NONBLOCK) { - return FALSE; - } - qpair->blocked++; - VMCI_WaitOnEvent(&qpair->event, VMCIQPairReleaseMutexCB, qpair); - VMCIQPairLock(qpair); - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_alloc -- - * - * This is the client interface for allocating the memory for a - * VMCIQPair structure and then attaching to the underlying - * queue. If an error occurs allocating the memory for the - * VMCIQPair structure, no attempt is made to attach. If an - * error occurs attaching, then there's the VMCIQPair structure - * is freed. - * - * Results: - * An err, if < 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_alloc) -int -vmci_qpair_alloc(VMCIQPair **qpair, // OUT - VMCIHandle *handle, // OUT - uint64 produceQSize, // IN - uint64 consumeQSize, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags) // IN -{ - VMCIQPair *myQPair; - int retval; - VMCIHandle src = VMCI_INVALID_HANDLE; - VMCIHandle dst = VMCI_MAKE_HANDLE(peer, VMCI_INVALID_ID); - VMCIRoute route; - VMCIEventReleaseCB wakeupCB; - void *clientData; - - /* - * Restrict the size of a queuepair. The device already enforces a limit - * on the total amount of memory that can be allocated to queuepairs for a - * guest. However, we try to allocate this memory before we make the - * queuepair allocation hypercall. On Windows and Mac OS, we request a - * single, continguous block, and it will fail if the OS cannot satisfy the - * request. On Linux, we allocate each page separately, which means rather - * than fail, the guest will thrash while it tries to allocate, and will - * become increasingly unresponsive to the point where it appears to be hung. - * So we place a limit on the size of an individual queuepair here, and - * leave the device to enforce the restriction on total queuepair memory. - * (Note that this doesn't prevent all cases; a user with only this much - * physical memory could still get into trouble.) The error used by the - * device is NO_RESOURCES, so use that here too. - */ - - if (produceQSize + consumeQSize < MAX(produceQSize, consumeQSize) || - produceQSize + consumeQSize > VMCI_MAX_GUEST_QP_MEMORY) { - return VMCI_ERROR_NO_RESOURCES; - } - - retval = VMCI_Route(&src, &dst, FALSE, &route); - if (retval < VMCI_SUCCESS) { - if (VMCI_GuestPersonalityActive()) { - route = VMCI_ROUTE_AS_GUEST; - } else { - route = VMCI_ROUTE_AS_HOST; - } - } - - if (flags & VMCI_QPFLAG_NONBLOCK && !vmkernel) { - return VMCI_ERROR_INVALID_ARGS; - } - - myQPair = VMCI_AllocKernelMem(sizeof *myQPair, VMCI_MEMORY_NONPAGED); - if (!myQPair) { - return VMCI_ERROR_NO_MEM; - } - - myQPair->produceQSize = produceQSize; - myQPair->consumeQSize = consumeQSize; - myQPair->peer = peer; - myQPair->flags = flags; - myQPair->privFlags = privFlags; - - clientData = NULL; - wakeupCB = NULL; - if (VMCI_ROUTE_AS_HOST == route) { - myQPair->guestEndpoint = FALSE; - if (!(flags & VMCI_QPFLAG_LOCAL)) { - myQPair->blocked = 0; - VMCI_CreateEvent(&myQPair->event); - wakeupCB = VMCIQPairWakeupCB; - clientData = (void *)myQPair; - } - } else { - myQPair->guestEndpoint = TRUE; - } - - retval = VMCIQueuePair_Alloc(handle, - &myQPair->produceQ, - myQPair->produceQSize, - &myQPair->consumeQ, - myQPair->consumeQSize, - myQPair->peer, - myQPair->flags, - myQPair->privFlags, - myQPair->guestEndpoint, - wakeupCB, - clientData); - - if (retval < VMCI_SUCCESS) { - if (VMCI_ROUTE_AS_HOST == route && !(flags & VMCI_QPFLAG_LOCAL)) { - VMCI_DestroyEvent(&myQPair->event); - } - VMCI_FreeKernelMem(myQPair, sizeof *myQPair); - return retval; - } - - *qpair = myQPair; - myQPair->handle = *handle; - - return retval; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_detach -- - * - * This is the client interface for detaching from a VMCIQPair. - * Note that this routine will free the memory allocated for the - * VMCIQPair structure, too. - * - * Results: - * An error, if < 0. - * - * Side effects: - * Will clear the caller's pointer to the VMCIQPair structure. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_detach) -int -vmci_qpair_detach(VMCIQPair **qpair) // IN/OUT -{ - int result; - VMCIQPair *oldQPair; - - if (!qpair || !(*qpair)) { - return VMCI_ERROR_INVALID_ARGS; - } - - oldQPair = *qpair; - result = VMCIQueuePair_Detach(oldQPair->handle, oldQPair->guestEndpoint); - - /* - * The guest can fail to detach for a number of reasons, and if it does so, - * it will cleanup the entry (if there is one). The host can fail too, but - * it won't cleanup the entry immediately, it will do that later when the - * context is freed. Either way, we need to release the qpair struct here; - * there isn't much the caller can do, and we don't want to leak. - */ - - if (!(oldQPair->guestEndpoint || (oldQPair->flags & VMCI_QPFLAG_LOCAL))) { - VMCI_DestroyEvent(&oldQPair->event); - } - VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair); - *qpair = NULL; - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_get_produce_indexes -- - * - * This is the client interface for getting the current indexes of the - * QPair from the point of the view of the caller as the producer. - * - * Results: - * err, if < 0 - * Success otherwise. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_get_produce_indexes) -int -vmci_qpair_get_produce_indexes(const VMCIQPair *qpair, // IN - uint64 *producerTail, // OUT - uint64 *consumerHead) // OUT -{ - VMCIQueueHeader *produceQHeader; - VMCIQueueHeader *consumeQHeader; - int result; - - if (!qpair) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPairLockHeader(qpair); - result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader); - if (result == VMCI_SUCCESS) { - VMCIQueueHeader_GetPointers(produceQHeader, consumeQHeader, - producerTail, consumerHead); - } - VMCIQPairUnlockHeader(qpair); - - if (result == VMCI_SUCCESS && - ((producerTail && *producerTail >= qpair->produceQSize) || - (consumerHead && *consumerHead >= qpair->produceQSize))) { - return VMCI_ERROR_INVALID_SIZE; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_get_consume_indexes -- - * - * This is the client interface for getting the current indexes of the - * QPair from the point of the view of the caller as the consumer. - * - * Results: - * err, if < 0 - * Success otherwise. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_get_consume_indexes) -int -vmci_qpair_get_consume_indexes(const VMCIQPair *qpair, // IN - uint64 *consumerTail, // OUT - uint64 *producerHead) // OUT -{ - VMCIQueueHeader *produceQHeader; - VMCIQueueHeader *consumeQHeader; - int result; - - if (!qpair) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPairLockHeader(qpair); - result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader); - if (result == VMCI_SUCCESS) { - VMCIQueueHeader_GetPointers(consumeQHeader, produceQHeader, - consumerTail, producerHead); - } - VMCIQPairUnlockHeader(qpair); - - if (result == VMCI_SUCCESS && - ((consumerTail && *consumerTail >= qpair->consumeQSize) || - (producerHead && *producerHead >= qpair->consumeQSize))) { - return VMCI_ERROR_INVALID_SIZE; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_produce_free_space -- - * - * This is the client interface for getting the amount of free - * space in the QPair from the point of the view of the caller as - * the producer which is the common case. - * - * Results: - * Err, if < 0. - * Full queue if = 0. - * Number of available bytes into which data can be enqueued if > 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_produce_free_space) -int64 -vmci_qpair_produce_free_space(const VMCIQPair *qpair) // IN -{ - VMCIQueueHeader *produceQHeader; - VMCIQueueHeader *consumeQHeader; - int64 result; - - if (!qpair) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPairLockHeader(qpair); - result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader); - if (result == VMCI_SUCCESS) { - result = VMCIQueueHeader_FreeSpace(produceQHeader, consumeQHeader, - qpair->produceQSize); - } else { - result = 0; - } - VMCIQPairUnlockHeader(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_consume_free_space -- - * - * This is the client interface for getting the amount of free - * space in the QPair from the point of the view of the caller as - * the consumer which is not the common case (see - * VMCIQPair_ProduceFreeSpace(), above). - * - * Results: - * Err, if < 0. - * Full queue if = 0. - * Number of available bytes into which data can be enqueued if > 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_consume_free_space) -int64 -vmci_qpair_consume_free_space(const VMCIQPair *qpair) // IN -{ - VMCIQueueHeader *produceQHeader; - VMCIQueueHeader *consumeQHeader; - int64 result; - - if (!qpair) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPairLockHeader(qpair); - result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader); - if (result == VMCI_SUCCESS) { - result = VMCIQueueHeader_FreeSpace(consumeQHeader, produceQHeader, - qpair->consumeQSize); - } else { - result = 0; - } - VMCIQPairUnlockHeader(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_produce_buf_ready -- - * - * This is the client interface for getting the amount of - * enqueued data in the QPair from the point of the view of the - * caller as the producer which is not the common case (see - * VMCIQPair_ConsumeBufReady(), above). - * - * Results: - * Err, if < 0. - * Empty queue if = 0. - * Number of bytes ready to be dequeued if > 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_produce_buf_ready) -int64 -vmci_qpair_produce_buf_ready(const VMCIQPair *qpair) // IN -{ - VMCIQueueHeader *produceQHeader; - VMCIQueueHeader *consumeQHeader; - int64 result; - - if (!qpair) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPairLockHeader(qpair); - result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader); - if (result == VMCI_SUCCESS) { - result = VMCIQueueHeader_BufReady(produceQHeader, consumeQHeader, - qpair->produceQSize); - } else { - result = 0; - } - VMCIQPairUnlockHeader(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_consume_buf_ready -- - * - * This is the client interface for getting the amount of - * enqueued data in the QPair from the point of the view of the - * caller as the consumer which is the normal case. - * - * Results: - * Err, if < 0. - * Empty queue if = 0. - * Number of bytes ready to be dequeued if > 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_consume_buf_ready) -int64 -vmci_qpair_consume_buf_ready(const VMCIQPair *qpair) // IN -{ - VMCIQueueHeader *produceQHeader; - VMCIQueueHeader *consumeQHeader; - int64 result; - - if (!qpair) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPairLockHeader(qpair); - result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader); - if (result == VMCI_SUCCESS) { - result = VMCIQueueHeader_BufReady(consumeQHeader, produceQHeader, - qpair->consumeQSize); - } else { - result = 0; - } - VMCIQPairUnlockHeader(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * EnqueueLocked -- - * - * Enqueues a given buffer to the produce queue using the provided - * function. As many bytes as possible (space available in the queue) - * are enqueued. - * - * Assumes the queue->mutex has been acquired. - * - * Results: - * VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue data. - * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue - * (as defined by the queue size). - * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer. - * VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't - * available. - * VMCI_ERROR_NOT_FOUND, if the vmmWorld registered with the queue pair - * cannot be found. - * Otherwise, the number of bytes written to the queue is returned. - * - * Side effects: - * Updates the tail pointer of the produce queue. - * - *----------------------------------------------------------------------------- - */ - -static ssize_t -EnqueueLocked(VMCIQueue *produceQ, // IN - VMCIQueue *consumeQ, // IN - const uint64 produceQSize, // IN - const void *buf, // IN - size_t bufSize, // IN - int bufType, // IN - VMCIMemcpyToQueueFunc memcpyToQueue, // IN - Bool canBlock) // IN -{ - int64 freeSpace; - uint64 tail; - size_t written; - ssize_t result; - -#if !defined VMX86_VMX - if (UNLIKELY(VMCI_EnqueueToDevNull(produceQ))) { - return (ssize_t) bufSize; - } - - result = VMCIQPairMapQueueHeaders(produceQ, consumeQ, canBlock); - if (UNLIKELY(result != VMCI_SUCCESS)) { - return result; - } -#endif - - freeSpace = VMCIQueueHeader_FreeSpace(produceQ->qHeader, - consumeQ->qHeader, - produceQSize); - if (freeSpace == 0) { - return VMCI_ERROR_QUEUEPAIR_NOSPACE; - } - - if (freeSpace < VMCI_SUCCESS) { - return (ssize_t)freeSpace; - } - - written = (size_t)(freeSpace > bufSize ? bufSize : freeSpace); - tail = VMCIQueueHeader_ProducerTail(produceQ->qHeader); - if (LIKELY(tail + written < produceQSize)) { - result = memcpyToQueue(produceQ, tail, buf, 0, written, bufType, - canBlock); - } else { - /* Tail pointer wraps around. */ - - const size_t tmp = (size_t)(produceQSize - tail); - - result = memcpyToQueue(produceQ, tail, buf, 0, tmp, bufType, canBlock); - if (result >= VMCI_SUCCESS) { - result = memcpyToQueue(produceQ, 0, buf, tmp, written - tmp, bufType, - canBlock); - } - } - - if (result < VMCI_SUCCESS) { - return result; - } - - result = VMCIQueueAddProducerTail(produceQ, written, produceQSize); - if (result < VMCI_SUCCESS) { - return result; - } - return written; -} - - -/* - *----------------------------------------------------------------------------- - * - * DequeueLocked -- - * - * Dequeues data (if available) from the given consume queue. Writes data - * to the user provided buffer using the provided function. - * - * Assumes the queue->mutex has been acquired. - * - * Results: - * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue. - * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue - * (as defined by the queue size). - * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer. - * VMCI_ERROR_NOT_FOUND, if the vmmWorld registered with the queue pair - * cannot be found. - * Otherwise the number of bytes dequeued is returned. - * - * Side effects: - * Updates the head pointer of the consume queue. - * - *----------------------------------------------------------------------------- - */ - -static ssize_t -DequeueLocked(VMCIQueue *produceQ, // IN - VMCIQueue *consumeQ, // IN - const uint64 consumeQSize, // IN - void *buf, // IN - size_t bufSize, // IN - int bufType, // IN - VMCIMemcpyFromQueueFunc memcpyFromQueue, // IN - Bool updateConsumer, // IN - Bool canBlock) // IN -{ - int64 bufReady; - uint64 head; - size_t read; - ssize_t result; - -#if !defined VMX86_VMX - result = VMCIQPairMapQueueHeaders(produceQ, consumeQ, canBlock); - if (UNLIKELY(result != VMCI_SUCCESS)) { - return result; - } -#endif - - bufReady = VMCIQueueHeader_BufReady(consumeQ->qHeader, - produceQ->qHeader, - consumeQSize); - if (bufReady == 0) { - return VMCI_ERROR_QUEUEPAIR_NODATA; - } - if (bufReady < VMCI_SUCCESS) { - return (ssize_t)bufReady; - } - - read = (size_t)(bufReady > bufSize ? bufSize : bufReady); - head = VMCIQueueHeader_ConsumerHead(produceQ->qHeader); - if (LIKELY(head + read < consumeQSize)) { - result = memcpyFromQueue(buf, 0, consumeQ, head, read, bufType, canBlock); - } else { - /* Head pointer wraps around. */ - - const size_t tmp = (size_t)(consumeQSize - head); - - result = memcpyFromQueue(buf, 0, consumeQ, head, tmp, bufType, canBlock); - if (result >= VMCI_SUCCESS) { - result = memcpyFromQueue(buf, tmp, consumeQ, 0, read - tmp, bufType, - canBlock); - } - } - - if (result < VMCI_SUCCESS) { - return result; - } - - if (updateConsumer) { - result = VMCIQueueAddConsumerHead(produceQ, read, consumeQSize); - if (result < VMCI_SUCCESS) { - return result; - } - } - - return read; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_enqueue -- - * - * This is the client interface for enqueueing data into the queue. - * - * Results: - * Err, if < 0. - * Number of bytes enqueued if >= 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_enqueue) -ssize_t -vmci_qpair_enqueue(VMCIQPair *qpair, // IN - const void *buf, // IN - size_t bufSize, // IN - int bufType) // IN -{ - ssize_t result; - - if (!qpair || !buf) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIQPairLock(qpair); - if (result != VMCI_SUCCESS) { - return result; - } - - do { - result = EnqueueLocked(qpair->produceQ, - qpair->consumeQ, - qpair->produceQSize, - buf, bufSize, bufType, - qpair->flags & VMCI_QPFLAG_LOCAL? - VMCIMemcpyToQueueLocal: - VMCIMemcpyToQueue, - !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) { - if (!VMCIQPairWaitForReadyQueue(qpair)) { - result = VMCI_ERROR_WOULD_BLOCK; - } - } - } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY); - - VMCIQPairUnlock(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_dequeue -- - * - * This is the client interface for dequeueing data from the queue. - * - * Results: - * Err, if < 0. - * Number of bytes dequeued if >= 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_dequeue) -ssize_t -vmci_qpair_dequeue(VMCIQPair *qpair, // IN - void *buf, // IN - size_t bufSize, // IN - int bufType) // IN -{ - ssize_t result; - - if (!qpair || !buf) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIQPairLock(qpair); - if (result != VMCI_SUCCESS) { - return result; - } - - do { - result = DequeueLocked(qpair->produceQ, - qpair->consumeQ, - qpair->consumeQSize, - buf, bufSize, bufType, - qpair->flags & VMCI_QPFLAG_LOCAL? - VMCIMemcpyFromQueueLocal: - VMCIMemcpyFromQueue, - TRUE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) { - if (!VMCIQPairWaitForReadyQueue(qpair)) { - result = VMCI_ERROR_WOULD_BLOCK; - } - } - } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY); - - VMCIQPairUnlock(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_peek -- - * - * This is the client interface for peeking into a queue. (I.e., - * copy data from the queue without updating the head pointer.) - * - * Results: - * Err, if < 0. - * Number of bytes peeked, if >= 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_peek) -ssize_t -vmci_qpair_peek(VMCIQPair *qpair, // IN - void *buf, // IN - size_t bufSize, // IN - int bufType) // IN -{ - ssize_t result; - - if (!qpair || !buf) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIQPairLock(qpair); - if (result != VMCI_SUCCESS) { - return result; - } - - do { - result = DequeueLocked(qpair->produceQ, - qpair->consumeQ, - qpair->consumeQSize, - buf, bufSize, bufType, - qpair->flags & VMCI_QPFLAG_LOCAL? - VMCIMemcpyFromQueueLocal: - VMCIMemcpyFromQueue, - FALSE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) { - if (!VMCIQPairWaitForReadyQueue(qpair)) { - result = VMCI_ERROR_WOULD_BLOCK; - } - } - } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY); - - VMCIQPairUnlock(qpair); - - return result; -} - - -#if (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ - (defined(__linux__) && defined(__KERNEL__)) || \ - (defined(_WIN32) && defined(WINNT_DDK)) - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_enquev -- - * - * This is the client interface for enqueueing data into the queue. - * - * Results: - * Err, if < 0. - * Number of bytes enqueued if >= 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_enquev) -ssize_t -vmci_qpair_enquev(VMCIQPair *qpair, // IN - void *iov, // IN - size_t iovSize, // IN - int bufType) // IN -{ - ssize_t result; - - if (!qpair || !iov) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIQPairLock(qpair); - if (result != VMCI_SUCCESS) { - return result; - } - - do { - result = EnqueueLocked(qpair->produceQ, - qpair->consumeQ, - qpair->produceQSize, - iov, iovSize, bufType, - qpair->flags & VMCI_QPFLAG_LOCAL? - VMCIMemcpyToQueueVLocal: - VMCIMemcpyToQueueV, - !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) { - if (!VMCIQPairWaitForReadyQueue(qpair)) { - result = VMCI_ERROR_WOULD_BLOCK; - } - } - } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY); - - VMCIQPairUnlock(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_dequev -- - * - * This is the client interface for dequeueing data from the queue. - * - * Results: - * Err, if < 0. - * Number of bytes dequeued if >= 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_dequev) -ssize_t -vmci_qpair_dequev(VMCIQPair *qpair, // IN - void *iov, // IN - size_t iovSize, // IN - int bufType) // IN -{ - ssize_t result; - - if (!qpair || !iov) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIQPairLock(qpair); - if (result != VMCI_SUCCESS) { - return result; - } - - do { - result = DequeueLocked(qpair->produceQ, - qpair->consumeQ, - qpair->consumeQSize, - iov, iovSize, bufType, - qpair->flags & VMCI_QPFLAG_LOCAL? - VMCIMemcpyFromQueueVLocal: - VMCIMemcpyFromQueueV, - TRUE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) { - if (!VMCIQPairWaitForReadyQueue(qpair)) { - result = VMCI_ERROR_WOULD_BLOCK; - } - } - } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY); - - VMCIQPairUnlock(qpair); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_qpair_peekv -- - * - * This is the client interface for peeking into a queue. (I.e., - * copy data from the queue without updating the head pointer.) - * - * Results: - * Err, if < 0. - * Number of bytes peeked, if >= 0. - * - * Side effects: - * Windows blocking call. - * - *----------------------------------------------------------------------------- - */ - -VMCI_EXPORT_SYMBOL(vmci_qpair_peekv) -ssize_t -vmci_qpair_peekv(VMCIQPair *qpair, // IN - void *iov, // IN - size_t iovSize, // IN - int bufType) // IN -{ - ssize_t result; - - if (!qpair || !iov) { - return VMCI_ERROR_INVALID_ARGS; - } - - result = VMCIQPairLock(qpair); - if (result != VMCI_SUCCESS) { - return result; - } - - do { - result = DequeueLocked(qpair->produceQ, - qpair->consumeQ, - qpair->consumeQSize, - iov, iovSize, bufType, - qpair->flags & VMCI_QPFLAG_LOCAL? - VMCIMemcpyFromQueueVLocal: - VMCIMemcpyFromQueueV, - FALSE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); - if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) { - if (!VMCIQPairWaitForReadyQueue(qpair)) { - result = VMCI_ERROR_WOULD_BLOCK; - } - } - } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY); - - VMCIQPairUnlock(qpair); - - return result; -} - -#endif /* Systems that support struct iovec */ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c b/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c deleted file mode 100644 index d2bf29774..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.c +++ /dev/null @@ -1,3062 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2016 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 - * - *********************************************************/ - -/* - * vmciQueuePair.c -- - * - * VMCI QueuePair API implementation in the host driver. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_handle_array.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciContext.h" -#include "vmciDatagram.h" -#include "vmciDriver.h" -#include "vmciEvent.h" -#include "vmciHashtable.h" -#include "vmciKernelAPI.h" -#include "vmciQueuePair.h" -#include "vmciResource.h" -#include "vmciRoute.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -#endif - -#define LGPFX "VMCIQueuePair: " - - -/* - * In the following, we will distinguish between two kinds of VMX processes - - * the ones with versions lower than VMCI_VERSION_NOVMVM that use specialized - * VMCI page files in the VMX and supporting VM to VM communication) and the - * newer ones that use the guest memory directly. We will in the following refer - * to the older VMX versions as old-style VMX'en, and the newer ones as new-style - * VMX'en. - * - * The state transition datagram is as follows (the VMCIQPB_ prefix has been - * removed for readability) - see below for more details on the transtions: - * - * -------------- NEW ------------- - * | | - * \_/ \_/ - * CREATED_NO_MEM <-----------------> CREATED_MEM - * | | | - * | o-----------------------o | - * | | | - * \_/ \_/ \_/ - * ATTACHED_NO_MEM <----------------> ATTACHED_MEM - * | | | - * | o----------------------o | - * | | | - * \_/ \_/ \_/ - * SHUTDOWN_NO_MEM <----------------> SHUTDOWN_MEM - * | | - * | | - * -------------> gone <------------- - * - * In more detail. When a VMCI queue pair is first created, it will be in the - * VMCIQPB_NEW state. It will then move into one of the following states: - * - VMCIQPB_CREATED_NO_MEM: this state indicates that either: - * - the created was performed by a host endpoint, in which case there is no - * backing memory yet. - * - the create was initiated by an old-style VMX, that uses - * VMCIQPBroker_SetPageStore to specify the UVAs of the queue pair at a - * later point in time. This state can be distinguished from the one above - * by the context ID of the creator. A host side is not allowed to attach - * until the page store has been set. - * - VMCIQPB_CREATED_MEM: this state is the result when the queue pair is created - * by a VMX using the queue pair device backend that sets the UVAs of the - * queue pair immediately and stores the information for later attachers. At - * this point, it is ready for the host side to attach to it. - * Once the queue pair is in one of the created states (with the exception of the - * case mentioned for older VMX'en above), it is possible to attach to the queue - * pair. Again we have two new states possible: - * - VMCIQPB_ATTACHED_MEM: this state can be reached through the following paths: - * - from VMCIQPB_CREATED_NO_MEM when a new-style VMX allocates a queue pair, - * and attaches to a queue pair previously created by the host side. - * - from VMCIQPB_CREATED_MEM when the host side attaches to a queue pair - * already created by a guest. - * - from VMCIQPB_ATTACHED_NO_MEM, when an old-style VMX calls - * VMCIQPBroker_SetPageStore (see below). - * - VMCIQPB_ATTACHED_NO_MEM: If the queue pair already was in the - * VMCIQPB_CREATED_NO_MEM due to a host side create, an old-style VMX will - * bring the queue pair into this state. Once VMCIQPBroker_SetPageStore is - * called to register the user memory, the VMCIQPB_ATTACH_MEM state will be - * entered. - * From the attached queue pair, the queue pair can enter the shutdown states - * when either side of the queue pair detaches. If the guest side detaches first, - * the queue pair will enter the VMCIQPB_SHUTDOWN_NO_MEM state, where the content - * of the queue pair will no longer be available. If the host side detaches first, - * the queue pair will either enter the VMCIQPB_SHUTDOWN_MEM, if the guest memory - * is currently mapped, or VMCIQPB_SHUTDOWN_NO_MEM, if the guest memory is not - * mapped (e.g., the host detaches while a guest is stunned). - * - * New-style VMX'en will also unmap guest memory, if the guest is quiesced, e.g., - * during a snapshot operation. In that case, the guest memory will no longer be - * available, and the queue pair will transition from *_MEM state to a *_NO_MEM - * state. The VMX may later map the memory once more, in which case the queue - * pair will transition from the *_NO_MEM state at that point back to the *_MEM - * state. Note that the *_NO_MEM state may have changed, since the peer may have - * either attached or detached in the meantime. The values are laid out such that - * ++ on a state will move from a *_NO_MEM to a *_MEM state, and vice versa. - */ - -typedef enum { - VMCIQPB_NEW, - VMCIQPB_CREATED_NO_MEM, - VMCIQPB_CREATED_MEM, - VMCIQPB_ATTACHED_NO_MEM, - VMCIQPB_ATTACHED_MEM, - VMCIQPB_SHUTDOWN_NO_MEM, - VMCIQPB_SHUTDOWN_MEM, - VMCIQPB_GONE -} QPBrokerState; - -#define QPBROKERSTATE_HAS_MEM(_qpb) (_qpb->state == VMCIQPB_CREATED_MEM || \ - _qpb->state == VMCIQPB_ATTACHED_MEM || \ - _qpb->state == VMCIQPB_SHUTDOWN_MEM) - -/* - * In the queue pair broker, we always use the guest point of view for - * the produce and consume queue values and references, e.g., the - * produce queue size stored is the guests produce queue size. The - * host endpoint will need to swap these around. The only exception is - * the local queue pairs on the host, in which case the host endpoint - * that creates the queue pair will have the right orientation, and - * the attaching host endpoint will need to swap. - */ - -typedef struct QueuePairEntry { - VMCIListItem listItem; - VMCIHandle handle; - VMCIId peer; - uint32 flags; - uint64 produceSize; - uint64 consumeSize; - uint32 refCount; -} QueuePairEntry; - -typedef struct QPBrokerEntry { - QueuePairEntry qp; - VMCIId createId; - VMCIId attachId; - QPBrokerState state; - Bool requireTrustedAttach; - Bool createdByTrusted; - Bool vmciPageFiles; // Created by VMX using VMCI page files - VMCIQueue *produceQ; - VMCIQueue *consumeQ; - VMCIQueueHeader savedProduceQ; - VMCIQueueHeader savedConsumeQ; - VMCIEventReleaseCB wakeupCB; - void *clientData; - void *localMem; // Kernel memory for local queue pair -} QPBrokerEntry; - -#if !defined(VMKERNEL) -typedef struct QPGuestEndpoint { - QueuePairEntry qp; - uint64 numPPNs; - void *produceQ; - void *consumeQ; - Bool hibernateFailure; - PPNSet ppnSet; -} QPGuestEndpoint; -#endif - -typedef struct QueuePairList { - VMCIList head; - Atomic_uint32 hibernate; - VMCIMutex mutex; -} QueuePairList; - -static QueuePairList qpBrokerList; - -#define QPE_NUM_PAGES(_QPE) ((uint32)(CEILING(_QPE.produceSize, PAGE_SIZE) + \ - CEILING(_QPE.consumeSize, PAGE_SIZE) + 2)) - -#if !defined(VMKERNEL) - static QueuePairList qpGuestEndpoints; - static VMCIHandleArray *hibernateFailedList; - static VMCILock hibernateFailedListLock; -#endif - -static void VMCIQPBrokerLock(void); -static void VMCIQPBrokerUnlock(void); - -static QueuePairEntry *QueuePairList_FindEntry(QueuePairList *qpList, - VMCIHandle handle); -static void QueuePairList_AddEntry(QueuePairList *qpList, - QueuePairEntry *entry); -static void QueuePairList_RemoveEntry(QueuePairList *qpList, - QueuePairEntry *entry); -static QueuePairEntry *QueuePairList_GetHead(QueuePairList *qpList); - -static int QueuePairNotifyPeer(Bool attach, VMCIHandle handle, VMCIId myId, - VMCIId peerId); - -static int VMCIQPBrokerAllocInt(VMCIHandle handle, VMCIId peer, - uint32 flags, VMCIPrivilegeFlags privFlags, - uint64 produceSize, - uint64 consumeSize, - QueuePairPageStore *pageStore, - VMCIContext *context, - VMCIEventReleaseCB wakeupCB, - void *clientData, - QPBrokerEntry **ent, - Bool *swap); -static int VMCIQPBrokerAttach(QPBrokerEntry *entry, - VMCIId peer, - uint32 flags, - VMCIPrivilegeFlags privFlags, - uint64 produceSize, - uint64 consumeSize, - QueuePairPageStore *pageStore, - VMCIContext *context, - VMCIEventReleaseCB wakeupCB, - void *clientData, - QPBrokerEntry **ent); -static int VMCIQPBrokerCreate(VMCIHandle handle, - VMCIId peer, - uint32 flags, - VMCIPrivilegeFlags privFlags, - uint64 produceSize, - uint64 consumeSize, - QueuePairPageStore *pageStore, - VMCIContext *context, - VMCIEventReleaseCB wakeupCB, - void *clientData, - QPBrokerEntry **ent); -static int VMCIQueuePairAllocHostWork(VMCIHandle *handle, VMCIQueue **produceQ, - uint64 produceSize, VMCIQueue **consumeQ, - uint64 consumeSize, - VMCIId peer, uint32 flags, - VMCIPrivilegeFlags privFlags, - VMCIEventReleaseCB wakeupCB, - void *clientData); -static int VMCIQueuePairDetachHostWork(VMCIHandle handle); - -static int QueuePairSaveHeaders(QPBrokerEntry *entry); -static void QueuePairResetSavedHeaders(QPBrokerEntry *entry); - -#if !defined(VMKERNEL) - -static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle); - -static QPGuestEndpoint *QPGuestEndpointCreate(VMCIHandle handle, - VMCIId peer, uint32 flags, - uint64 produceSize, - uint64 consumeSize, - void *produceQ, void *consumeQ); -static void QPGuestEndpointDestroy(QPGuestEndpoint *entry); -static int VMCIQueuePairAllocHypercall(const QPGuestEndpoint *entry); -static int VMCIQueuePairAllocGuestWork(VMCIHandle *handle, VMCIQueue **produceQ, - uint64 produceSize, VMCIQueue **consumeQ, - uint64 consumeSize, - VMCIId peer, uint32 flags, - VMCIPrivilegeFlags privFlags); -static int VMCIQueuePairDetachGuestWork(VMCIHandle handle); -static int VMCIQueuePairDetachHypercall(VMCIHandle handle); -static void VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry); -static void VMCIQPUnmarkHibernateFailed(QPGuestEndpoint *entry); - -extern int VMCI_SendDatagram(VMCIDatagram *); - -#endif - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueuePair_Alloc -- - * - * Allocates a VMCI QueuePair. Only checks validity of input - * arguments. The real work is done in the host or guest - * specific function. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQueuePair_Alloc(VMCIHandle *handle, // IN/OUT - VMCIQueue **produceQ, // OUT - uint64 produceSize, // IN - VMCIQueue **consumeQ, // OUT - uint64 consumeSize, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - Bool guestEndpoint, // IN - VMCIEventReleaseCB wakeupCB, // IN - void *clientData) // IN -{ - if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) || - (flags & ~VMCI_QP_ALL_FLAGS)) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (guestEndpoint) { -#if !defined(VMKERNEL) - return VMCIQueuePairAllocGuestWork(handle, produceQ, produceSize, consumeQ, - consumeSize, peer, flags, privFlags); -#else - return VMCI_ERROR_INVALID_ARGS; -#endif - } else { - return VMCIQueuePairAllocHostWork(handle, produceQ, produceSize, consumeQ, - consumeSize, peer, flags, privFlags, - wakeupCB, clientData); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueuePair_Detach -- - * - * Detaches from a VMCI QueuePair. Only checks validity of input argument. - * Real work is done in the host or guest specific function. - * - * Results: - * Success or failure. - * - * Side effects: - * Memory is freed. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQueuePair_Detach(VMCIHandle handle, // IN - Bool guestEndpoint) // IN -{ - if (VMCI_HANDLE_INVALID(handle)) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (guestEndpoint) { -#if !defined(VMKERNEL) - return VMCIQueuePairDetachGuestWork(handle); -#else - return VMCI_ERROR_INVALID_ARGS; -#endif - } else { - return VMCIQueuePairDetachHostWork(handle); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairList_Init -- - * - * Initializes the list of QueuePairs. - * - * Results: - * Success or failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -QueuePairList_Init(QueuePairList *qpList) // IN -{ - int ret; - - VMCIList_Init(&qpList->head); - Atomic_Write(&qpList->hibernate, 0); - ret = VMCIMutex_Init(&qpList->mutex, "VMCIQPListLock", - VMCI_SEMA_RANK_QUEUEPAIRLIST); - return ret; -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairList_Destroy -- - * - * Destroy the list's mutex. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -QueuePairList_Destroy(QueuePairList *qpList) -{ - VMCIMutex_Destroy(&qpList->mutex); - VMCIList_Init(&qpList->head); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBrokerLock -- - * - * Acquires the mutex protecting a VMCI queue pair broker transaction. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIQPBrokerLock(void) -{ - VMCIMutex_Acquire(&qpBrokerList.mutex); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBrokerUnlock -- - * - * Releases the mutex protecting a VMCI queue pair broker transaction. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIQPBrokerUnlock(void) -{ - VMCIMutex_Release(&qpBrokerList.mutex); -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairList_FindEntry -- - * - * Finds the entry in the list corresponding to a given handle. Assumes - * that the list is locked. - * - * Results: - * Pointer to entry. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static QueuePairEntry * -QueuePairList_FindEntry(QueuePairList *qpList, // IN - VMCIHandle handle) // IN -{ - VMCIListItem *next; - - if (VMCI_HANDLE_INVALID(handle)) { - return NULL; - } - - VMCIList_Scan(next, &qpList->head) { - QueuePairEntry *entry = VMCIList_Entry(next, QueuePairEntry, listItem); - - if (VMCI_HANDLE_EQUAL(entry->handle, handle)) { - return entry; - } - } - - return NULL; -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairList_AddEntry -- - * - * Adds the given entry to the list. Assumes that the list is locked. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -QueuePairList_AddEntry(QueuePairList *qpList, // IN - QueuePairEntry *entry) // IN -{ - if (entry) { - VMCIList_Insert(&entry->listItem, &qpList->head); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairList_RemoveEntry -- - * - * Removes the given entry from the list. Assumes that the list is locked. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -QueuePairList_RemoveEntry(QueuePairList *qpList, // IN - QueuePairEntry *entry) // IN -{ - UNREFERENCED_PARAMETER(qpList); - if (entry) { - VMCIList_Remove(&entry->listItem); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairList_GetHead -- - * - * Returns the entry from the head of the list. Assumes that the list is - * locked. - * - * Results: - * Pointer to entry. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static QueuePairEntry * -QueuePairList_GetHead(QueuePairList *qpList) -{ - VMCIListItem *first = VMCIList_First(&qpList->head); - - if (first) { - QueuePairEntry *entry = VMCIList_Entry(first, QueuePairEntry, listItem); - return entry; - } - - return NULL; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Init -- - * - * Initalizes queue pair broker state. - * - * Results: - * Success or failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_Init(void) -{ - return QueuePairList_Init(&qpBrokerList); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Exit -- - * - * Destroys the queue pair broker state. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIQPBroker_Exit(void) -{ - QPBrokerEntry *entry; - - VMCIQPBrokerLock(); - - while ((entry = (QPBrokerEntry *)QueuePairList_GetHead(&qpBrokerList)) != NULL) { - QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp); - VMCI_FreeKernelMem(entry, sizeof *entry); - } - - VMCIQPBrokerUnlock(); - QueuePairList_Destroy(&qpBrokerList); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Alloc -- - * - * Requests that a queue pair be allocated with the VMCI queue - * pair broker. Allocates a queue pair entry if one does not - * exist. Attaches to one if it exists, and retrieves the page - * files backing that QueuePair. Assumes that the queue pair - * broker lock is held. - * - * Results: - * Success or failure. - * - * Side effects: - * Memory may be allocated. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_Alloc(VMCIHandle handle, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - uint64 produceSize, // IN - uint64 consumeSize, // IN - QueuePairPageStore *pageStore, // IN/OUT - VMCIContext *context) // IN: Caller -{ - return VMCIQPBrokerAllocInt(handle, peer, flags, privFlags, - produceSize, consumeSize, - pageStore, context, NULL, NULL, - NULL, NULL); -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairNotifyPeer -- - * - * Enqueues an event datagram to notify the peer VM attached to - * the given queue pair handle about attach/detach event by the - * given VM. - * - * Results: - * Payload size of datagram enqueued on success, error code otherwise. - * - * Side effects: - * Memory is allocated. - * - *----------------------------------------------------------------------------- - */ - -int -QueuePairNotifyPeer(Bool attach, // IN: attach or detach? - VMCIHandle handle, // IN - VMCIId myId, // IN - VMCIId peerId) // IN: CID of VM to notify -{ - int rv; - VMCIEventMsg *eMsg; - VMCIEventPayload_QP *evPayload; - char buf[sizeof *eMsg + sizeof *evPayload]; - - if (VMCI_HANDLE_INVALID(handle) || myId == VMCI_INVALID_ID || - peerId == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - /* - * Notification message contains: queue pair handle and - * attaching/detaching VM's context id. - */ - - eMsg = (VMCIEventMsg *)buf; - - /* - * In VMCIContext_EnqueueDatagram() we enforce the upper limit on number of - * pending events from the hypervisor to a given VM otherwise a rogue VM - * could do an arbitrary number of attach and detach operations causing memory - * pressure in the host kernel. - */ - - /* Clear out any garbage. */ - memset(eMsg, 0, sizeof buf); - - eMsg->hdr.dst = VMCI_MAKE_HANDLE(peerId, VMCI_EVENT_HANDLER); - eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_CONTEXT_RESOURCE_ID); - eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *evPayload - sizeof eMsg->hdr; - eMsg->eventData.event = attach ? VMCI_EVENT_QP_PEER_ATTACH : - VMCI_EVENT_QP_PEER_DETACH; - evPayload = VMCIEventMsgPayload(eMsg); - evPayload->handle = handle; - evPayload->peerId = myId; - - rv = VMCIDatagram_Dispatch(VMCI_HYPERVISOR_CONTEXT_ID, (VMCIDatagram *)eMsg, - FALSE); - if (rv < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to enqueue QueuePair %s event datagram for " - "context (ID=0x%x).\n", attach ? "ATTACH" : "DETACH", - peerId)); - } - - return rv; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIQueuePairAllocHostWork -- - * - * This function implements the kernel API for allocating a queue - * pair. - * - * Results: - * VMCI_SUCCESS on succes and appropriate failure code otherwise. - * - * Side effects: - * May allocate memory. - * - *---------------------------------------------------------------------- - */ - -static int -VMCIQueuePairAllocHostWork(VMCIHandle *handle, // IN/OUT - VMCIQueue **produceQ, // OUT - uint64 produceSize, // IN - VMCIQueue **consumeQ, // OUT - uint64 consumeSize, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - VMCIEventReleaseCB wakeupCB, // IN - void *clientData) // IN -{ - VMCIContext *context; - QPBrokerEntry *entry; - int result; - Bool swap; - - if (VMCI_HANDLE_INVALID(*handle)) { - VMCIId resourceID = VMCIResource_GetID(VMCI_HOST_CONTEXT_ID); - if (resourceID == VMCI_INVALID_ID) { - return VMCI_ERROR_NO_HANDLE; - } - *handle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID, resourceID); - } - - context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID); - ASSERT(context); - - entry = NULL; - result = VMCIQPBrokerAllocInt(*handle, peer, flags, privFlags, produceSize, - consumeSize, NULL, context, wakeupCB, clientData, - &entry, &swap); - if (result == VMCI_SUCCESS) { - if (swap) { - /* - * If this is a local queue pair, the attacher will swap around produce - * and consume queues. - */ - - *produceQ = entry->consumeQ; - *consumeQ = entry->produceQ; - } else { - *produceQ = entry->produceQ; - *consumeQ = entry->consumeQ; - } - } else { - *handle = VMCI_INVALID_HANDLE; - VMCI_DEBUG_LOG(4, (LGPFX"queue pair broker failed to alloc (result=%d).\n", - result)); - } - VMCIContext_Release(context); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIQueuePairDetachHostWork -- - * - * This function implements the host kernel API for detaching from - * a queue pair. - * - * Results: - * VMCI_SUCCESS on success and appropriate failure code otherwise. - * - * Side effects: - * May deallocate memory. - * - *---------------------------------------------------------------------- - */ - -static int -VMCIQueuePairDetachHostWork(VMCIHandle handle) // IN -{ - int result; - VMCIContext *context; - - context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID); - - result = VMCIQPBroker_Detach(handle, context); - - VMCIContext_Release(context); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBrokerAllocInt -- - * - * QueuePair_Alloc for use when setting up queue pair endpoints - * on the host. Like QueuePair_Alloc, but returns a pointer to - * the QPBrokerEntry on success. - * - * Results: - * Success or failure. - * - * Side effects: - * Memory may be allocated. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPBrokerAllocInt(VMCIHandle handle, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - uint64 produceSize, // IN - uint64 consumeSize, // IN - QueuePairPageStore *pageStore, // IN/OUT - VMCIContext *context, // IN: Caller - VMCIEventReleaseCB wakeupCB, // IN - void *clientData, // IN - QPBrokerEntry **ent, // OUT - Bool *swap) // OUT: swap queues? -{ - const VMCIId contextId = VMCIContext_GetId(context); - Bool create; - QPBrokerEntry *entry; - Bool isLocal = flags & VMCI_QPFLAG_LOCAL; - int result; - -#if defined(_WIN32) -#pragma warning(suppress: 6235) /* !vmkernel always true */ -#endif - if (VMCI_HANDLE_INVALID(handle) || - (flags & ~VMCI_QP_ALL_FLAGS) || - (isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID || - handle.context != contextId)) || - !(produceSize || consumeSize) || - !context || contextId == VMCI_INVALID_ID || - handle.context == VMCI_INVALID_ID) { - VMCI_DEBUG_LOG(5, ("Invalid argument - handle, flags, whatever\n")); - return VMCI_ERROR_INVALID_ARGS; - } - - if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) { - VMCI_DEBUG_LOG(5, ("Invalid argument - page store\n")); - return VMCI_ERROR_INVALID_ARGS; - } - - /* - * In the initial argument check, we ensure that non-vmkernel hosts - * are not allowed to create local queue pairs. - */ - - ASSERT(vmkernel || !isLocal); - - VMCIQPBrokerLock(); - - if (!isLocal && VMCIContext_QueuePairExists(context, handle)) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair " - "(handle=0x%x:0x%x).\n", - contextId, handle.context, handle.resource)); - VMCIQPBrokerUnlock(); - return VMCI_ERROR_ALREADY_EXISTS; - } - - entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle); - if (!entry) { - create = TRUE; - result = VMCIQPBrokerCreate(handle, peer, flags, privFlags, produceSize, - consumeSize, pageStore, context, wakeupCB, - clientData, ent); - } else { - create = FALSE; - result = VMCIQPBrokerAttach(entry, peer, flags, privFlags, produceSize, - consumeSize, pageStore, context, wakeupCB, - clientData, ent); - } - - VMCIQPBrokerUnlock(); - - if (swap) { - *swap = (contextId == VMCI_HOST_CONTEXT_ID) && !(create && isLocal); - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBrokerCreate -- - * - * The first endpoint issuing a queue pair allocation will create the state - * of the queue pair in the queue pair broker. - * - * If the creator is a guest, it will associate a VMX virtual address range - * with the queue pair as specified by the pageStore. For compatibility with - * older VMX'en, that would use a separate step to set the VMX virtual - * address range, the virtual address range can be registered later using - * VMCIQPBroker_SetPageStore. In that case, a pageStore of NULL should be - * used. - * - * If the creator is the host, a pageStore of NULL should be used as well, - * since the host is not able to supply a page store for the queue pair. - * - * For older VMX and host callers, the queue pair will be created in the - * VMCIQPB_CREATED_NO_MEM state, and for current VMX callers, it will be - * created in VMCOQPB_CREATED_MEM state. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Memory will be allocated, and pages may be pinned. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPBrokerCreate(VMCIHandle handle, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - uint64 produceSize, // IN - uint64 consumeSize, // IN - QueuePairPageStore *pageStore, // IN - VMCIContext *context, // IN: Caller - VMCIEventReleaseCB wakeupCB, // IN - void *clientData, // IN - QPBrokerEntry **ent) // OUT -{ - QPBrokerEntry *entry = NULL; - const VMCIId contextId = VMCIContext_GetId(context); - Bool isLocal = flags & VMCI_QPFLAG_LOCAL; - int result; - uint64 guestProduceSize; - uint64 guestConsumeSize; - - /* - * Do not create if the caller asked not to. - */ - - if (flags & VMCI_QPFLAG_ATTACH_ONLY) { - VMCI_DEBUG_LOG(5, ("QP Create - attach only\n")); - return VMCI_ERROR_NOT_FOUND; - } - - /* - * Creator's context ID should match handle's context ID or the creator - * must allow the context in handle's context ID as the "peer". - */ - - if (handle.context != contextId && handle.context != peer) { - VMCI_DEBUG_LOG(5, ("QP Create - contextId fail, %x != %x, %x\n", - handle.context, contextId, peer)); - return VMCI_ERROR_NO_ACCESS; - } - - if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(peer)) { - VMCI_DEBUG_LOG(5, ("QP Create - VM2VM\n")); - return VMCI_ERROR_DST_UNREACHABLE; - } - - /* - * Creator's context ID for local queue pairs should match the - * peer, if a peer is specified. - */ - - if (isLocal && peer != VMCI_INVALID_ID && contextId != peer) { - VMCI_DEBUG_LOG(5, ("QP Create - peer %x, context %x\n", - peer, contextId)); - return VMCI_ERROR_NO_ACCESS; - } - - entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC); - if (!entry) { - VMCI_DEBUG_LOG(5, ("QP Create - no memory\n")); - return VMCI_ERROR_NO_MEM; - } - - if (VMCIContext_GetId(context) == VMCI_HOST_CONTEXT_ID && !isLocal) { - /* - * The queue pair broker entry stores values from the guest - * point of view, so a creating host side endpoint should swap - * produce and consume values -- unless it is a local queue - * pair, in which case no swapping is necessary, since the local - * attacher will swap queues. - */ - - guestProduceSize = consumeSize; - guestConsumeSize = produceSize; - } else { - guestProduceSize = produceSize; - guestConsumeSize = consumeSize; - } - - memset(entry, 0, sizeof *entry); - entry->qp.handle = handle; - entry->qp.peer = peer; - entry->qp.flags = flags; - entry->qp.produceSize = guestProduceSize; - entry->qp.consumeSize = guestConsumeSize; - entry->qp.refCount = 1; - entry->createId = contextId; - entry->attachId = VMCI_INVALID_ID; - entry->state = VMCIQPB_NEW; - entry->requireTrustedAttach = - (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE; - entry->createdByTrusted = - (privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE; - entry->vmciPageFiles = FALSE; - entry->wakeupCB = wakeupCB; - entry->clientData = clientData; - entry->produceQ = VMCIHost_AllocQueue(guestProduceSize); - if (entry->produceQ == NULL) { - result = VMCI_ERROR_NO_MEM; - VMCI_DEBUG_LOG(5, ("QP Create - no memory PQ\n")); - goto error; - } - entry->consumeQ = VMCIHost_AllocQueue(guestConsumeSize); - if (entry->consumeQ == NULL) { - result = VMCI_ERROR_NO_MEM; - VMCI_DEBUG_LOG(5, ("QP Create - no memory CQ\n")); - goto error; - } - - VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ); - - VMCIList_InitEntry(&entry->qp.listItem); - - if (isLocal) { - ASSERT(pageStore == NULL); - - entry->localMem = VMCI_AllocKernelMem(QPE_NUM_PAGES(entry->qp) * PAGE_SIZE, - VMCI_MEMORY_NONPAGED); - if (entry->localMem == NULL) { - result = VMCI_ERROR_NO_MEM; - VMCI_DEBUG_LOG(5, ("QP Create - no memory LM\n")); - goto error; - } - entry->state = VMCIQPB_CREATED_MEM; - entry->produceQ->qHeader = entry->localMem; - entry->consumeQ->qHeader = - (VMCIQueueHeader *)((uint8 *)entry->localMem + - (CEILING(entry->qp.produceSize, PAGE_SIZE) + 1) * PAGE_SIZE); - VMCIQueueHeader_Init(entry->produceQ->qHeader, handle); - VMCIQueueHeader_Init(entry->consumeQ->qHeader, handle); - } else if (pageStore) { - ASSERT(entry->createId != VMCI_HOST_CONTEXT_ID || isLocal); - - /* - * The VMX already initialized the queue pair headers, so no - * need for the kernel side to do that. - */ - - result = VMCIHost_RegisterUserMemory(pageStore, - entry->produceQ, - entry->consumeQ); - if (result < VMCI_SUCCESS) { - VMCI_DEBUG_LOG(5, ("QP Create - cannot register user memory\n")); - goto error; - } - VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ); - entry->state = VMCIQPB_CREATED_MEM; - } else { - /* - * A create without a pageStore may be either a host side create (in which - * case we are waiting for the guest side to supply the memory) or an old - * style queue pair create (in which case we will expect a set page store - * call as the next step). - */ - - entry->state = VMCIQPB_CREATED_NO_MEM; - } - - QueuePairList_AddEntry(&qpBrokerList, &entry->qp); - if (ent != NULL) { - *ent = entry; - } - - VMCIContext_QueuePairCreate(context, handle); - - return VMCI_SUCCESS; - -error: - if (entry != NULL) { - if (entry->produceQ != NULL) { - VMCIHost_FreeQueue(entry->produceQ, guestProduceSize); - } - if (entry->consumeQ != NULL) { - VMCIHost_FreeQueue(entry->consumeQ, guestConsumeSize); - } - VMCI_FreeKernelMem(entry, sizeof *entry); - } - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBrokerAttach -- - * - * The second endpoint issuing a queue pair allocation will attach to the - * queue pair registered with the queue pair broker. - * - * If the attacher is a guest, it will associate a VMX virtual address range - * with the queue pair as specified by the pageStore. At this point, the - * already attach host endpoint may start using the queue pair, and an - * attach event is sent to it. For compatibility with older VMX'en, that - * used a separate step to set the VMX virtual address range, the virtual - * address range can be registered later using VMCIQPBroker_SetPageStore. In - * that case, a pageStore of NULL should be used, and the attach event will - * be generated once the actual page store has been set. - * - * If the attacher is the host, a pageStore of NULL should be used as well, - * since the page store information is already set by the guest. - * - * For new VMX and host callers, the queue pair will be moved to the - * VMCIQPB_ATTACHED_MEM state, and for older VMX callers, it will be - * moved to the VMCOQPB_ATTACHED_NO_MEM state. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Memory will be allocated, and pages may be pinned. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQPBrokerAttach(QPBrokerEntry *entry, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags, // IN - uint64 produceSize, // IN - uint64 consumeSize, // IN - QueuePairPageStore *pageStore, // IN/OUT - VMCIContext *context, // IN: Caller - VMCIEventReleaseCB wakeupCB, // IN - void *clientData, // IN - QPBrokerEntry **ent) // OUT -{ - const VMCIId contextId = VMCIContext_GetId(context); - Bool isLocal = flags & VMCI_QPFLAG_LOCAL; - int result; - - UNREFERENCED_PARAMETER(peer); - - if (entry->state != VMCIQPB_CREATED_NO_MEM && - entry->state != VMCIQPB_CREATED_MEM) { - VMCI_DEBUG_LOG(5, ("QP Attach - state is %x\n", entry->state)); - return VMCI_ERROR_UNAVAILABLE; - } - - if (isLocal) { - if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) || - contextId != entry->createId) { - VMCI_DEBUG_LOG(5, ("QP Attach - invalid args, ctx=%x, createId=%x\n", - contextId, entry->createId)); - return VMCI_ERROR_INVALID_ARGS; - } - } else if (contextId == entry->createId || contextId == entry->attachId) { - VMCI_DEBUG_LOG(5, ("QP Attach - already, ctx=%x, create=%x, attach=%x\n", - contextId, entry->createId, entry->attachId)); - return VMCI_ERROR_ALREADY_EXISTS; - } - - ASSERT(entry->qp.refCount < 2); - ASSERT(entry->attachId == VMCI_INVALID_ID); - - if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(entry->createId)) { - VMCI_DEBUG_LOG(5, ("QP Attach - VM2VM\n")); - return VMCI_ERROR_DST_UNREACHABLE; - } - - /* - * If we are attaching from a restricted context then the queuepair - * must have been created by a trusted endpoint. - */ - - if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) { - if (!entry->createdByTrusted) { - VMCI_DEBUG_LOG(5, ("QP Attach - restricted vs trusted\n")); - return VMCI_ERROR_NO_ACCESS; - } - } - - /* - * If we are attaching to a queuepair that was created by a restricted - * context then we must be trusted. - */ - - if (entry->requireTrustedAttach) { - if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) { - VMCI_DEBUG_LOG(5, ("QP Attach - trusted attach required\n")); - return VMCI_ERROR_NO_ACCESS; - } - } - - /* - * If the creator specifies VMCI_INVALID_ID in "peer" field, access - * control check is not performed. - */ - - if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) { - VMCI_DEBUG_LOG(5, ("QP Attach - bad peer id %x != %x\n", - contextId, entry->qp.peer)); - return VMCI_ERROR_NO_ACCESS; - } - - if (entry->createId == VMCI_HOST_CONTEXT_ID) { - /* - * Do not attach if the caller doesn't support Host Queue Pairs - * and a host created this queue pair. - */ - - if (!VMCIContext_SupportsHostQP(context)) { - VMCI_DEBUG_LOG(5, ("QP Attach - no attach to host qp\n")); - return VMCI_ERROR_INVALID_RESOURCE; - } - } else if (contextId == VMCI_HOST_CONTEXT_ID) { - VMCIContext *createContext; - Bool supportsHostQP; - - /* - * Do not attach a host to a user created queue pair if that - * user doesn't support host queue pair end points. - */ - - createContext = VMCIContext_Get(entry->createId); - supportsHostQP = VMCIContext_SupportsHostQP(createContext); - VMCIContext_Release(createContext); - - if (!supportsHostQP) { - VMCI_DEBUG_LOG(5, ("QP Attach - no host attach to qp\n")); - return VMCI_ERROR_INVALID_RESOURCE; - } - } - - if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER)) { - VMCI_DEBUG_LOG(5, ("QP Attach - flags mismatch\n")); - return VMCI_ERROR_QUEUEPAIR_MISMATCH; - } - - if (contextId != VMCI_HOST_CONTEXT_ID) { - /* - * The queue pair broker entry stores values from the guest - * point of view, so an attaching guest should match the values - * stored in the entry. - */ - - if (entry->qp.produceSize != produceSize || - entry->qp.consumeSize != consumeSize) { - VMCI_DEBUG_LOG(5, ("QP Attach - queue size mismatch\n")); - return VMCI_ERROR_QUEUEPAIR_MISMATCH; - } - } else if (entry->qp.produceSize != consumeSize || - entry->qp.consumeSize != produceSize) { - VMCI_DEBUG_LOG(5, ("QP Attach - host queue size mismatch\n")); - return VMCI_ERROR_QUEUEPAIR_MISMATCH; - } - - if (contextId != VMCI_HOST_CONTEXT_ID) { - /* - * If a guest attached to a queue pair, it will supply the backing memory. - * If this is a pre NOVMVM vmx, the backing memory will be supplied by - * calling VMCIQPBroker_SetPageStore() following the return of the - * VMCIQPBroker_Alloc() call. If it is a vmx of version NOVMVM or later, - * the page store must be supplied as part of the VMCIQPBroker_Alloc call. - * Under all circumstances must the initially created queue pair not have - * any memory associated with it already. - */ - - if (entry->state != VMCIQPB_CREATED_NO_MEM) { - VMCI_DEBUG_LOG(5, ("QP Attach - bad QP state for VM2VM, %x, %p\n", - entry->state, pageStore)); - return VMCI_ERROR_INVALID_ARGS; - } - - if (pageStore != NULL) { - /* - * Patch up host state to point to guest supplied memory. The VMX - * already initialized the queue pair headers, so no need for the - * kernel side to do that. - */ - - result = VMCIHost_RegisterUserMemory(pageStore, - entry->produceQ, - entry->consumeQ); - if (result < VMCI_SUCCESS) { - VMCI_DEBUG_LOG(5, ("QP Attach - cannot register memory\n")); - return result; - } - VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ); - if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) { - result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, - entry->qp.flags); - if (result < VMCI_SUCCESS) { - VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ); - VMCI_DEBUG_LOG(5, ("QP Attach - cannot map queues\n")); - return result; - } - } - entry->state = VMCIQPB_ATTACHED_MEM; - } else { - entry->state = VMCIQPB_ATTACHED_NO_MEM; - } - } else if (entry->state == VMCIQPB_CREATED_NO_MEM) { - /* - * The host side is attempting to attach to a queue pair that doesn't have - * any memory associated with it. This must be a pre NOVMVM vmx that hasn't - * set the page store information yet, or a quiesced VM. - */ - - VMCI_DEBUG_LOG(5, ("QP Attach - QP without memory\n")); - return VMCI_ERROR_UNAVAILABLE; - } else { - /* - * For non-blocking queue pairs, we cannot rely on enqueue/dequeue to map - * in the pages on the host-side, since it may block, so we make an attempt - * here. - */ - - if (flags & VMCI_QPFLAG_NONBLOCK) { - result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, flags); - if (result < VMCI_SUCCESS) { - VMCI_DEBUG_LOG(5, ("QP Attach - cannot map queues for host\n")); - return result; - } - entry->qp.flags |= flags & VMCI_QPFLAG_NONBLOCK; - } - - /* - * The host side has successfully attached to a queue pair. - */ - - entry->state = VMCIQPB_ATTACHED_MEM; - } - - if (entry->state == VMCIQPB_ATTACHED_MEM) { - result = QueuePairNotifyPeer(TRUE, entry->qp.handle, contextId, - entry->createId); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue " - "pair (handle=0x%x:0x%x).\n", entry->createId, - entry->qp.handle.context, entry->qp.handle.resource)); - } - } - - entry->attachId = contextId; - entry->qp.refCount++; - if (wakeupCB) { - ASSERT(!entry->wakeupCB); - entry->wakeupCB = wakeupCB; - entry->clientData = clientData; - } - - /* - * When attaching to local queue pairs, the context already has - * an entry tracking the queue pair, so don't add another one. - */ - - if (!isLocal) { - VMCIContext_QueuePairCreate(context, entry->qp.handle); - } else { - ASSERT(VMCIContext_QueuePairExists(context, entry->qp.handle)); - } - if (ent != NULL) { - *ent = entry; - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_SetPageStore -- - * - * VMX'en with versions lower than VMCI_VERSION_NOVMVM use a separate - * step to add the UVAs of the VMX mapping of the queue pair. This function - * provides backwards compatibility with such VMX'en, and takes care of - * registering the page store for a queue pair previously allocated by the - * VMX during create or attach. This function will move the queue pair state - * to either from VMCIQBP_CREATED_NO_MEM to VMCIQBP_CREATED_MEM or - * VMCIQBP_ATTACHED_NO_MEM to VMCIQBP_ATTACHED_MEM. If moving to the - * attached state with memory, the queue pair is ready to be used by the - * host peer, and an attached event will be generated. - * - * Assumes that the queue pair broker lock is held. - * - * This function is only used by the hosted platform, since there is no - * issue with backwards compatibility for vmkernel. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Pages may get pinned. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_SetPageStore(VMCIHandle handle, // IN - VA64 produceUVA, // IN - VA64 consumeUVA, // IN - VMCIContext *context) // IN: Caller -{ - QPBrokerEntry *entry; - int result; - const VMCIId contextId = VMCIContext_GetId(context); - - if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - /* - * We only support guest to host queue pairs, so the VMX must - * supply UVAs for the mapped page files. - */ - - if (produceUVA == 0 || consumeUVA == 0) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPBrokerLock(); - - if (!VMCIContext_QueuePairExists(context, handle)) { - VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair " - "(handle=0x%x:0x%x).\n", contextId, handle.context, - handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle); - if (!entry) { - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - /* - * If I'm the owner then I can set the page store. - * - * Or, if a host created the QueuePair and I'm the attached peer - * then I can set the page store. - */ - - if (entry->createId != contextId && - (entry->createId != VMCI_HOST_CONTEXT_ID || - entry->attachId != contextId)) { - result = VMCI_ERROR_QUEUEPAIR_NOTOWNER; - goto out; - } - - if (entry->state != VMCIQPB_CREATED_NO_MEM && - entry->state != VMCIQPB_ATTACHED_NO_MEM) { - result = VMCI_ERROR_UNAVAILABLE; - goto out; - } - - result = VMCIHost_GetUserMemory(produceUVA, consumeUVA, - entry->produceQ, entry->consumeQ); - if (result < VMCI_SUCCESS) { - goto out; - } - VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ); - result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE); - if (result < VMCI_SUCCESS) { - VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ); - goto out; - } - - if (entry->state == VMCIQPB_CREATED_NO_MEM) { - entry->state = VMCIQPB_CREATED_MEM; - } else { - ASSERT(entry->state == VMCIQPB_ATTACHED_NO_MEM); - entry->state = VMCIQPB_ATTACHED_MEM; - } - entry->vmciPageFiles = TRUE; - - if (entry->state == VMCIQPB_ATTACHED_MEM) { - result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue " - "pair (handle=0x%x:0x%x).\n", entry->createId, - entry->qp.handle.context, entry->qp.handle.resource)); - } - } - - result = VMCI_SUCCESS; -out: - VMCIQPBrokerUnlock(); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Detach -- - * - * The main entry point for detaching from a queue pair registered with the - * queue pair broker. If more than one endpoint is attached to the queue - * pair, the first endpoint will mainly decrement a reference count and - * generate a notification to its peer. The last endpoint will clean up - * the queue pair state registered with the broker. - * - * When a guest endpoint detaches, it will unmap and unregister the guest - * memory backing the queue pair. If the host is still attached, it will - * no longer be able to access the queue pair content. - * - * If the queue pair is already in a state where there is no memory - * registered for the queue pair (any *_NO_MEM state), it will transition to - * the VMCIQPB_SHUTDOWN_NO_MEM state. This will also happen, if a guest - * endpoint is the first of two endpoints to detach. If the host endpoint is - * the first out of two to detach, the queue pair will move to the - * VMCIQPB_SHUTDOWN_MEM state. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Memory may be freed, and pages may be unpinned. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_Detach(VMCIHandle handle, // IN - VMCIContext *context) // IN -{ - QPBrokerEntry *entry; - const VMCIId contextId = VMCIContext_GetId(context); - VMCIId peerId; - Bool isLocal = FALSE; - int result; - - if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPBrokerLock(); - - if (!VMCIContext_QueuePairExists(context, handle)) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair " - "(handle=0x%x:0x%x).\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle); - if (!entry) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair " - "(handle=0x%x:0x%x) that isn't present in broker.\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - if (contextId != entry->createId && contextId != entry->attachId) { - result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED; - goto out; - } - - if (contextId == entry->createId) { - peerId = entry->attachId; - entry->createId = VMCI_INVALID_ID; - } else { - peerId = entry->createId; - entry->attachId = VMCI_INVALID_ID; - } - entry->qp.refCount--; - - isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL; - - if (contextId != VMCI_HOST_CONTEXT_ID) { - int result2; - Bool headersMapped; - - ASSERT(!isLocal); - - /* - * Pre NOVMVM vmx'en may detach from a queue pair before setting the page - * store, and in that case there is no user memory to detach from. Also, - * more recent VMX'en may detach from a queue pair in the quiesced state. - */ - - VMCI_AcquireQueueMutex(entry->produceQ, TRUE); - headersMapped = entry->produceQ->qHeader || entry->consumeQ->qHeader; - if (QPBROKERSTATE_HAS_MEM(entry)) { - result2 = VMCIHost_UnmapQueues(INVALID_VMCI_GUEST_MEM_ID, - entry->produceQ, - entry->consumeQ); - if (result2 < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to unmap queue headers for queue pair " - "(handle=0x%x:0x%x,result2=%d).\n", handle.context, - handle.resource, result2)); - } - VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ); - if (entry->vmciPageFiles) { - VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ); - } else { - VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ); - } - } - if (!headersMapped) { - QueuePairResetSavedHeaders(entry); - } - VMCI_ReleaseQueueMutex(entry->produceQ); - if (!headersMapped && entry->wakeupCB) { - entry->wakeupCB(entry->clientData); - } - } else { - if (entry->wakeupCB) { - entry->wakeupCB = NULL; - entry->clientData = NULL; - } - } - - if (entry->qp.refCount == 0) { - QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp); - - if (isLocal) { - VMCI_FreeKernelMem(entry->localMem, QPE_NUM_PAGES(entry->qp) * PAGE_SIZE); - } - VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ); - VMCIHost_FreeQueue(entry->produceQ, entry->qp.produceSize); - VMCIHost_FreeQueue(entry->consumeQ, entry->qp.consumeSize); - VMCI_FreeKernelMem(entry, sizeof *entry); - - VMCIContext_QueuePairDestroy(context, handle); - } else { - ASSERT(peerId != VMCI_INVALID_ID); - QueuePairNotifyPeer(FALSE, handle, contextId, peerId); - if (contextId == VMCI_HOST_CONTEXT_ID && QPBROKERSTATE_HAS_MEM(entry)) { - entry->state = VMCIQPB_SHUTDOWN_MEM; - } else { - entry->state = VMCIQPB_SHUTDOWN_NO_MEM; - } - if (!isLocal) { - VMCIContext_QueuePairDestroy(context, handle); - } - } - result = VMCI_SUCCESS; -out: - VMCIQPBrokerUnlock(); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Map -- - * - * Establishes the necessary mappings for a queue pair given a - * reference to the queue pair guest memory. This is usually - * called when a guest is unquiesced and the VMX is allowed to - * map guest memory once again. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Memory may be allocated, and pages may be pinned. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_Map(VMCIHandle handle, // IN - VMCIContext *context, // IN - VMCIQPGuestMem guestMem) // IN -{ - QPBrokerEntry *entry; - const VMCIId contextId = VMCIContext_GetId(context); - Bool isLocal = FALSE; - int result; - - if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPBrokerLock(); - - if (!VMCIContext_QueuePairExists(context, handle)) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair " - "(handle=0x%x:0x%x).\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle); - if (!entry) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair " - "(handle=0x%x:0x%x) that isn't present in broker.\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - if (contextId != entry->createId && contextId != entry->attachId) { - result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED; - goto out; - } - - isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL; - - if (vmkernel) { - /* - * On vmkernel, the readiness of the queue pair can be signalled - * immediately since the guest memory is already registered. - */ - - VMCI_AcquireQueueMutex(entry->produceQ, TRUE); - VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ); - if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) { - result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, - entry->qp.flags); - } else { - result = VMCI_SUCCESS; - } - if (result == VMCI_SUCCESS) { - QueuePairResetSavedHeaders(entry); - } - VMCI_ReleaseQueueMutex(entry->produceQ); - if (result == VMCI_SUCCESS) { - if (entry->wakeupCB) { - entry->wakeupCB(entry->clientData); - } - } - } else if (contextId != VMCI_HOST_CONTEXT_ID) { - QueuePairPageStore pageStore; - - ASSERT(entry->state == VMCIQPB_CREATED_NO_MEM || - entry->state == VMCIQPB_SHUTDOWN_NO_MEM || - entry->state == VMCIQPB_ATTACHED_NO_MEM); - ASSERT(!isLocal); - - pageStore.pages = guestMem; - pageStore.len = QPE_NUM_PAGES(entry->qp); - - VMCI_AcquireQueueMutex(entry->produceQ, TRUE); - QueuePairResetSavedHeaders(entry); - result = VMCIHost_RegisterUserMemory(&pageStore, entry->produceQ, entry->consumeQ); - VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ); - VMCI_ReleaseQueueMutex(entry->produceQ); - if (result == VMCI_SUCCESS) { - /* - * Move state from *_NO_MEM to *_MEM. - */ - - entry->state++; - - ASSERT(entry->state == VMCIQPB_CREATED_MEM || - entry->state == VMCIQPB_SHUTDOWN_MEM || - entry->state == VMCIQPB_ATTACHED_MEM); - - if (entry->wakeupCB) { - entry->wakeupCB(entry->clientData); - } - } - } else { - result = VMCI_SUCCESS; - } - -out: - VMCIQPBrokerUnlock(); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairSaveHeaders -- - * - * Saves a snapshot of the queue headers for the given QP broker - * entry. Should be used when guest memory is unmapped. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code if guest memory - * can't be accessed.. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -QueuePairSaveHeaders(QPBrokerEntry *entry) // IN -{ - int result; - - if (entry->produceQ->savedHeader != NULL && - entry->consumeQ->savedHeader != NULL) { - /* - * If the headers have already been saved, we don't need to do - * it again, and we don't want to map in the headers - * unnecessarily. - */ - return VMCI_SUCCESS; - } - if (NULL == entry->produceQ->qHeader || NULL == entry->consumeQ->qHeader) { - result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE); - if (result < VMCI_SUCCESS) { - return result; - } -#if defined(_WIN32) - __assume(entry->produceQ->qHeader != NULL); - __assume(entry->consumeQ->qHeader != NULL); -#endif - } - memcpy(&entry->savedProduceQ, entry->produceQ->qHeader, - sizeof entry->savedProduceQ); - entry->produceQ->savedHeader = &entry->savedProduceQ; - memcpy(&entry->savedConsumeQ, entry->consumeQ->qHeader, - sizeof entry->savedConsumeQ); - entry->consumeQ->savedHeader = &entry->savedConsumeQ; - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * QueuePairResetSavedHeaders -- - * - * Resets saved queue headers for the given QP broker - * entry. Should be used when guest memory becomes available - * again, or the guest detaches. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -QueuePairResetSavedHeaders(QPBrokerEntry *entry) // IN -{ - if (vmkernel) { - VMCI_LockQueueHeader(entry->produceQ); - } - entry->produceQ->savedHeader = NULL; - entry->consumeQ->savedHeader = NULL; - if (vmkernel) { - VMCI_UnlockQueueHeader(entry->produceQ); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Unmap -- - * - * Removes all references to the guest memory of a given queue pair, and - * will move the queue pair from state *_MEM to *_NO_MEM. It is usually - * called when a VM is being quiesced where access to guest memory should - * avoided. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Memory may be freed, and pages may be unpinned. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_Unmap(VMCIHandle handle, // IN - VMCIContext *context, // IN - VMCIGuestMemID gid) // IN -{ - QPBrokerEntry *entry; - const VMCIId contextId = VMCIContext_GetId(context); - Bool isLocal = FALSE; - int result; - - if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) { - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIQPBrokerLock(); - if (!VMCIContext_QueuePairExists(context, handle)) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair " - "(handle=0x%x:0x%x).\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle); - if (!entry) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair " - "(handle=0x%x:0x%x) that isn't present in broker.\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - if (contextId != entry->createId && contextId != entry->attachId) { - result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED; - goto out; - } - - isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL; - - if (contextId != VMCI_HOST_CONTEXT_ID) { - ASSERT(entry->state != VMCIQPB_CREATED_NO_MEM && - entry->state != VMCIQPB_SHUTDOWN_NO_MEM && - entry->state != VMCIQPB_ATTACHED_NO_MEM); - ASSERT(!isLocal); - - VMCI_AcquireQueueMutex(entry->produceQ, TRUE); - result = QueuePairSaveHeaders(entry); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Failed to save queue headers for queue pair " - "(handle=0x%x:0x%x,result=%d).\n", handle.context, - handle.resource, result)); - } - VMCIHost_UnmapQueues(gid, entry->produceQ, entry->consumeQ); - VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ); - if (!vmkernel) { - /* - * On hosted, when we unmap queue pairs, the VMX will also - * unmap the guest memory, so we invalidate the previously - * registered memory. If the queue pair is mapped again at a - * later point in time, we will need to reregister the user - * memory with a possibly new user VA. - */ - - VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ); - - /* - * Move state from *_MEM to *_NO_MEM. - */ - - entry->state--; - } - - VMCI_ReleaseQueueMutex(entry->produceQ); - } - - result = VMCI_SUCCESS; -out: - VMCIQPBrokerUnlock(); - return result; -} - -#if defined(VMKERNEL) -/* - *----------------------------------------------------------------------------- - * - * VMCIQPBroker_Revalidate -- - * - * Revalidates the guest memory mappings of a given queue pair. - * - * Results: - * VMCI_SUCCESS on success, appropriate error code otherwise. - * - * Side effects: - * Nond. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPBroker_Revalidate(VMCIHandle handle, // IN - VMCIContext *context) // IN -{ - QPBrokerEntry *entry; - const VMCIId contextId = VMCIContext_GetId(context); - int result = VMCI_SUCCESS; - - ASSERT(!VMCI_HANDLE_INVALID(handle) && contextId != VMCI_INVALID_ID); - - VMCIQPBrokerLock(); - if (!VMCIContext_QueuePairExists(context, handle)) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair " - "(handle=0x%x:0x%x).\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle); - if (entry == NULL) { - VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to " - "queue pair (handle=0x%x:0x%x) that isn't present in " - "broker.\n", - contextId, handle.context, handle.resource)); - result = VMCI_ERROR_NOT_FOUND; - goto out; - } - - if (contextId != entry->createId && contextId != entry->attachId) { - result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED; - goto out; - } - - if (contextId != VMCI_HOST_CONTEXT_ID) { - ASSERT(entry->state != VMCIQPB_CREATED_NO_MEM && - entry->state != VMCIQPB_SHUTDOWN_NO_MEM && - entry->state != VMCIQPB_ATTACHED_NO_MEM); - ASSERT((entry->qp.flags & VMCI_QPFLAG_LOCAL) == 0); - - VMCI_AcquireQueueMutex(entry->produceQ, TRUE); - result = VMCIHost_RevalidateQueues(entry->produceQ, entry->consumeQ); - VMCI_ReleaseQueueMutex(entry->produceQ); - } - -out: - VMCIQPBrokerUnlock(); - return result; -} -#endif - - -#if !defined(VMKERNEL) - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPGuestEndpoints_Init -- - * - * Initalizes data structure state keeping track of queue pair - * guest endpoints. - * - * Results: - * VMCI_SUCCESS on success and appropriate failure code otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQPGuestEndpoints_Init(void) -{ - int err; - - err = QueuePairList_Init(&qpGuestEndpoints); - if (err < VMCI_SUCCESS) { - return err; - } - - hibernateFailedList = VMCIHandleArray_Create(0); - if (NULL == hibernateFailedList) { - QueuePairList_Destroy(&qpGuestEndpoints); - return VMCI_ERROR_NO_MEM; - } - - /* - * The lock rank must be lower than subscriberLock in vmciEvent, - * since we hold the hibernateFailedListLock while generating - * detach events. - */ - - err = VMCI_InitLock(&hibernateFailedListLock, "VMCIQPHibernateFailed", - VMCI_LOCK_RANK_QPHIBERNATE); - if (err < VMCI_SUCCESS) { - VMCIHandleArray_Destroy(hibernateFailedList); - hibernateFailedList = NULL; - QueuePairList_Destroy(&qpGuestEndpoints); - } - - return err; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPGuestEndpoints_Exit -- - * - * Destroys all guest queue pair endpoints. If active guest queue - * pairs still exist, hypercalls to attempt detach from these - * queue pairs will be made. Any failure to detach is silently - * ignored. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIQPGuestEndpoints_Exit(void) -{ - QPGuestEndpoint *entry; - - VMCIMutex_Acquire(&qpGuestEndpoints.mutex); - - while ((entry = (QPGuestEndpoint *)QueuePairList_GetHead(&qpGuestEndpoints)) != NULL) { - /* - * Don't make a hypercall for local QueuePairs. - */ - if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL)) { - VMCIQueuePairDetachHypercall(entry->qp.handle); - } - /* - * We cannot fail the exit, so let's reset refCount. - */ - entry->qp.refCount = 0; - QueuePairList_RemoveEntry(&qpGuestEndpoints, &entry->qp); - QPGuestEndpointDestroy(entry); - } - - Atomic_Write(&qpGuestEndpoints.hibernate, 0); - VMCIMutex_Release(&qpGuestEndpoints.mutex); - QueuePairList_Destroy(&qpGuestEndpoints); - VMCI_CleanupLock(&hibernateFailedListLock); - VMCIHandleArray_Destroy(hibernateFailedList); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPGuestEndpoints_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * TRUE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIQPGuestEndpoints_Sync(void) -{ - VMCIMutex_Acquire(&qpGuestEndpoints.mutex); - VMCIMutex_Release(&qpGuestEndpoints.mutex); -} - - -/* - *----------------------------------------------------------------------------- - * - * QPGuestEndpointCreate -- - * - * Allocates and initializes a QPGuestEndpoint structure. - * Allocates a QueuePair rid (and handle) iff the given entry has - * an invalid handle. 0 through VMCI_RESERVED_RESOURCE_ID_MAX - * are reserved handles. Assumes that the QP list mutex is held - * by the caller. - * - * Results: - * Pointer to structure intialized. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -QPGuestEndpoint * -QPGuestEndpointCreate(VMCIHandle handle, // IN - VMCIId peer, // IN - uint32 flags, // IN - uint64 produceSize, // IN - uint64 consumeSize, // IN - void *produceQ, // IN - void *consumeQ) // IN -{ - static VMCIId queuePairRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1; - QPGuestEndpoint *entry; - const uint64 numPPNs = CEILING(produceSize, PAGE_SIZE) + - CEILING(consumeSize, PAGE_SIZE) + - 2; /* One page each for the queue headers. */ - - ASSERT((produceSize || consumeSize) && produceQ && consumeQ); - - if (VMCI_HANDLE_INVALID(handle)) { - VMCIId contextID = vmci_get_context_id(); - VMCIId oldRID = queuePairRID; - - /* - * Generate a unique QueuePair rid. Keep on trying until we wrap around - * in the RID space. - */ - ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX); - do { - handle = VMCI_MAKE_HANDLE(contextID, queuePairRID); - entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints, - handle); - queuePairRID++; - if (UNLIKELY(!queuePairRID)) { - /* - * Skip the reserved rids. - */ - queuePairRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1; - } - } while (entry && queuePairRID != oldRID); - - if (UNLIKELY(entry != NULL)) { - ASSERT(queuePairRID == oldRID); - /* - * We wrapped around --- no rids were free. - */ - return NULL; - } - } - - ASSERT(!VMCI_HANDLE_INVALID(handle) && - QueuePairList_FindEntry(&qpGuestEndpoints, handle) == NULL); - entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NORMAL); - if (entry) { - entry->qp.handle = handle; - entry->qp.peer = peer; - entry->qp.flags = flags; - entry->qp.produceSize = produceSize; - entry->qp.consumeSize = consumeSize; - entry->qp.refCount = 0; - entry->numPPNs = numPPNs; - memset(&entry->ppnSet, 0, sizeof entry->ppnSet); - entry->produceQ = produceQ; - entry->consumeQ = consumeQ; - VMCIList_InitEntry(&entry->qp.listItem); - } - return entry; -} - - -/* - *----------------------------------------------------------------------------- - * - * QPGuestEndpointDestroy -- - * - * Frees a QPGuestEndpoint structure. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -QPGuestEndpointDestroy(QPGuestEndpoint *entry) // IN -{ - ASSERT(entry); - ASSERT(entry->qp.refCount == 0); - - VMCI_FreePPNSet(&entry->ppnSet); - VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ); - VMCI_FreeQueue(entry->produceQ, entry->qp.produceSize); - VMCI_FreeQueue(entry->consumeQ, entry->qp.consumeSize); - VMCI_FreeKernelMem(entry, sizeof *entry); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueuePairAllocHypercall -- - * - * Helper to make a QueuePairAlloc hypercall when the driver is - * supporting a guest device. - * - * Results: - * Result of the hypercall. - * - * Side effects: - * Memory is allocated & freed. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQueuePairAllocHypercall(const QPGuestEndpoint *entry) // IN -{ - VMCIQueuePairAllocMsg *allocMsg; - size_t msgSize; - int result; - - if (!entry || entry->numPPNs <= 2) { - return VMCI_ERROR_INVALID_ARGS; - } - - ASSERT(!(entry->qp.flags & VMCI_QPFLAG_LOCAL)); - - msgSize = sizeof *allocMsg + (size_t)entry->numPPNs * sizeof(PPN); - allocMsg = VMCI_AllocKernelMem(msgSize, VMCI_MEMORY_NONPAGED); - if (!allocMsg) { - return VMCI_ERROR_NO_MEM; - } - - allocMsg->hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_QUEUEPAIR_ALLOC); - allocMsg->hdr.src = VMCI_ANON_SRC_HANDLE; - allocMsg->hdr.payloadSize = msgSize - VMCI_DG_HEADERSIZE; - allocMsg->handle = entry->qp.handle; - allocMsg->peer = entry->qp.peer; - allocMsg->flags = entry->qp.flags; - allocMsg->produceSize = entry->qp.produceSize; - allocMsg->consumeSize = entry->qp.consumeSize; - allocMsg->numPPNs = entry->numPPNs; - result = VMCI_PopulatePPNList((uint8 *)allocMsg + sizeof *allocMsg, &entry->ppnSet); - if (result == VMCI_SUCCESS) { - result = VMCI_SendDatagram((VMCIDatagram *)allocMsg); - } - VMCI_FreeKernelMem(allocMsg, msgSize); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueuePairAllocGuestWork -- - * - * This functions handles the actual allocation of a VMCI queue - * pair guest endpoint. Allocates physical pages for the queue - * pair. It makes OS dependent calls through generic wrappers. - * - * Results: - * Success or failure. - * - * Side effects: - * Memory is allocated. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQueuePairAllocGuestWork(VMCIHandle *handle, // IN/OUT - VMCIQueue **produceQ, // OUT - uint64 produceSize, // IN - VMCIQueue **consumeQ, // OUT - uint64 consumeSize, // IN - VMCIId peer, // IN - uint32 flags, // IN - VMCIPrivilegeFlags privFlags) // IN - -{ - const uint64 numProducePages = CEILING(produceSize, PAGE_SIZE) + 1; - const uint64 numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1; - void *myProduceQ = NULL; - void *myConsumeQ = NULL; - int result; - QPGuestEndpoint *queuePairEntry = NULL; - - /* - * XXX Check for possible overflow of 'size' arguments when passed to - * compat_get_order (after some arithmetic ops). - */ - - ASSERT(handle && produceQ && consumeQ && (produceSize || consumeSize)); - - if (privFlags != VMCI_NO_PRIVILEGE_FLAGS) { - return VMCI_ERROR_NO_ACCESS; - } - - VMCIMutex_Acquire(&qpGuestEndpoints.mutex); - - /* Check if creation/attachment of a queuepair is allowed. */ - if (!VMCI_CanCreate()) { - result = VMCI_ERROR_UNAVAILABLE; - goto error; - } - - if ((Atomic_Read(&qpGuestEndpoints.hibernate) == 1) && - !(flags & VMCI_QPFLAG_LOCAL)) { - /* - * While guest OS is in hibernate state, creating non-local - * queue pairs is not allowed after the point where the VMCI - * guest driver converted the existing queue pairs to local - * ones. - */ - - result = VMCI_ERROR_UNAVAILABLE; - goto error; - } - - if ((queuePairEntry = (QPGuestEndpoint *) - QueuePairList_FindEntry(&qpGuestEndpoints, *handle)) != NULL) { - if (queuePairEntry->qp.flags & VMCI_QPFLAG_LOCAL) { - /* Local attach case. */ - if (queuePairEntry->qp.refCount > 1) { - VMCI_DEBUG_LOG(4, (LGPFX"Error attempting to attach more than " - "once.\n")); - result = VMCI_ERROR_UNAVAILABLE; - goto errorKeepEntry; - } - - if (queuePairEntry->qp.produceSize != consumeSize || - queuePairEntry->qp.consumeSize != produceSize || - queuePairEntry->qp.flags != (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) { - VMCI_DEBUG_LOG(4, (LGPFX"Error mismatched queue pair in local " - "attach.\n")); - result = VMCI_ERROR_QUEUEPAIR_MISMATCH; - goto errorKeepEntry; - } - - /* - * Do a local attach. We swap the consume and produce queues for the - * attacher and deliver an attach event. - */ - result = QueuePairNotifyPeerLocal(TRUE, *handle); - if (result < VMCI_SUCCESS) { - goto errorKeepEntry; - } - myProduceQ = queuePairEntry->consumeQ; - myConsumeQ = queuePairEntry->produceQ; - goto out; - } - result = VMCI_ERROR_ALREADY_EXISTS; - goto errorKeepEntry; - } - - myProduceQ = VMCI_AllocQueue(produceSize, flags); - if (!myProduceQ) { - VMCI_WARNING((LGPFX"Error allocating pages for produce queue.\n")); - result = VMCI_ERROR_NO_MEM; - goto error; - } - - myConsumeQ = VMCI_AllocQueue(consumeSize, flags); - if (!myConsumeQ) { - VMCI_WARNING((LGPFX"Error allocating pages for consume queue.\n")); - result = VMCI_ERROR_NO_MEM; - goto error; - } - - queuePairEntry = QPGuestEndpointCreate(*handle, peer, flags, - produceSize, consumeSize, - myProduceQ, myConsumeQ); - if (!queuePairEntry) { - VMCI_WARNING((LGPFX"Error allocating memory in %s.\n", __FUNCTION__)); - result = VMCI_ERROR_NO_MEM; - goto error; - } - - result = VMCI_AllocPPNSet(myProduceQ, numProducePages, myConsumeQ, - numConsumePages, &queuePairEntry->ppnSet); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"VMCI_AllocPPNSet failed.\n")); - goto error; - } - - /* - * It's only necessary to notify the host if this queue pair will be - * attached to from another context. - */ - if (queuePairEntry->qp.flags & VMCI_QPFLAG_LOCAL) { - /* Local create case. */ - VMCIId contextId = vmci_get_context_id(); - - /* - * Enforce similar checks on local queue pairs as we do for regular ones. - * The handle's context must match the creator or attacher context id - * (here they are both the current context id) and the attach-only flag - * cannot exist during create. We also ensure specified peer is this - * context or an invalid one. - */ - if (queuePairEntry->qp.handle.context != contextId || - (queuePairEntry->qp.peer != VMCI_INVALID_ID && - queuePairEntry->qp.peer != contextId)) { - result = VMCI_ERROR_NO_ACCESS; - goto error; - } - - if (queuePairEntry->qp.flags & VMCI_QPFLAG_ATTACH_ONLY) { - result = VMCI_ERROR_NOT_FOUND; - goto error; - } - } else { - result = VMCIQueuePairAllocHypercall(queuePairEntry); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"VMCIQueuePairAllocHypercall result = %d.\n", - result)); - goto error; - } - } - - VMCI_InitQueueMutex((VMCIQueue *)myProduceQ, (VMCIQueue *)myConsumeQ); - - QueuePairList_AddEntry(&qpGuestEndpoints, &queuePairEntry->qp); - -out: - queuePairEntry->qp.refCount++; - *handle = queuePairEntry->qp.handle; - *produceQ = (VMCIQueue *)myProduceQ; - *consumeQ = (VMCIQueue *)myConsumeQ; - - /* - * We should initialize the queue pair header pages on a local queue pair - * create. For non-local queue pairs, the hypervisor initializes the header - * pages in the create step. - */ - if ((queuePairEntry->qp.flags & VMCI_QPFLAG_LOCAL) && - queuePairEntry->qp.refCount == 1) { - VMCIQueueHeader_Init((*produceQ)->qHeader, *handle); - VMCIQueueHeader_Init((*consumeQ)->qHeader, *handle); - } - - VMCIMutex_Release(&qpGuestEndpoints.mutex); - - return VMCI_SUCCESS; - -error: - VMCIMutex_Release(&qpGuestEndpoints.mutex); - if (queuePairEntry) { - /* The queues will be freed inside the destroy routine. */ - QPGuestEndpointDestroy(queuePairEntry); - } else { - if (myProduceQ) { - VMCI_FreeQueue(myProduceQ, produceSize); - } - if (myConsumeQ) { - VMCI_FreeQueue(myConsumeQ, consumeSize); - } - } - return result; - -errorKeepEntry: - /* This path should only be used when an existing entry was found. */ - ASSERT(queuePairEntry->qp.refCount > 0); - VMCIMutex_Release(&qpGuestEndpoints.mutex); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueuePairDetachHypercall -- - * - * Helper to make a QueuePairDetach hypercall when the driver is - * supporting a guest device. - * - * Results: - * Result of the hypercall. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIQueuePairDetachHypercall(VMCIHandle handle) // IN -{ - VMCIQueuePairDetachMsg detachMsg; - - detachMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_QUEUEPAIR_DETACH); - detachMsg.hdr.src = VMCI_ANON_SRC_HANDLE; - detachMsg.hdr.payloadSize = sizeof handle; - detachMsg.handle = handle; - - return VMCI_SendDatagram((VMCIDatagram *)&detachMsg); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQueuePairDetachGuestWork -- - * - * Helper for VMCI QueuePair detach interface. Frees the physical - * pages for the queue pair. - * - * Results: - * Success or failure. - * - * Side effects: - * Memory may be freed. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIQueuePairDetachGuestWork(VMCIHandle handle) // IN -{ - int result; - QPGuestEndpoint *entry; - uint32 refCount; - - ASSERT(!VMCI_HANDLE_INVALID(handle)); - - VMCIMutex_Acquire(&qpGuestEndpoints.mutex); - - entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints, handle); - if (!entry) { - VMCIMutex_Release(&qpGuestEndpoints.mutex); - return VMCI_ERROR_NOT_FOUND; - } - - ASSERT(entry->qp.refCount >= 1); - - if (entry->qp.flags & VMCI_QPFLAG_LOCAL) { - result = VMCI_SUCCESS; - - if (entry->qp.refCount > 1) { - result = QueuePairNotifyPeerLocal(FALSE, handle); - /* - * We can fail to notify a local queuepair because we can't allocate. - * We still want to release the entry if that happens, so don't bail - * out yet. - */ - } - } else { - result = VMCIQueuePairDetachHypercall(handle); - if (entry->hibernateFailure) { - if (result == VMCI_ERROR_NOT_FOUND) { - /* - * If a queue pair detach failed when entering - * hibernation, the guest driver and the device may - * disagree on its existence when coming out of - * hibernation. The guest driver will regard it as a - * non-local queue pair, but the device state is gone, - * since the device has been powered off. In this case, we - * treat the queue pair as a local queue pair with no - * peer. - */ - - ASSERT(entry->qp.refCount == 1); - result = VMCI_SUCCESS; - } - if (result == VMCI_SUCCESS) { - VMCIQPUnmarkHibernateFailed(entry); - } - } - if (result < VMCI_SUCCESS) { - /* - * We failed to notify a non-local queuepair. That other queuepair - * might still be accessing the shared memory, so don't release the - * entry yet. It will get cleaned up by VMCIQueuePair_Exit() - * if necessary (assuming we are going away, otherwise why did this - * fail?). - */ - - VMCIMutex_Release(&qpGuestEndpoints.mutex); - return result; - } - } - - /* - * If we get here then we either failed to notify a local queuepair, or - * we succeeded in all cases. Release the entry if required. - */ - - entry->qp.refCount--; - if (entry->qp.refCount == 0) { - QueuePairList_RemoveEntry(&qpGuestEndpoints, &entry->qp); - } - - /* If we didn't remove the entry, this could change once we unlock. */ - refCount = entry ? entry->qp.refCount : - 0xffffffff; /* - * Value does not matter, silence the - * compiler. - */ - - VMCIMutex_Release(&qpGuestEndpoints.mutex); - - if (refCount == 0) { - QPGuestEndpointDestroy(entry); - } - return result; -} - - -/* - *---------------------------------------------------------------------------- - * - * QueuePairNotifyPeerLocal -- - * - * Dispatches a queue pair event message directly into the local event - * queue. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -QueuePairNotifyPeerLocal(Bool attach, // IN: attach or detach? - VMCIHandle handle) // IN: queue pair handle -{ - VMCIEventMsg *eMsg; - VMCIEventPayload_QP *ePayload; - /* buf is only 48 bytes. */ - char buf[sizeof *eMsg + sizeof *ePayload]; - VMCIId contextId = vmci_get_context_id(); - - eMsg = (VMCIEventMsg *)buf; - ePayload = VMCIEventMsgPayload(eMsg); - - eMsg->hdr.dst = VMCI_MAKE_HANDLE(contextId, VMCI_EVENT_HANDLER); - eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, - VMCI_CONTEXT_RESOURCE_ID); - eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *ePayload - sizeof eMsg->hdr; - eMsg->eventData.event = attach ? VMCI_EVENT_QP_PEER_ATTACH : - VMCI_EVENT_QP_PEER_DETACH; - ePayload->peerId = contextId; - ePayload->handle = handle; - - return VMCIEvent_Dispatch((VMCIDatagram *)eMsg); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPMarkHibernateFailed -- - * - * Helper function that marks a queue pair entry as not being - * converted to a local version during hibernation. Must be - * called with the queue pair list mutex held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry) // IN -{ - VMCILockFlags flags; - VMCIHandle handle; - - /* - * entry->handle is located in paged memory, so it can't be - * accessed while holding a spinlock. - */ - - handle = entry->qp.handle; - entry->hibernateFailure = TRUE; - VMCI_GrabLock_BH(&hibernateFailedListLock, &flags); - VMCIHandleArray_AppendEntry(&hibernateFailedList, handle); - VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIQPUnmarkHibernateFailed -- - * - * Helper function that removes a queue pair entry from the group - * of handles marked as having failed hibernation. Must be called - * with the queue pair list lock held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIQPUnmarkHibernateFailed(QPGuestEndpoint *entry) // IN -{ - VMCILockFlags flags; - VMCIHandle handle; - - /* - * entry->handle is located in paged memory, so it can't be - * accessed while holding a spinlock. - */ - - handle = entry->qp.handle; - entry->hibernateFailure = FALSE; - VMCI_GrabLock_BH(&hibernateFailedListLock, &flags); - VMCIHandleArray_RemoveEntry(hibernateFailedList, handle); - VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags); -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCIQPGuestEndpoints_Convert -- - * - * Guest queue pair endpoints may be converted to local ones in - * two cases: when entering hibernation or when the device is - * powered off before entering a sleep mode. Below we first - * discuss the case of hibernation and then the case of entering - * sleep state. - * - * When the guest enters hibernation, any non-local queue pairs - * will disconnect no later than at the time the VMCI device - * powers off. To preserve the content of the non-local queue - * pairs for this guest, we make a local copy of the content and - * disconnect from the queue pairs. This will ensure that the - * peer doesn't continue to update the queue pair state while the - * guest OS is checkpointing the memory (otherwise we might end - * up with a inconsistent snapshot where the pointers of the - * consume queue are checkpointed later than the data pages they - * point to, possibly indicating that non-valid data is - * valid). While we are in hibernation mode, we block the - * allocation of new non-local queue pairs. Note that while we - * are doing the conversion to local queue pairs, we are holding - * the queue pair list lock, which will prevent concurrent - * creation of additional non-local queue pairs. - * - * The hibernation cannot fail, so if we are unable to either - * save the queue pair state or detach from a queue pair, we deal - * with it by keeping the queue pair around, and converting it to - * a local queue pair when going out of hibernation. Since - * failing a detach is highly unlikely (it would require a queue - * pair being actively used as part of a DMA operation), this is - * an acceptable fall back. Once we come back from hibernation, - * these queue pairs will no longer be external, so we simply - * mark them as local at that point. - * - * For the sleep state, the VMCI device will also be put into the - * D3 power state, which may make the device inaccessible to the - * guest driver (Windows unmaps the I/O space). When entering - * sleep state, the hypervisor is likely to suspend the guest as - * well, which will again convert all queue pairs to local ones. - * However, VMCI device clients, e.g., VMCI Sockets, may attempt - * to use queue pairs after the device has been put into the D3 - * power state, so we convert the queue pairs to local ones in - * that case as well. When exiting the sleep states, the device - * has not been reset, so all device state is still in sync with - * the device driver, so no further processing is necessary at - * that point. - * - * Results: - * None. - * - * Side effects: - * Queue pairs are detached. - * - *---------------------------------------------------------------------------- - */ - -void -VMCIQPGuestEndpoints_Convert(Bool toLocal, // IN - Bool deviceReset) // IN -{ - if (toLocal) { - VMCIListItem *next; - - VMCIMutex_Acquire(&qpGuestEndpoints.mutex); - - VMCIList_Scan(next, &qpGuestEndpoints.head) { - QPGuestEndpoint *entry = (QPGuestEndpoint *)VMCIList_Entry( - next, - QueuePairEntry, - listItem); - - if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL)) { - UNUSED_PARAM(VMCIQueue *prodQ); // Only used on Win32 - UNUSED_PARAM(VMCIQueue *consQ); // Only used on Win32 - void *oldProdQ; - UNUSED_PARAM(void *oldConsQ); // Only used on Win32 - int result; - - prodQ = (VMCIQueue *)entry->produceQ; - consQ = (VMCIQueue *)entry->consumeQ; - oldConsQ = oldProdQ = NULL; - - VMCI_AcquireQueueMutex(prodQ, TRUE); - - result = VMCI_ConvertToLocalQueue(consQ, prodQ, - entry->qp.consumeSize, - TRUE, &oldConsQ); - if (result != VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Hibernate failed to create local consume " - "queue from handle %x:%x (error: %d)\n", - entry->qp.handle.context, entry->qp.handle.resource, - result)); - VMCI_ReleaseQueueMutex(prodQ); - VMCIQPMarkHibernateFailed(entry); - continue; - } - result = VMCI_ConvertToLocalQueue(prodQ, consQ, - entry->qp.produceSize, - FALSE, &oldProdQ); - if (result != VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Hibernate failed to create local produce " - "queue from handle %x:%x (error: %d)\n", - entry->qp.handle.context, entry->qp.handle.resource, - result)); - VMCI_RevertToNonLocalQueue(consQ, oldConsQ, - entry->qp.consumeSize); - VMCI_ReleaseQueueMutex(prodQ); - VMCIQPMarkHibernateFailed(entry); - continue; - } - - /* - * Now that the contents of the queue pair has been saved, - * we can detach from the non-local queue pair. This will - * discard the content of the non-local queues. - */ - - result = VMCIQueuePairDetachHypercall(entry->qp.handle); - if (result < VMCI_SUCCESS) { - VMCI_WARNING((LGPFX"Hibernate failed to detach from handle " - "%x:%x\n", - entry->qp.handle.context, - entry->qp.handle.resource)); - VMCI_RevertToNonLocalQueue(consQ, oldConsQ, - entry->qp.consumeSize); - VMCI_RevertToNonLocalQueue(prodQ, oldProdQ, - entry->qp.produceSize); - VMCI_ReleaseQueueMutex(prodQ); - VMCIQPMarkHibernateFailed(entry); - continue; - } - - entry->qp.flags |= VMCI_QPFLAG_LOCAL; - - VMCI_ReleaseQueueMutex(prodQ); - - VMCI_FreeQueueBuffer(oldProdQ, entry->qp.produceSize); - VMCI_FreeQueueBuffer(oldConsQ, entry->qp.consumeSize); - - QueuePairNotifyPeerLocal(FALSE, entry->qp.handle); - } - } - Atomic_Write(&qpGuestEndpoints.hibernate, 1); - - VMCIMutex_Release(&qpGuestEndpoints.mutex); - } else { - VMCILockFlags flags; - VMCIHandle handle; - - /* - * When a guest enters hibernation, there may be queue pairs - * around, that couldn't be converted to local queue - * pairs. When coming out of hibernation, these queue pairs - * will be restored as part of the guest main mem by the OS - * hibernation code and they can now be regarded as local - * versions. Since they are no longer connected, detach - * notifications are sent to the local endpoint. - */ - - VMCI_GrabLock_BH(&hibernateFailedListLock, &flags); - while (VMCIHandleArray_GetSize(hibernateFailedList) > 0) { - handle = VMCIHandleArray_RemoveTail(hibernateFailedList); - if (deviceReset) { - QueuePairNotifyPeerLocal(FALSE, handle); - } - } - VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags); - - Atomic_Write(&qpGuestEndpoints.hibernate, 0); - } -} - -#endif /* !VMKERNEL */ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.h b/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.h deleted file mode 100644 index 90be2b7ce..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciQueuePair.h +++ /dev/null @@ -1,106 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciQueuePair.h -- - * - * VMCI QueuePair API implementation in the host driver. - */ - -#ifndef _VMCI_QUEUE_PAIR_H_ -#define _VMCI_QUEUE_PAIR_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" -#include "vmci_iocontrols.h" -#include "vmci_kernel_if.h" -#include "vmciContext.h" -#include "vmciQueue.h" - -/* - * QueuePairPageStore describes how the memory of a given queue pair - * is backed. When the queue pair is between the host and a guest, the - * page store consists of references to the guest pages. On vmkernel, - * this is a list of PPNs, and on hosted, it is a user VA where the - * queue pair is mapped into the VMX address space. - */ - -typedef struct QueuePairPageStore { - VMCIQPGuestMem pages; // Reference to pages backing the queue pair. - uint32 len; // Length of pageList/virtual addres range (in pages). -} QueuePairPageStore; - - -/* - *------------------------------------------------------------------------------ - * - * VMCI_QP_PAGESTORE_IS_WELLFORMED -- - * - * Utility function that checks whether the fields of the page - * store contain valid values. - * - * Result: - * TRUE if the page store is wellformed. FALSE otherwise. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -static INLINE Bool -VMCI_QP_PAGESTORE_IS_WELLFORMED(QueuePairPageStore *pageStore) // IN -{ - return pageStore->len >= 2; -} - -int VMCIQPBroker_Init(void); -void VMCIQPBroker_Exit(void); -int VMCIQPBroker_Alloc(VMCIHandle handle, VMCIId peer, uint32 flags, - VMCIPrivilegeFlags privFlags, - uint64 produceSize, uint64 consumeSize, - QueuePairPageStore *pageStore, - VMCIContext *context); -int VMCIQPBroker_SetPageStore(VMCIHandle handle, VA64 produceUVA, VA64 consumeUVA, - VMCIContext *context); -int VMCIQPBroker_Detach(VMCIHandle handle, VMCIContext *context); - -int VMCIQPGuestEndpoints_Init(void); -void VMCIQPGuestEndpoints_Exit(void); -void VMCIQPGuestEndpoints_Sync(void); -void VMCIQPGuestEndpoints_Convert(Bool toLocal, Bool deviceReset); - -int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ, - uint64 produceSize, VMCIQueue **consumeQ, - uint64 consumeSize, VMCIId peer, uint32 flags, - VMCIPrivilegeFlags privFlags, Bool guestEndpoint, - VMCIEventReleaseCB wakeupCB, void *clientData); -int VMCIQueuePair_Detach(VMCIHandle handle, Bool guestEndpoint); -int VMCIQPBroker_Map(VMCIHandle handle, VMCIContext *context, VMCIQPGuestMem guestMem); -int VMCIQPBroker_Unmap(VMCIHandle handle, VMCIContext *context, VMCIGuestMemID gid); -#ifdef VMKERNEL -int VMCIQPBroker_Revalidate(VMCIHandle handle, VMCIContext *context); -#endif - -#endif /* !_VMCI_QUEUE_PAIR_H_ */ - diff --git a/open-vm-tools/modules/linux/vmci/common/vmciResource.c b/open-vm-tools/modules/linux/vmci/common/vmciResource.c deleted file mode 100644 index 720924bc5..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciResource.c +++ /dev/null @@ -1,424 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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 - * - *********************************************************/ - -/* - * vmciResource.c -- - * - * Implementation of the VMCI Resource Access Control API. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciHashtable.h" -#include "vmciResource.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -# include "vmciDriver.h" -#else -# include "vmciDriver.h" -#endif - -#define LGPFX "VMCIResource: " - -/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */ -static uint32 resourceID = VMCI_RESERVED_RESOURCE_ID_MAX + 1; -static VMCILock resourceIdLock; - -static void VMCIResourceDoRemove(VMCIResource *resource); - -static VMCIHashTable *resourceTable = NULL; - - -/* Public Resource Access Control API. */ - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Init -- - * - * Initializes the VMCI Resource Access Control API. Creates a hashtable - * to hold all resources, and registers vectors and callbacks for - * hypercalls. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIResource_Init(void) -{ - int err = VMCI_InitLock(&resourceIdLock, "VMCIRIDLock", - VMCI_LOCK_RANK_RESOURCE); - if (err < VMCI_SUCCESS) { - return err; - } - - resourceTable = VMCIHashTable_Create(128); - if (resourceTable == NULL) { - VMCI_WARNING((LGPFX"Failed creating a resource hash table for VMCI.\n")); - VMCI_CleanupLock(&resourceIdLock); - return VMCI_ERROR_NO_MEM; - } - - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Exit -- - * - * Cleans up resources. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIResource_Exit(void) -{ - /* Cleanup resources.*/ - VMCI_CleanupLock(&resourceIdLock); - - if (resourceTable) { - VMCIHashTable_Destroy(resourceTable); - } -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_GetID -- - * - * Return resource ID. The first VMCI_RESERVED_RESOURCE_ID_MAX are - * reserved so we start from its value + 1. - * - * Result: - * VMCI resource id on success, VMCI_INVALID_ID on failure. - * - * Side effects: - * None. - * - * - *------------------------------------------------------------------------------ - */ - -VMCIId -VMCIResource_GetID(VMCIId contextID) -{ - VMCIId oldRID = resourceID; - VMCIId currentRID; - Bool foundRID = FALSE; - - /* - * Generate a unique resource ID. Keep on trying until we wrap around - * in the RID space. - */ - ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX); - - do { - VMCILockFlags flags; - VMCIHandle handle; - - VMCI_GrabLock(&resourceIdLock, &flags); - currentRID = resourceID; - handle = VMCI_MAKE_HANDLE(contextID, currentRID); - resourceID++; - if (UNLIKELY(resourceID == VMCI_INVALID_ID)) { - /* - * Skip the reserved rids. - */ - - resourceID = VMCI_RESERVED_RESOURCE_ID_MAX + 1; - } - VMCI_ReleaseLock(&resourceIdLock, flags); - foundRID = !VMCIHashTable_EntryExists(resourceTable, handle); - } while (!foundRID && resourceID != oldRID); - - if (UNLIKELY(!foundRID)) { - return VMCI_INVALID_ID; - } else { - return currentRID; - } -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Add -- - * - * Results: - * VMCI_SUCCESS if successful, error code if not. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIResource_Add(VMCIResource *resource, // IN - VMCIResourceType resourceType, // IN - VMCIHandle resourceHandle, // IN - VMCIResourceFreeCB containerFreeCB, // IN - void *containerObject) // IN -{ - int result; - - ASSERT(resource); - - if (VMCI_HANDLE_EQUAL(resourceHandle, VMCI_INVALID_HANDLE)) { - VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument resource (handle=0x%x:0x%x).\n", - resourceHandle.context, resourceHandle.resource)); - return VMCI_ERROR_INVALID_ARGS; - } - - VMCIHashTable_InitEntry(&resource->hashEntry, resourceHandle); - resource->type = resourceType; - resource->containerFreeCB = containerFreeCB; - resource->containerObject = containerObject; - - /* Add resource to hashtable. */ - result = VMCIHashTable_AddEntry(resourceTable, &resource->hashEntry); - if (result != VMCI_SUCCESS) { - VMCI_DEBUG_LOG(4, (LGPFX"Failed to add entry to hash table " - "(result=%d).\n", result)); - return result; - } - - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Remove -- - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIResource_Remove(VMCIHandle resourceHandle, // IN: - VMCIResourceType resourceType) // IN: -{ - VMCIResource *resource = VMCIResource_Get(resourceHandle, resourceType); - if (resource == NULL) { - return; - } - - /* Remove resource from hashtable. */ - VMCIHashTable_RemoveEntry(resourceTable, &resource->hashEntry); - - VMCIResource_Release(resource); - /* resource could be freed by now. */ -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Get -- - * - * Results: - * Resource is successful. Otherwise NULL. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCIResource * -VMCIResource_Get(VMCIHandle resourceHandle, // IN - VMCIResourceType resourceType) // IN -{ - VMCIResource *resource; - VMCIHashEntry *entry = VMCIHashTable_GetEntry(resourceTable, resourceHandle); - if (entry == NULL) { - return NULL; - } - resource = RESOURCE_CONTAINER(entry, VMCIResource, hashEntry); - if (resourceType == VMCI_RESOURCE_TYPE_ANY || - resource->type == resourceType) { - return resource; - } - VMCIHashTable_ReleaseEntry(resourceTable, entry); - return NULL; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Hold -- - * - * Hold the given resource. This will hold the hashtable entry. This - * is like doing a Get() but without having to lookup the resource by - * handle. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIResource_Hold(VMCIResource *resource) -{ - ASSERT(resource); - VMCIHashTable_HoldEntry(resourceTable, &resource->hashEntry); -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResourceDoRemove -- - * - * Deallocates data structures associated with the given resource - * and invoke any call back registered for the resource. - * - * Results: - * None. - * - * Side effects: - * May deallocate memory and invoke a callback for the removed resource. - * - *------------------------------------------------------------------------------ - */ - -static void INLINE -VMCIResourceDoRemove(VMCIResource *resource) -{ - ASSERT(resource); - - if (resource->containerFreeCB) { - resource->containerFreeCB(resource->containerObject); - /* Resource has been freed don't dereference it. */ - } -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Release -- - * - * Results: - * None. - * - * Side effects: - * resource's containerFreeCB will get called if last reference. - * - *------------------------------------------------------------------------------ - */ - -int -VMCIResource_Release(VMCIResource *resource) -{ - int result; - - ASSERT(resource); - - result = VMCIHashTable_ReleaseEntry(resourceTable, &resource->hashEntry); - if (result == VMCI_SUCCESS_ENTRY_DEAD) { - VMCIResourceDoRemove(resource); - } - - /* - * We propagate the information back to caller in case it wants to know - * whether entry was freed. - */ - return result; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Handle -- - * - * Get the handle for the given resource. - * - * Results: - * The resource's associated handle. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -VMCIHandle -VMCIResource_Handle(VMCIResource *resource) -{ - ASSERT(resource); - return resource->hashEntry.handle; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCIResource_Sync -- - * - * Use this as a synchronization point when setting globals, for example, - * during device shutdown. - * - * Results: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -void -VMCIResource_Sync(void) -{ - VMCIHashTable_Sync(resourceTable); -} diff --git a/open-vm-tools/modules/linux/vmci/common/vmciResource.h b/open-vm-tools/modules/linux/vmci/common/vmciResource.h deleted file mode 100644 index 506629bc9..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciResource.h +++ /dev/null @@ -1,79 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2013 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 - * - *********************************************************/ - -/* - * vmciResource.h -- - * - * VMCI Resource Access Control API. - */ - -#ifndef _VMCI_RESOURCE_H_ -#define _VMCI_RESOURCE_H_ - -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" -#include "vmci_kernel_if.h" -#include "vmciHashtable.h" -#include "vmciContext.h" - -#define RESOURCE_CONTAINER(ptr, type, member) \ - ((type *)((char *)(ptr) - offsetof(type, member))) - -typedef void(*VMCIResourceFreeCB)(void *resource); - -typedef enum { - VMCI_RESOURCE_TYPE_ANY, - VMCI_RESOURCE_TYPE_API, - VMCI_RESOURCE_TYPE_GROUP, - VMCI_RESOURCE_TYPE_DATAGRAM, - VMCI_RESOURCE_TYPE_DOORBELL, -} VMCIResourceType; - -typedef struct VMCIResource { - VMCIHashEntry hashEntry; - VMCIResourceType type; - VMCIResourceFreeCB containerFreeCB; // Callback to free container - // object when refCount is 0. - void *containerObject; // Container object reference. -} VMCIResource; - - -int VMCIResource_Init(void); -void VMCIResource_Exit(void); -void VMCIResource_Sync(void); - -VMCIId VMCIResource_GetID(VMCIId contextID); - -int VMCIResource_Add(VMCIResource *resource, VMCIResourceType resourceType, - VMCIHandle resourceHandle, - VMCIResourceFreeCB containerFreeCB, void *containerObject); -void VMCIResource_Remove(VMCIHandle resourceHandle, - VMCIResourceType resourceType); -VMCIResource *VMCIResource_Get(VMCIHandle resourceHandle, - VMCIResourceType resourceType); -void VMCIResource_Hold(VMCIResource *resource); -int VMCIResource_Release(VMCIResource *resource); -VMCIHandle VMCIResource_Handle(VMCIResource *resource); - - -#endif // _VMCI_RESOURCE_H_ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciRoute.c b/open-vm-tools/modules/linux/vmci/common/vmciRoute.c deleted file mode 100644 index cc98b93c5..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciRoute.c +++ /dev/null @@ -1,290 +0,0 @@ -/********************************************************* - * Copyright (C) 2011-2012,2014 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 - * - *********************************************************/ - -/* - * vmciRoute.c -- - * - * Implementation of VMCI routing rules. - */ - -#include "vmci_kernel_if.h" -#include "vm_assert.h" -#include "vmci_defs.h" -#include "vmci_infrastructure.h" -#include "vmciCommonInt.h" -#include "vmciContext.h" -#include "vmciDriver.h" -#include "vmciKernelAPI.h" -#include "vmciRoute.h" -#if defined(VMKERNEL) -# include "vmciVmkInt.h" -# include "vm_libc.h" -# include "helper_ext.h" -#endif - -#define LGPFX "VMCIRoute: " - - -/* - *------------------------------------------------------------------------------ - * - * VMCI_Route -- - * - * Make a routing decision for the given source and destination handles. - * This will try to determine the route using the handles and the available - * devices. - * - * Result: - * A VMCIRoute value. - * - * Side effects: - * Sets the source context if it is invalid. - * - *------------------------------------------------------------------------------ - */ - -int -VMCI_Route(VMCIHandle *src, // IN/OUT - const VMCIHandle *dst, // IN - Bool fromGuest, // IN - VMCIRoute *route) // OUT -{ - Bool hasHostDevice; - Bool hasGuestDevice; - - ASSERT(src); - ASSERT(dst); - ASSERT(route); - - *route = VMCI_ROUTE_NONE; - - /* - * "fromGuest" is only ever set to TRUE by IOCTL_VMCI_DATAGRAM_SEND (or by - * the vmkernel equivalent), which comes from the VMX, so we know it is - * coming from a guest. - */ - - /* - * To avoid inconsistencies, test these once. We will test them again - * when we do the actual send to ensure that we do not touch a non-existent - * device. - */ - - hasHostDevice = VMCI_HostPersonalityActive(); - hasGuestDevice = VMCI_GuestPersonalityActive(); - - /* Must have a valid destination context. */ - if (VMCI_INVALID_ID == dst->context) { - return VMCI_ERROR_INVALID_ARGS; - } - - /* Anywhere to hypervisor. */ - if (VMCI_HYPERVISOR_CONTEXT_ID == dst->context) { - /* - * If this message already came from a guest then we cannot send it - * to the hypervisor. It must come from a local client. - */ - - if (fromGuest) { - return VMCI_ERROR_DST_UNREACHABLE; - } - - /* We must be acting as a guest in order to send to the hypervisor. */ - if (!hasGuestDevice) { - return VMCI_ERROR_DEVICE_NOT_FOUND; - } - - /* And we cannot send if the source is the host context. */ - if (VMCI_HOST_CONTEXT_ID == src->context) { - return VMCI_ERROR_INVALID_ARGS; - } - - /* Send from local client down to the hypervisor. */ - *route = VMCI_ROUTE_AS_GUEST; - return VMCI_SUCCESS; - } - - /* Anywhere to local client on host. */ - if (VMCI_HOST_CONTEXT_ID == dst->context) { - /* - * If it is not from a guest but we are acting as a guest, then we need - * to send it down to the host. Note that if we are also acting as a - * host then this will prevent us from sending from local client to - * local client, but we accept that restriction as a way to remove - * any ambiguity from the host context. - */ - - if (src->context == VMCI_HYPERVISOR_CONTEXT_ID) { - /* - * If the hypervisor is the source, this is host local - * communication. The hypervisor may send vmci event - * datagrams to the host itself, but it will never send - * datagrams to an "outer host" through the guest device. - */ - - if (hasHostDevice) { - *route = VMCI_ROUTE_AS_HOST; - return VMCI_SUCCESS; - } else { - return VMCI_ERROR_DEVICE_NOT_FOUND; - } - } - - if (!fromGuest && hasGuestDevice) { - /* If no source context then use the current. */ - if (VMCI_INVALID_ID == src->context) { - src->context = vmci_get_context_id(); - } - - /* Send it from local client down to the host. */ - *route = VMCI_ROUTE_AS_GUEST; - return VMCI_SUCCESS; - } - - /* - * Otherwise we already received it from a guest and it is destined - * for a local client on this host, or it is from another local client - * on this host. We must be acting as a host to service it. - */ - - if (!hasHostDevice) { - return VMCI_ERROR_DEVICE_NOT_FOUND; - } - - if (VMCI_INVALID_ID == src->context) { - /* - * If it came from a guest then it must have a valid context. - * Otherwise we can use the host context. - */ - - if (fromGuest) { - return VMCI_ERROR_INVALID_ARGS; - } - src->context = VMCI_HOST_CONTEXT_ID; - } - - /* Route to local client. */ - *route = VMCI_ROUTE_AS_HOST; - return VMCI_SUCCESS; - } - - /* If we are acting as a host then this might be destined for a guest. */ - if (hasHostDevice) { - /* It will have a context if it is meant for a guest. */ - if (VMCIContext_Exists(dst->context)) { - if (VMCI_INVALID_ID == src->context) { - /* - * If it came from a guest then it must have a valid context. - * Otherwise we can use the host context. - */ - - if (fromGuest) { - return VMCI_ERROR_INVALID_ARGS; - } - src->context = VMCI_HOST_CONTEXT_ID; - } else if (VMCI_CONTEXT_IS_VM(src->context) && - src->context != dst->context) { - /* - * VM to VM communication is not allowed. Since we catch - * all communication destined for the host above, this - * must be destined for a VM since there is a valid - * context. - */ - - ASSERT(VMCI_CONTEXT_IS_VM(dst->context)); - - return VMCI_ERROR_DST_UNREACHABLE; - } - - /* 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; - } - } - - /* - * We must be a guest trying to send to another guest, which means - * we need to send it down to the host. We do not filter out VM to - * VM communication here, since we want to be able to use the guest - * driver on older versions that do support VM to VM communication. - */ - - 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; - } - - /* If no source context then use the current context. */ - if (VMCI_INVALID_ID == src->context) { - src->context = vmci_get_context_id(); - } - - /* - * Send it from local client down to the host, which will route it to - * the other guest for us. - */ - - *route = VMCI_ROUTE_AS_GUEST; - return VMCI_SUCCESS; -} - - -/* - *------------------------------------------------------------------------------ - * - * VMCI_RouteString -- - * - * Get a string for the given route. - * - * Result: - * A string representing the route, if the route is valid, otherwise an - * empty string. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ - -const char * -VMCI_RouteString(VMCIRoute route) // IN -{ - const char *vmciRouteStrings[] = { - "none", - "as host", - "as guest", - }; - if (route >= VMCI_ROUTE_NONE && route <= VMCI_ROUTE_AS_GUEST) { - return vmciRouteStrings[route]; - } - return ""; -} diff --git a/open-vm-tools/modules/linux/vmci/common/vmciRoute.h b/open-vm-tools/modules/linux/vmci/common/vmciRoute.h deleted file mode 100644 index e10388c4b..000000000 --- a/open-vm-tools/modules/linux/vmci/common/vmciRoute.h +++ /dev/null @@ -1,49 +0,0 @@ -/********************************************************* - * Copyright (C) 2011-2013 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 - * - *********************************************************/ - -/* - * vmciRoute.h -- - * - * VMCI Routing. - */ - -#ifndef _VMCI_ROUTE_H_ -#define _VMCI_ROUTE_H_ - -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_defs.h" - - -typedef enum { - VMCI_ROUTE_NONE, - VMCI_ROUTE_AS_HOST, - VMCI_ROUTE_AS_GUEST, -} VMCIRoute; - - -int VMCI_Route(VMCIHandle *src, const VMCIHandle *dst, Bool fromGuest, - VMCIRoute *route); -const char *VMCI_RouteString(VMCIRoute route); - - -#endif // _VMCI_ROUTE_H_ diff --git a/open-vm-tools/modules/linux/vmci/linux/driver.c b/open-vm-tools/modules/linux/vmci/linux/driver.c deleted file mode 100644 index d656bf000..000000000 --- a/open-vm-tools/modules/linux/vmci/linux/driver.c +++ /dev/null @@ -1,2535 +0,0 @@ -/********************************************************* - * Copyright (C) 2011-2014,2017 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 - * - *********************************************************/ - -/* Must come before any kernel header file */ -#include "driver-config.h" - -#define EXPORT_SYMTAB - -#include -#include - -#include -#include -#include -#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) -# include -/* Use weak: not all kernels export sys_ioctl for use by modules */ -asmlinkage __attribute__((weak)) long -sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -#endif -#include -#include -#include -#include - -#include "compat_highmem.h" -#include "compat_interrupt.h" -#include "compat_ioport.h" -#include "compat_kernel.h" -#include "compat_mm.h" -#include "compat_module.h" -#include "compat_mutex.h" -#include "compat_page.h" -#include "compat_pci.h" -#include "compat_sched.h" -#include "compat_slab.h" -#include "compat_uaccess.h" -#include "compat_version.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) -# error "Linux kernels before 2.6.9 are not supported." -#endif - -#include "vm_basic_types.h" -#include "vm_device_version.h" - -#include "vmware.h" -#include "driverLog.h" -#include "pgtbl.h" -#include "vmci_defs.h" -#include "vmci_handle_array.h" -#include "vmci_infrastructure.h" -#include "vmci_iocontrols.h" -#include "vmci_version.h" -#include "vmci_kernel_if.h" -#include "vmciCommonInt.h" -#include "vmciContext.h" -#include "vmciDatagram.h" -#include "vmciDoorbell.h" -#include "vmciDriver.h" -#include "vmciEvent.h" -#include "vmciKernelAPI.h" -#include "vmciQueuePair.h" -#include "vmciResource.h" - -#define LGPFX "VMCI: " - -#define VMCI_DEVICE_NAME "vmci" -#define VMCI_MODULE_NAME "vmci" - - -/* - *---------------------------------------------------------------------- - * - * PCI Device interface -- - * - * Declarations of types and functions related to the VMCI PCI - * device personality. - * - * - *---------------------------------------------------------------------- - */ - -/* - * VMCI PCI driver state - */ - -typedef struct vmci_device { - compat_mutex_t lock; - - unsigned int ioaddr; - unsigned int ioaddr_size; - unsigned int irq; - unsigned int intr_type; - Bool exclusive_vectors; - struct msix_entry msix_entries[VMCI_MAX_INTRS]; - - Bool enabled; - spinlock_t dev_spinlock; - atomic_t datagrams_allowed; -} vmci_device; - -static const struct pci_device_id vmci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), }, - { 0 }, -}; - -static int vmci_probe_device(struct pci_dev *pdev, - const struct pci_device_id *id); -static void vmci_remove_device(struct pci_dev* pdev); - -static struct pci_driver vmci_driver = { - .name = VMCI_DEVICE_NAME, - .id_table = vmci_ids, - .probe = vmci_probe_device, - .remove = vmci_remove_device, -}; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id, - struct pt_regs * regs); -static compat_irqreturn_t vmci_interrupt_bm(int irq, void *dev_id, - struct pt_regs * regs); -#else -static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id); -static compat_irqreturn_t vmci_interrupt_bm(int irq, void *dev_id); -#endif -static void dispatch_datagrams(unsigned long data); -static void process_bitmap(unsigned long data); - -/* MSI-X has performance problems in < 2.6.19 */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -# define VMCI_DISABLE_MSIX 0 -#else -# define VMCI_DISABLE_MSIX 1 -#endif - -/* - * Needed by other components of this module. It's okay to have one global - * instance of this because there can only ever be one VMCI device. Our - * virtual hardware enforces this. - */ - -struct pci_dev *vmci_pdev; - -static vmci_device vmci_dev; -static compat_mod_param_bool vmci_disable_host = 0; -static compat_mod_param_bool vmci_disable_guest = 0; -static compat_mod_param_bool vmci_disable_msi; -static compat_mod_param_bool vmci_disable_msix = VMCI_DISABLE_MSIX; - -DECLARE_TASKLET(vmci_dg_tasklet, dispatch_datagrams, - (unsigned long)&vmci_dev); - -DECLARE_TASKLET(vmci_bm_tasklet, process_bitmap, - (unsigned long)&vmci_dev); - -/* - * Allocate a buffer for incoming datagrams globally to avoid repeated - * allocation in the interrupt handler's atomic context. - */ - -static uint8 *data_buffer = NULL; -static uint32 data_buffer_size = VMCI_MAX_DG_SIZE; - -/* - * If the VMCI hardware supports the notification bitmap, we allocate - * and register a page with the device. - */ - -static uint8 *notification_bitmap; -static dma_addr_t notification_base; - - -/* - *---------------------------------------------------------------------- - * - * Host device node interface -- - * - * Implements VMCI by implementing open/close/ioctl functions - * - * - *---------------------------------------------------------------------- - */ - -/* - * Per-instance host state - */ - -typedef struct VMCILinux { - VMCIContext *context; - int userVersion; - VMCIObjType ctType; -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) - compat_mutex_t lock; -#endif -} VMCILinux; - -/* - * Static driver state. - */ - -#define VM_DEVICE_NAME_SIZE 32 -#define LINUXLOG_BUFFER_SIZE 1024 - -typedef struct VMCILinuxState { - struct miscdevice misc; - char buf[LINUXLOG_BUFFER_SIZE]; - atomic_t activeContexts; -} VMCILinuxState; - -static int VMCISetupNotify(VMCIContext *context, VA notifyUVA); -static void VMCIUnsetNotifyInt(VMCIContext *context, Bool useLock); - -static int LinuxDriver_Open(struct inode *inode, struct file *filp); - -static int LinuxDriver_Ioctl(struct inode *inode, struct file *filp, - u_int iocmd, unsigned long ioarg); - -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) -static long LinuxDriver_UnlockedIoctl(struct file *filp, - u_int iocmd, unsigned long ioarg); -#endif - -static int LinuxDriver_Close(struct inode *inode, struct file *filp); -static unsigned int LinuxDriverPoll(struct file *file, poll_table *wait); - - -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) -#define LinuxDriverLockIoctlPerFD(mutex) compat_mutex_lock(mutex) -#define LinuxDriverUnlockIoctlPerFD(mutex) compat_mutex_unlock(mutex) -#else -#define LinuxDriverLockIoctlPerFD(mutex) do {} while (0) -#define LinuxDriverUnlockIoctlPerFD(mutex) do {} while (0) -#endif - -/* should be const if not for older kernels support */ -static struct file_operations vmuser_fops = { - .owner = THIS_MODULE, - .open = LinuxDriver_Open, - .release = LinuxDriver_Close, - .poll = LinuxDriverPoll, -#ifdef HAVE_UNLOCKED_IOCTL - .unlocked_ioctl = LinuxDriver_UnlockedIoctl, -#else - .ioctl = LinuxDriver_Ioctl, -#endif -#ifdef HAVE_COMPAT_IOCTL - .compat_ioctl = LinuxDriver_UnlockedIoctl, -#endif -}; - -static struct VMCILinuxState linuxState = { - .misc = { - .name = VMCI_DEVICE_NAME, - .minor = MISC_DYNAMIC_MINOR, - .fops = &vmuser_fops, - }, - .activeContexts = ATOMIC_INIT(0), -}; - - -/* - *---------------------------------------------------------------------- - * - * Shared VMCI device definitions -- - * - * Types and variables shared by both host and guest personality - * - * - *---------------------------------------------------------------------- - */ - -static Bool guestDeviceInit; -static atomic_t guestDeviceActive; -static Bool hostDeviceInit; - -/* - *----------------------------------------------------------------------------- - * - * Host device support -- - * - * The following functions implement the support for the VMCI - * host driver. - * - * - *----------------------------------------------------------------------------- - */ - - -#ifdef VM_X86_64 -#ifndef HAVE_COMPAT_IOCTL -static int -LinuxDriver_Ioctl32_Handler(unsigned int fd, unsigned int iocmd, - unsigned long ioarg, struct file * filp) -{ - int ret; - ret = -ENOTTY; - if (filp && filp->f_op && filp->f_op->ioctl == LinuxDriver_Ioctl) { - ret = LinuxDriver_Ioctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); - } - return ret; -} -#endif /* !HAVE_COMPAT_IOCTL */ - -static int -register_ioctl32_handlers(void) -{ -#ifndef HAVE_COMPAT_IOCTL - { - int i; - - for (i = IOCTL_VMCI_FIRST; i < IOCTL_VMCI_LAST; i++) { - int retval = register_ioctl32_conversion(i, - LinuxDriver_Ioctl32_Handler); - - if (retval) { - Warning(LGPFX"Failed to register ioctl32 conversion " - "(cmd=%d,err=%d).\n", i, retval); - return retval; - } - } - - for (i = IOCTL_VMCI_FIRST2; i < IOCTL_VMCI_LAST2; i++) { - int retval = register_ioctl32_conversion(i, - LinuxDriver_Ioctl32_Handler); - - if (retval) { - Warning(LGPFX"Failed to register ioctl32 conversion " - "(cmd=%d,err=%d).\n", i, retval); - return retval; - } - } - } -#endif /* !HAVE_COMPAT_IOCTL */ - return 0; -} - -static void -unregister_ioctl32_handlers(void) -{ -#ifndef HAVE_COMPAT_IOCTL - { - int i; - - for (i = IOCTL_VMCI_FIRST; i < IOCTL_VMCI_LAST; i++) { - int retval = unregister_ioctl32_conversion(i); - - if (retval) { - Warning(LGPFX"Failed to unregister ioctl32 conversion " - "(cmd=%d,err=%d).\n", i, retval); - } - } - - for (i = IOCTL_VMCI_FIRST2; i < IOCTL_VMCI_LAST2; i++) { - int retval = unregister_ioctl32_conversion(i); - - if (retval) { - Warning(LGPFX"Failed to unregister ioctl32 conversion " - "(cmd=%d,err=%d).\n", i, retval); - } - } - } -#endif /* !HAVE_COMPAT_IOCTL */ -} -#else /* VM_X86_64 */ -#define register_ioctl32_handlers() (0) -#define unregister_ioctl32_handlers() do { } while (0) -#endif /* VM_X86_64 */ - - -/* - *----------------------------------------------------------------------------- - * - * vmci_host_init -- - * - * Initializes the VMCI host device driver. - * - * Results: - * 0 on success, other error codes on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -vmci_host_init(void) -{ - int error; - - if (VMCI_HostInit() < VMCI_SUCCESS) { - return -ENOMEM; - } - - error = misc_register(&linuxState.misc); - if (error) { - Warning(LGPFX "Module registration error " - "(name=%s, major=%d, minor=%d, err=%d).\n", - linuxState.misc.name, MISC_MAJOR, linuxState.misc.minor, - error); - goto err_host_cleanup; - } - - error = register_ioctl32_handlers(); - if (error) { - Warning(LGPFX "Failed to register ioctl32 handlers, err: %d\n", error); - goto err_misc_unregister; - } - - Log(LGPFX "Module registered (name=%s, major=%d, minor=%d).\n", - linuxState.misc.name, MISC_MAJOR, linuxState.misc.minor); - - return 0; - -err_misc_unregister: - misc_deregister(&linuxState.misc); -err_host_cleanup: - VMCI_HostCleanup(); - return error; -} - - -/* - *---------------------------------------------------------------------- - * - * LinuxDriver_Open -- - * - * Called on open of /dev/vmci. - * - * Side effects: - * Increment use count used to determine eventual deallocation of - * the module - * - *---------------------------------------------------------------------- - */ - -static int -LinuxDriver_Open(struct inode *inode, // IN - struct file *filp) // IN -{ - VMCILinux *vmciLinux; - - vmciLinux = kmalloc(sizeof *vmciLinux, GFP_KERNEL); - if (vmciLinux == NULL) { - return -ENOMEM; - } - memset(vmciLinux, 0, sizeof *vmciLinux); - vmciLinux->ctType = VMCIOBJ_NOT_SET; - vmciLinux->userVersion = 0; -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) - compat_mutex_init(&vmciLinux->lock); -#endif - - filp->private_data = vmciLinux; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * LinuxDriver_Close -- - * - * Called on close of /dev/vmci, most often when the process - * exits. - * - *---------------------------------------------------------------------- - */ - -static int -LinuxDriver_Close(struct inode *inode, // IN - struct file *filp) // IN -{ - VMCILinux *vmciLinux; - - vmciLinux = (VMCILinux *)filp->private_data; - ASSERT(vmciLinux); - - if (vmciLinux->ctType == VMCIOBJ_CONTEXT) { - ASSERT(vmciLinux->context); - - VMCIContext_ReleaseContext(vmciLinux->context); - vmciLinux->context = NULL; - - /* - * The number of active contexts is used to track whether any - * VMX'en are using the host personality. It is incremented when - * a context is created through the IOCTL_VMCI_INIT_CONTEXT - * ioctl. - */ - - atomic_dec(&linuxState.activeContexts); - } - vmciLinux->ctType = VMCIOBJ_NOT_SET; - - kfree(vmciLinux); - filp->private_data = NULL; - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * LinuxDriverPoll -- - * - * This is used to wake up the VMX when a VMCI call arrives, or - * to wake up select() or poll() at the next clock tick. - * - *---------------------------------------------------------------------- - */ - -static unsigned int -LinuxDriverPoll(struct file *filp, - poll_table *wait) -{ - VMCILockFlags flags; - VMCILinux *vmciLinux = (VMCILinux *) filp->private_data; - unsigned int mask = 0; - - if (vmciLinux->ctType == VMCIOBJ_CONTEXT) { - ASSERT(vmciLinux->context != NULL); - /* - * Check for VMCI calls to this VM context. - */ - - if (wait != NULL) { - poll_wait(filp, &vmciLinux->context->hostContext.waitQueue, wait); - } - - VMCI_GrabLock(&vmciLinux->context->lock, &flags); - if (vmciLinux->context->pendingDatagrams > 0 || - VMCIHandleArray_GetSize(vmciLinux->context->pendingDoorbellArray) > 0) { - mask = POLLIN; - } - VMCI_ReleaseLock(&vmciLinux->context->lock, flags); - } - return mask; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCICopyHandleArrayToUser -- - * - * Copies the handles of a handle array into a user buffer, and - * returns the new length in userBufferSize. If the copy to the - * user buffer fails, the functions still returns VMCI_SUCCESS, - * but retval != 0. - * - *---------------------------------------------------------------------- - */ - -static int -VMCICopyHandleArrayToUser(void *userBufUVA, // IN - uint64 *userBufSize, // IN/OUT - VMCIHandleArray *handleArray, // IN - int *retval) // IN -{ - uint32 arraySize; - VMCIHandle *handles; - - if (handleArray) { - arraySize = VMCIHandleArray_GetSize(handleArray); - } else { - arraySize = 0; - } - - if (arraySize * sizeof *handles > *userBufSize) { - return VMCI_ERROR_MORE_DATA; - } - - *userBufSize = arraySize * sizeof *handles; - if (*userBufSize) { - *retval = copy_to_user(userBufUVA, - VMCIHandleArray_GetHandles(handleArray), - *userBufSize); - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIDoQPBrokerAlloc -- - * - * Helper function for creating queue pair and copying the result - * to user memory. - * - * Results: - * 0 if result value was copied to user memory, -EFAULT otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCIDoQPBrokerAlloc(VMCIHandle handle, - VMCIId peer, - uint32 flags, - uint64 produceSize, - uint64 consumeSize, - QueuePairPageStore *pageStore, - VMCIContext *context, - Bool vmToVm, - void *resultUVA) -{ - VMCIId cid; - int result; - int retval; - - cid = VMCIContext_GetId(context); - - result = VMCIQPBroker_Alloc(handle, peer, flags, VMCI_NO_PRIVILEGE_FLAGS, - produceSize, consumeSize, pageStore, context); - if (result == VMCI_SUCCESS && vmToVm) { - result = VMCI_SUCCESS_QUEUEPAIR_CREATE; - } - retval = copy_to_user(resultUVA, &result, sizeof result); - if (retval) { - retval = -EFAULT; - if (result >= VMCI_SUCCESS) { - result = VMCIQPBroker_Detach(handle, context); - ASSERT(result >= VMCI_SUCCESS); - } - } - - return retval; -} - - -/* - *----------------------------------------------------------------------------- - * - * LinuxDriver_Ioctl -- - * - * Main path for UserRPC - * - * Results: - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -LinuxDriver_Ioctl(struct inode *inode, - struct file *filp, - u_int iocmd, - unsigned long ioarg) -{ - VMCILinux *vmciLinux = (VMCILinux *) filp->private_data; - int retval = 0; - - switch (iocmd) { - case IOCTL_VMCI_VERSION2: { - int verFromUser; - - if (copy_from_user(&verFromUser, (void *)ioarg, sizeof verFromUser)) { - retval = -EFAULT; - break; - } - - vmciLinux->userVersion = verFromUser; - } - /* Fall through. */ - case IOCTL_VMCI_VERSION: - /* - * The basic logic here is: - * - * If the user sends in a version of 0 tell it our version. - * If the user didn't send in a version, tell it our version. - * If the user sent in an old version, tell it -its- version. - * If the user sent in an newer version, tell it our version. - * - * The rationale behind telling the caller its version is that - * Workstation 6.5 required that VMX and VMCI kernel module were - * version sync'd. All new VMX users will be programmed to - * handle the VMCI kernel module version. - */ - - if (vmciLinux->userVersion > 0 && - vmciLinux->userVersion < VMCI_VERSION_HOSTQP) { - retval = vmciLinux->userVersion; - } else { - retval = VMCI_VERSION; - } - break; - - case IOCTL_VMCI_INIT_CONTEXT: { - VMCIInitBlock initBlock; - VMCIHostUser user; - - retval = copy_from_user(&initBlock, (void *)ioarg, sizeof initBlock); - if (retval != 0) { - Log(LGPFX"Error reading init block.\n"); - retval = -EFAULT; - break; - } - - LinuxDriverLockIoctlPerFD(&vmciLinux->lock); - if (vmciLinux->ctType != VMCIOBJ_NOT_SET) { - Log(LGPFX"Received VMCI init on initialized handle.\n"); - retval = -EINVAL; - goto init_release; - } - - if (initBlock.flags & ~VMCI_PRIVILEGE_FLAG_RESTRICTED) { - Log(LGPFX"Unsupported VMCI restriction flag.\n"); - retval = -EINVAL; - goto init_release; - } - - user = current_uid(); - retval = VMCIContext_InitContext(initBlock.cid, initBlock.flags, - 0 /* Unused */, vmciLinux->userVersion, - &user, &vmciLinux->context); - if (retval < VMCI_SUCCESS) { - Log(LGPFX"Error initializing context.\n"); - retval = retval == VMCI_ERROR_DUPLICATE_ENTRY ? -EEXIST : -EINVAL; - goto init_release; - } - - /* - * Copy cid to userlevel, we do this to allow the VMX to enforce its - * policy on cid generation. - */ - initBlock.cid = VMCIContext_GetId(vmciLinux->context); - retval = copy_to_user((void *)ioarg, &initBlock, sizeof initBlock); - if (retval != 0) { - VMCIContext_ReleaseContext(vmciLinux->context); - vmciLinux->context = NULL; - Log(LGPFX"Error writing init block.\n"); - retval = -EFAULT; - goto init_release; - } - ASSERT(initBlock.cid != VMCI_INVALID_ID); - - vmciLinux->ctType = VMCIOBJ_CONTEXT; - - atomic_inc(&linuxState.activeContexts); - - init_release: - LinuxDriverUnlockIoctlPerFD(&vmciLinux->lock); - break; - } - - case IOCTL_VMCI_DATAGRAM_SEND: { - VMCIDatagramSendRecvInfo sendInfo; - VMCIDatagram *dg = NULL; - VMCIId cid; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Warning(LGPFX"Ioctl only valid for context handle (iocmd=%d).\n", iocmd); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&sendInfo, (void *) ioarg, sizeof sendInfo); - if (retval) { - Warning(LGPFX"copy_from_user failed.\n"); - retval = -EFAULT; - break; - } - - if (sendInfo.len > VMCI_MAX_DG_SIZE) { - Warning(LGPFX"Datagram too big (size=%d).\n", sendInfo.len); - retval = -EINVAL; - break; - } - - if (sendInfo.len < sizeof *dg) { - Warning(LGPFX"Datagram too small (size=%d).\n", sendInfo.len); - retval = -EINVAL; - break; - } - - dg = VMCI_AllocKernelMem(sendInfo.len, VMCI_MEMORY_NORMAL); - if (dg == NULL) { - Log(LGPFX"Cannot allocate memory to dispatch datagram.\n"); - retval = -ENOMEM; - break; - } - - retval = copy_from_user(dg, (char *)(VA)sendInfo.addr, sendInfo.len); - if (retval != 0) { - Log(LGPFX"Error getting datagram (err=%d).\n", retval); - VMCI_FreeKernelMem(dg, sendInfo.len); - retval = -EFAULT; - break; - } - - VMCI_DEBUG_LOG(10, (LGPFX"Datagram dst (handle=0x%x:0x%x) src " - "(handle=0x%x:0x%x), payload (size=%"FMT64"u " - "bytes).\n", dg->dst.context, dg->dst.resource, - dg->src.context, dg->src.resource, - dg->payloadSize)); - - /* Get source context id. */ - ASSERT(vmciLinux->context); - cid = VMCIContext_GetId(vmciLinux->context); - ASSERT(cid != VMCI_INVALID_ID); - sendInfo.result = VMCIDatagram_Dispatch(cid, dg, TRUE); - VMCI_FreeKernelMem(dg, sendInfo.len); - retval = copy_to_user((void *)ioarg, &sendInfo, sizeof sendInfo); - break; - } - - case IOCTL_VMCI_DATAGRAM_RECEIVE: { - VMCIDatagramSendRecvInfo recvInfo; - VMCIDatagram *dg = NULL; - size_t size; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Warning(LGPFX"Ioctl only valid for context handle (iocmd=%d).\n", - iocmd); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&recvInfo, (void *) ioarg, sizeof recvInfo); - if (retval) { - Warning(LGPFX"copy_from_user failed.\n"); - retval = -EFAULT; - break; - } - - ASSERT(vmciLinux->ctType == VMCIOBJ_CONTEXT); - - size = recvInfo.len; - ASSERT(vmciLinux->context); - recvInfo.result = VMCIContext_DequeueDatagram(vmciLinux->context, - &size, &dg); - - if (recvInfo.result >= VMCI_SUCCESS) { - ASSERT(dg); - retval = copy_to_user((void *) ((uintptr_t) recvInfo.addr), dg, - VMCI_DG_SIZE(dg)); - VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg)); - if (retval != 0) { - break; - } - } - retval = copy_to_user((void *)ioarg, &recvInfo, sizeof recvInfo); - break; - } - - case IOCTL_VMCI_QUEUEPAIR_ALLOC: { - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_ALLOC only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - if (vmciLinux->userVersion < VMCI_VERSION_NOVMVM) { - VMCIQueuePairAllocInfo_VMToVM queuePairAllocInfo; - VMCIQueuePairAllocInfo_VMToVM *info = (VMCIQueuePairAllocInfo_VMToVM *)ioarg; - - retval = copy_from_user(&queuePairAllocInfo, (void *)ioarg, - sizeof queuePairAllocInfo); - if (retval) { - retval = -EFAULT; - break; - } - - retval = VMCIDoQPBrokerAlloc(queuePairAllocInfo.handle, - queuePairAllocInfo.peer, - queuePairAllocInfo.flags, - queuePairAllocInfo.produceSize, - queuePairAllocInfo.consumeSize, - NULL, - vmciLinux->context, - TRUE, // VM to VM style create - &info->result); - } else { - VMCIQueuePairAllocInfo queuePairAllocInfo; - VMCIQueuePairAllocInfo *info = (VMCIQueuePairAllocInfo *)ioarg; - QueuePairPageStore pageStore; - - retval = copy_from_user(&queuePairAllocInfo, (void *)ioarg, - sizeof queuePairAllocInfo); - if (retval) { - retval = -EFAULT; - break; - } - - pageStore.pages = queuePairAllocInfo.ppnVA; - pageStore.len = queuePairAllocInfo.numPPNs; - - retval = VMCIDoQPBrokerAlloc(queuePairAllocInfo.handle, - queuePairAllocInfo.peer, - queuePairAllocInfo.flags, - queuePairAllocInfo.produceSize, - queuePairAllocInfo.consumeSize, - &pageStore, - vmciLinux->context, - FALSE, // Not VM to VM style create - &info->result); - } - break; - } - - case IOCTL_VMCI_QUEUEPAIR_SETVA: { - VMCIQueuePairSetVAInfo setVAInfo; - VMCIQueuePairSetVAInfo *info = (VMCIQueuePairSetVAInfo *)ioarg; - int32 result; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETVA only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - if (vmciLinux->userVersion < VMCI_VERSION_NOVMVM) { - Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETVA not supported for this VMX version.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&setVAInfo, (void *)ioarg, sizeof setVAInfo); - if (retval) { - retval = -EFAULT; - break; - } - - if (setVAInfo.va) { - /* - * VMX is passing down a new VA for the queue pair mapping. - */ - - result = VMCIQPBroker_Map(setVAInfo.handle, vmciLinux->context, setVAInfo.va); - } else { - /* - * The queue pair is about to be unmapped by the VMX. - */ - - result = VMCIQPBroker_Unmap(setVAInfo.handle, vmciLinux->context, 0); - } - - retval = copy_to_user(&info->result, &result, sizeof result); - if (retval) { - retval = -EFAULT; - } - - break; - } - - case IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE: { - VMCIQueuePairPageFileInfo pageFileInfo; - VMCIQueuePairPageFileInfo *info = (VMCIQueuePairPageFileInfo *)ioarg; - int32 result; - - if (vmciLinux->userVersion < VMCI_VERSION_HOSTQP || - vmciLinux->userVersion >= VMCI_VERSION_NOVMVM) { - Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE not supported this VMX " - "(version=%d).\n", vmciLinux->userVersion); - retval = -EINVAL; - break; - } - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&pageFileInfo, (void *)ioarg, sizeof *info); - if (retval) { - retval = -EFAULT; - break; - } - - /* - * Communicate success pre-emptively to the caller. Note that - * the basic premise is that it is incumbent upon the caller not - * to look at the info.result field until after the ioctl() - * returns. And then, only if the ioctl() result indicates no - * error. We send up the SUCCESS status before calling - * SetPageStore() store because failing to copy up the result - * code means unwinding the SetPageStore(). - * - * It turns out the logic to unwind a SetPageStore() opens a can - * of worms. For example, if a host had created the QueuePair - * and a guest attaches and SetPageStore() is successful but - * writing success fails, then ... the host has to be stopped - * from writing (anymore) data into the QueuePair. That means - * an additional test in the VMCI_Enqueue() code path. Ugh. - */ - - result = VMCI_SUCCESS; - retval = copy_to_user(&info->result, &result, sizeof result); - if (retval == 0) { - result = VMCIQPBroker_SetPageStore(pageFileInfo.handle, - pageFileInfo.produceVA, - pageFileInfo.consumeVA, - vmciLinux->context); - if (result < VMCI_SUCCESS) { - - retval = copy_to_user(&info->result, &result, sizeof result); - if (retval != 0) { - /* - * Note that in this case the SetPageStore() call - * failed but we were unable to communicate that to the - * caller (because the copy_to_user() call failed). - * So, if we simply return an error (in this case - * -EFAULT) then the caller will know that the - * SetPageStore failed even though we couldn't put the - * result code in the result field and indicate exactly - * why it failed. - * - * That says nothing about the issue where we were once - * able to write to the caller's info memory and now - * can't. Something more serious is probably going on - * than the fact that SetPageStore() didn't work. - */ - retval = -EFAULT; - } - } - - } else { - /* - * In this case, we can't write a result field of the - * caller's info block. So, we don't even try to - * SetPageStore(). - */ - retval = -EFAULT; - } - - break; - } - - case IOCTL_VMCI_QUEUEPAIR_DETACH: { - VMCIQueuePairDetachInfo detachInfo; - VMCIQueuePairDetachInfo *info = (VMCIQueuePairDetachInfo *)ioarg; - int32 result; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_DETACH only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&detachInfo, (void *)ioarg, sizeof detachInfo); - if (retval) { - retval = -EFAULT; - break; - } - - result = VMCIQPBroker_Detach(detachInfo.handle, vmciLinux->context); - if (result == VMCI_SUCCESS && - vmciLinux->userVersion < VMCI_VERSION_NOVMVM) { - result = VMCI_SUCCESS_LAST_DETACH; - } - - retval = copy_to_user(&info->result, &result, sizeof result); - if (retval) { - retval = -EFAULT; - } - - break; - } - - case IOCTL_VMCI_CTX_ADD_NOTIFICATION: { - VMCINotifyAddRemoveInfo arInfo; - VMCINotifyAddRemoveInfo *info = (VMCINotifyAddRemoveInfo *)ioarg; - int32 result; - VMCIId cid; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_CTX_ADD_NOTIFICATION only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&arInfo, (void *)ioarg, sizeof arInfo); - if (retval) { - retval = -EFAULT; - break; - } - - cid = VMCIContext_GetId(vmciLinux->context); - result = VMCIContext_AddNotification(cid, arInfo.remoteCID); - retval = copy_to_user(&info->result, &result, sizeof result); - if (retval) { - retval = -EFAULT; - break; - } - break; - } - - case IOCTL_VMCI_CTX_REMOVE_NOTIFICATION: { - VMCINotifyAddRemoveInfo arInfo; - VMCINotifyAddRemoveInfo *info = (VMCINotifyAddRemoveInfo *)ioarg; - int32 result; - VMCIId cid; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_CTX_REMOVE_NOTIFICATION only valid for " - "contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&arInfo, (void *)ioarg, sizeof arInfo); - if (retval) { - retval = -EFAULT; - break; - } - - cid = VMCIContext_GetId(vmciLinux->context); - result = VMCIContext_RemoveNotification(cid, arInfo.remoteCID); - retval = copy_to_user(&info->result, &result, sizeof result); - if (retval) { - retval = -EFAULT; - break; - } - break; - } - - case IOCTL_VMCI_CTX_GET_CPT_STATE: { - VMCICptBufInfo getInfo; - VMCIId cid; - char *cptBuf; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_CTX_GET_CPT_STATE only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&getInfo, (void *)ioarg, sizeof getInfo); - if (retval) { - retval = -EFAULT; - break; - } - - cid = VMCIContext_GetId(vmciLinux->context); - getInfo.result = VMCIContext_GetCheckpointState(cid, getInfo.cptType, - &getInfo.bufSize, - &cptBuf); - if (getInfo.result == VMCI_SUCCESS && getInfo.bufSize) { - retval = copy_to_user((void *)(VA)getInfo.cptBuf, cptBuf, - getInfo.bufSize); - VMCI_FreeKernelMem(cptBuf, getInfo.bufSize); - if (retval) { - retval = -EFAULT; - break; - } - } - retval = copy_to_user((void *)ioarg, &getInfo, sizeof getInfo); - if (retval) { - retval = -EFAULT; - break; - } - break; - } - - case IOCTL_VMCI_CTX_SET_CPT_STATE: { - VMCICptBufInfo setInfo; - VMCIId cid; - char *cptBuf; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_CTX_SET_CPT_STATE only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&setInfo, (void *)ioarg, sizeof setInfo); - if (retval) { - retval = -EFAULT; - break; - } - - cptBuf = VMCI_AllocKernelMem(setInfo.bufSize, VMCI_MEMORY_NORMAL); - if (cptBuf == NULL) { - Log(LGPFX"Cannot allocate memory to set cpt state (type=%d).\n", - setInfo.cptType); - retval = -ENOMEM; - break; - } - retval = copy_from_user(cptBuf, (void *)(VA)setInfo.cptBuf, - setInfo.bufSize); - if (retval) { - VMCI_FreeKernelMem(cptBuf, setInfo.bufSize); - retval = -EFAULT; - break; - } - - cid = VMCIContext_GetId(vmciLinux->context); - setInfo.result = VMCIContext_SetCheckpointState(cid, setInfo.cptType, - setInfo.bufSize, cptBuf); - VMCI_FreeKernelMem(cptBuf, setInfo.bufSize); - retval = copy_to_user((void *)ioarg, &setInfo, sizeof setInfo); - if (retval) { - retval = -EFAULT; - break; - } - break; - } - - case IOCTL_VMCI_GET_CONTEXT_ID: { - VMCIId cid = VMCI_HOST_CONTEXT_ID; - - retval = copy_to_user((void *)ioarg, &cid, sizeof cid); - break; - } - - case IOCTL_VMCI_SET_NOTIFY: { - VMCISetNotifyInfo notifyInfo; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_SET_NOTIFY only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(¬ifyInfo, (void *)ioarg, sizeof notifyInfo); - if (retval) { - retval = -EFAULT; - break; - } - - if ((VA)notifyInfo.notifyUVA != (VA)NULL) { - notifyInfo.result = VMCISetupNotify(vmciLinux->context, - (VA)notifyInfo.notifyUVA); - } else { - VMCIUnsetNotifyInt(vmciLinux->context, TRUE); - notifyInfo.result = VMCI_SUCCESS; - } - - retval = copy_to_user((void *)ioarg, ¬ifyInfo, sizeof notifyInfo); - if (retval) { - retval = -EFAULT; - break; - } - - break; - } - - case IOCTL_VMCI_NOTIFY_RESOURCE: { - VMCINotifyResourceInfo info; - VMCIId cid; - - if (vmciLinux->userVersion < VMCI_VERSION_NOTIFY) { - Log(LGPFX"IOCTL_VMCI_NOTIFY_RESOURCE is invalid for current" - " VMX versions.\n"); - retval = -EINVAL; - break; - } - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_NOTIFY_RESOURCE is only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&info, (void *)ioarg, sizeof info); - if (retval) { - retval = -EFAULT; - break; - } - - cid = VMCIContext_GetId(vmciLinux->context); - switch (info.action) { - case VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY: - if (info.resource == VMCI_NOTIFY_RESOURCE_DOOR_BELL) { - info.result = VMCIContext_NotifyDoorbell(cid, info.handle, - VMCI_NO_PRIVILEGE_FLAGS); - } else { - info.result = VMCI_ERROR_UNAVAILABLE; - } - break; - case VMCI_NOTIFY_RESOURCE_ACTION_CREATE: - info.result = VMCIContext_DoorbellCreate(cid, info.handle); - break; - case VMCI_NOTIFY_RESOURCE_ACTION_DESTROY: - info.result = VMCIContext_DoorbellDestroy(cid, info.handle); - break; - default: - Log(LGPFX"IOCTL_VMCI_NOTIFY_RESOURCE got unknown action (action=%d).\n", - info.action); - info.result = VMCI_ERROR_INVALID_ARGS; - } - retval = copy_to_user((void *)ioarg, &info, - sizeof info); - if (retval) { - retval = -EFAULT; - break; - } - - break; - } - - case IOCTL_VMCI_NOTIFICATIONS_RECEIVE: { - VMCINotificationReceiveInfo info; - VMCIHandleArray *dbHandleArray; - VMCIHandleArray *qpHandleArray; - VMCIId cid; - - if (vmciLinux->ctType != VMCIOBJ_CONTEXT) { - Log(LGPFX"IOCTL_VMCI_NOTIFICATIONS_RECEIVE is only valid for contexts.\n"); - retval = -EINVAL; - break; - } - - if (vmciLinux->userVersion < VMCI_VERSION_NOTIFY) { - Log(LGPFX"IOCTL_VMCI_NOTIFICATIONS_RECEIVE is not supported for the" - " current vmx version.\n"); - retval = -EINVAL; - break; - } - - retval = copy_from_user(&info, (void *)ioarg, sizeof info); - if (retval) { - retval = -EFAULT; - break; - } - - if ((info.dbHandleBufSize && !info.dbHandleBufUVA) || - (info.qpHandleBufSize && !info.qpHandleBufUVA)) { - retval = -EINVAL; - break; - } - - cid = VMCIContext_GetId(vmciLinux->context); - info.result = VMCIContext_ReceiveNotificationsGet(cid, - &dbHandleArray, - &qpHandleArray); - if (info.result == VMCI_SUCCESS) { - info.result = - VMCICopyHandleArrayToUser((void *)(VA)info.dbHandleBufUVA, - &info.dbHandleBufSize, - dbHandleArray, - &retval); - if (info.result == VMCI_SUCCESS && !retval) { - info.result = - VMCICopyHandleArrayToUser((void *)(VA)info.qpHandleBufUVA, - &info.qpHandleBufSize, - qpHandleArray, - &retval); - } - if (!retval) { - retval = copy_to_user((void *)ioarg, &info, sizeof info); - } - VMCIContext_ReceiveNotificationsRelease(cid, dbHandleArray, qpHandleArray, - info.result == VMCI_SUCCESS && !retval); - } else { - retval = copy_to_user((void *)ioarg, &info, sizeof info); - } - break; - } - - default: - Warning(LGPFX"Unknown ioctl (iocmd=%d).\n", iocmd); - retval = -EINVAL; - } - - return retval; -} - - -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) -/* - *----------------------------------------------------------------------------- - * - * LinuxDriver_UnlockedIoctl -- - * - * Wrapper for LinuxDriver_Ioctl supporting the compat_ioctl and - * unlocked_ioctl methods that have signatures different from the - * old ioctl. Used as compat_ioctl method for 32bit apps running - * on 64bit kernel and for unlocked_ioctl on systems supporting - * those. LinuxDriver_Ioctl may safely be called without holding - * the BKL. - * - * Results: - * Same as LinuxDriver_Ioctl. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static long -LinuxDriver_UnlockedIoctl(struct file *filp, - u_int iocmd, - unsigned long ioarg) -{ - return LinuxDriver_Ioctl(NULL, filp, iocmd, ioarg); -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUserVAInvalidPointer -- - * - * Checks if a given user VA is valid or not. Copied from - * bora/modules/vmnet/linux/hostif.c:VNetUserIfInvalidPointer(). TODO - * libify the common code. - * - * Results: - * TRUE iff invalid. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE Bool -VMCIUserVAInvalidPointer(VA uva, // IN: - size_t size) // IN: -{ - return !access_ok(VERIFY_WRITE, (void *)uva, size); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUserVALockPage -- - * - * Lock physical page backing a given user VA. Copied from - * bora/modules/vmnet/linux/userif.c:UserIfLockPage(). TODO libify the - * common code. - * - * Results: - * Pointer to struct page on success, NULL otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -VMCIUserVALockPage(VA addr) // IN: -{ - struct page *page = NULL; - int retval; - - down_read(¤t->mm->mmap_sem); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) - retval = get_user_pages(addr, 1, 1, 0, &page, NULL); -#else - retval = get_user_pages(current, current->mm, addr, - 1, 1, 0, &page, NULL); -#endif - up_read(¤t->mm->mmap_sem); - - if (retval != 1) { - return NULL; - } - - return page; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMapBoolPtr -- - * - * Lock physical page backing a given user VA and maps it to kernel - * address space. The range of the mapped memory should be within a - * single page otherwise an error is returned. Copied from - * bora/modules/vmnet/linux/userif.c:VNetUserIfMapUint32Ptr(). TODO - * libify the common code. - * - * Results: - * 0 on success, negative error code otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int -VMCIMapBoolPtr(VA notifyUVA, // IN: - struct page **p, // OUT: - Bool **notifyPtr) // OUT: -{ - if (VMCIUserVAInvalidPointer(notifyUVA, sizeof **notifyPtr) || - (((notifyUVA + sizeof **notifyPtr - 1) & ~(PAGE_SIZE - 1)) != - (notifyUVA & ~(PAGE_SIZE - 1)))) { - return -EINVAL; - } - - *p = VMCIUserVALockPage(notifyUVA); - if (*p == NULL) { - return -EAGAIN; - } - - *notifyPtr = (Bool *)((uint8 *)kmap(*p) + (notifyUVA & (PAGE_SIZE - 1))); - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCISetupNotify -- - * - * Sets up a given context for notify to work. Calls VMCIMapBoolPtr() - * which maps the notify boolean in user VA in kernel space. - * - * Results: - * VMCI_SUCCESS on success, error code otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -VMCISetupNotify(VMCIContext *context, // IN: - VA notifyUVA) // IN: -{ - int retval; - - if (context->notify) { - Warning(LGPFX"Notify mechanism is already set up.\n"); - return VMCI_ERROR_DUPLICATE_ENTRY; - } - - retval = - VMCIMapBoolPtr(notifyUVA, &context->notifyPage, &context->notify) == 0 ? - VMCI_SUCCESS : VMCI_ERROR_GENERIC; - if (retval == VMCI_SUCCESS) { - VMCIContext_CheckAndSignalNotify(context); - } - - return retval; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUnsetNotifyInt -- - * - * Internal version of VMCIUnsetNotify, that allows for locking - * the context before unsetting the notify pointer. If useLock is - * TRUE, the context lock is grabbed. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIUnsetNotifyInt(VMCIContext *context, // IN - Bool useLock) // IN -{ - VMCILockFlags flags; - - if (useLock) { - VMCI_GrabLock(&context->lock, &flags); - } - - if (context->notifyPage) { - struct page *notifyPage = context->notifyPage; - - context->notify = NULL; - context->notifyPage = NULL; - - if (useLock) { - VMCI_ReleaseLock(&context->lock, flags); - } - - kunmap(notifyPage); - put_page(notifyPage); - } else { - if (useLock) { - VMCI_ReleaseLock(&context->lock, flags); - } - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIUnsetNotify -- - * - * Reverts actions set up by VMCISetupNotify(). Unmaps and unlocks the - * page mapped/locked by VMCISetupNotify(). - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIUnsetNotify(VMCIContext *context) // IN: -{ - VMCIUnsetNotifyInt(context, FALSE); -} - - -/* - *----------------------------------------------------------------------------- - * - * PCI device support -- - * - * The following functions implement the support for the VMCI - * guest device. This includes initializing the device and - * interrupt handling. - * - *----------------------------------------------------------------------------- - */ - - -/* - *----------------------------------------------------------------------------- - * - * vmci_guest_init -- - * - * Initializes the VMCI PCI device. The initialization might fail - * if there is no VMCI PCI device. - * - * Results: - * 0 on success, other error codes on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -vmci_guest_init(void) -{ - int retval; - - /* Initialize guest device data. */ - compat_mutex_init(&vmci_dev.lock); - vmci_dev.intr_type = VMCI_INTR_TYPE_INTX; - vmci_dev.exclusive_vectors = FALSE; - spin_lock_init(&vmci_dev.dev_spinlock); - vmci_dev.enabled = FALSE; - atomic_set(&vmci_dev.datagrams_allowed, 0); - atomic_set(&guestDeviceActive, 0); - - data_buffer = vmalloc(data_buffer_size); - if (!data_buffer) { - return -ENOMEM; - } - - /* This should be last to make sure we are done initializing. */ - retval = pci_register_driver(&vmci_driver); - if (retval < 0) { - vfree(data_buffer); - data_buffer = NULL; - return retval; - } - - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_enable_msix -- - * - * Enable MSI-X. Try exclusive vectors first, then shared vectors. - * - * Results: - * 0 on success, other error codes on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -vmci_enable_msix(struct pci_dev *pdev) // IN -{ - int i; - int result; - - for (i = 0; i < VMCI_MAX_INTRS; ++i) { - vmci_dev.msix_entries[i].entry = i; - vmci_dev.msix_entries[i].vector = i; - } - - result = pci_enable_msix(pdev, vmci_dev.msix_entries, VMCI_MAX_INTRS); - if (!result) { - vmci_dev.exclusive_vectors = TRUE; - } else if (result > 0) { - result = pci_enable_msix(pdev, vmci_dev.msix_entries, 1); - } - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_probe_device -- - * - * Most of the initialization at module load time is done here. - * - * Results: - * Returns 0 for success, an error otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device - const struct pci_device_id *id) // IN: matching device ID -{ - unsigned int ioaddr; - unsigned int ioaddr_size; - unsigned int capabilities; - int result; - - printk(KERN_INFO "Probing for vmci/PCI.\n"); - - result = pci_enable_device(pdev); - if (result) { - printk(KERN_ERR "Cannot VMCI device %s: error %d\n", - pci_name(pdev), result); - return result; - } - pci_set_master(pdev); /* To enable QueuePair functionality. */ - ioaddr = pci_resource_start(pdev, 0); - ioaddr_size = pci_resource_len(pdev, 0); - - /* - * Request I/O region with adjusted base address and size. The adjusted - * values are needed and used if we release the region in case of failure. - */ - - if (!compat_request_region(ioaddr, ioaddr_size, "vmci")) { - printk(KERN_INFO "vmci: Another driver already loaded " - "for device in slot %s.\n", pci_name(pdev)); - goto pci_disable; - } - - printk(KERN_INFO "Found vmci/PCI at %#x, irq %u.\n", ioaddr, pdev->irq); - - /* - * Verify that the VMCI Device supports the capabilities that - * we need. If the device is missing capabilities that we would - * like to use, check for fallback capabilities and use those - * instead (so we can run a new VM on old hosts). Fail the load if - * a required capability is missing and there is no fallback. - * - * Right now, we need datagrams. There are no fallbacks. - */ - capabilities = inl(ioaddr + VMCI_CAPS_ADDR); - - if ((capabilities & VMCI_CAPS_DATAGRAM) == 0) { - printk(KERN_ERR "VMCI device does not support datagrams.\n"); - goto release; - } - - /* - * If the hardware supports notifications, we will use that as - * well. - */ - if (capabilities & VMCI_CAPS_NOTIFICATIONS) { - capabilities = VMCI_CAPS_DATAGRAM; - notification_bitmap = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, - ¬ification_base, - GFP_KERNEL); - if (notification_bitmap == NULL) { - printk(KERN_ERR "VMCI device unable to allocate notification bitmap.\n"); - } else { - memset(notification_bitmap, 0, PAGE_SIZE); - capabilities |= VMCI_CAPS_NOTIFICATIONS; - } - } else { - capabilities = VMCI_CAPS_DATAGRAM; - } - printk(KERN_INFO "VMCI: using capabilities 0x%x.\n", capabilities); - - /* Let the host know which capabilities we intend to use. */ - outl(capabilities, ioaddr + VMCI_CAPS_ADDR); - - /* Device struct initialization. */ - compat_mutex_lock(&vmci_dev.lock); - if (vmci_dev.enabled) { - printk(KERN_ERR "VMCI device already enabled.\n"); - goto unlock; - } - - vmci_dev.ioaddr = ioaddr; - vmci_dev.ioaddr_size = ioaddr_size; - atomic_set(&vmci_dev.datagrams_allowed, 1); - - /* - * Register notification bitmap with device if that capability is - * used - */ - if (capabilities & VMCI_CAPS_NOTIFICATIONS) { - unsigned long bitmapPPN = notification_base >> PAGE_SHIFT; - if (!VMCI_RegisterNotificationBitmap(bitmapPPN)) { - printk(KERN_ERR "VMCI device unable to register notification bitmap " - "with PPN 0x%x.\n", (uint32)bitmapPPN); - goto datagram_disallow; - } - } - - /* Check host capabilities. */ - if (!VMCI_CheckHostCapabilities()) { - goto remove_bitmap; - } - - /* Enable device. */ - vmci_dev.enabled = TRUE; - pci_set_drvdata(pdev, &vmci_dev); - vmci_pdev = pdev; - - /* - * We do global initialization here because we need datagrams - * during VMCIUtil_Init, since it registers for VMCI events. If we - * ever support more than one VMCI device we will have to create - * seperate LateInit/EarlyExit functions that can be used to do - * initialization/cleanup that depends on the device being - * accessible. We need to initialize VMCI components before - * requesting an irq - the VMCI interrupt handler uses these - * components, and it may be invoked once request_irq() has - * registered the handler (as the irq line may be shared). - */ - VMCIUtil_Init(); - - if (VMCIQPGuestEndpoints_Init() < VMCI_SUCCESS) { - goto util_exit; - } - - /* - * Enable interrupts. Try MSI-X first, then MSI, and then fallback on - * legacy interrupts. - */ - if (!vmci_disable_msix && !vmci_enable_msix(pdev)) { - vmci_dev.intr_type = VMCI_INTR_TYPE_MSIX; - vmci_dev.irq = vmci_dev.msix_entries[0].vector; - } else if (!vmci_disable_msi && !pci_enable_msi(pdev)) { - vmci_dev.intr_type = VMCI_INTR_TYPE_MSI; - vmci_dev.irq = pdev->irq; - } else { - vmci_dev.intr_type = VMCI_INTR_TYPE_INTX; - vmci_dev.irq = pdev->irq; - } - - /* Request IRQ for legacy or MSI interrupts, or for first MSI-X vector. */ - result = request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED, - "vmci", &vmci_dev); - if (result) { - printk(KERN_ERR "vmci: irq %u in use: %d\n", vmci_dev.irq, result); - goto components_exit; - } - - /* - * For MSI-X with exclusive vectors we need to request an interrupt for each - * vector so that we get a separate interrupt handler routine. This allows - * us to distinguish between the vectors. - */ - - if (vmci_dev.exclusive_vectors) { - ASSERT(vmci_dev.intr_type == VMCI_INTR_TYPE_MSIX); - result = request_irq(vmci_dev.msix_entries[1].vector, vmci_interrupt_bm, - 0, "vmci", &vmci_dev); - if (result) { - printk(KERN_ERR "vmci: irq %u in use: %d\n", - vmci_dev.msix_entries[1].vector, result); - free_irq(vmci_dev.irq, &vmci_dev); - goto components_exit; - } - } - - printk(KERN_INFO "Registered vmci device.\n"); - - atomic_inc(&guestDeviceActive); - - compat_mutex_unlock(&vmci_dev.lock); - - /* Enable specific interrupt bits. */ - if (capabilities & VMCI_CAPS_NOTIFICATIONS) { - outl(VMCI_IMR_DATAGRAM | VMCI_IMR_NOTIFICATION, - vmci_dev.ioaddr + VMCI_IMR_ADDR); - } else { - outl(VMCI_IMR_DATAGRAM, vmci_dev.ioaddr + VMCI_IMR_ADDR); - } - - /* Enable interrupts. */ - outl(VMCI_CONTROL_INT_ENABLE, vmci_dev.ioaddr + VMCI_CONTROL_ADDR); - - return 0; - - components_exit: - VMCIQPGuestEndpoints_Exit(); - tasklet_kill(&vmci_dg_tasklet); - tasklet_kill(&vmci_bm_tasklet); - util_exit: - VMCIUtil_Exit(); - vmci_dev.enabled = FALSE; - if (vmci_dev.intr_type == VMCI_INTR_TYPE_MSIX) { - pci_disable_msix(pdev); - } else if (vmci_dev.intr_type == VMCI_INTR_TYPE_MSI) { - pci_disable_msi(pdev); - } - remove_bitmap: - if (notification_bitmap) { - outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR); - } - datagram_disallow: - atomic_set(&vmci_dev.datagrams_allowed, 0); - unlock: - compat_mutex_unlock(&vmci_dev.lock); - release: - if (notification_bitmap) { - dma_free_coherent(&pdev->dev, PAGE_SIZE, notification_bitmap, - notification_base); - notification_bitmap = NULL; - } - release_region(ioaddr, ioaddr_size); - pci_disable: - pci_disable_device(pdev); - return -EBUSY; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_remove_device -- - * - * Cleanup, called for each device on unload. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -vmci_remove_device(struct pci_dev* pdev) -{ - struct vmci_device *dev = pci_get_drvdata(pdev); - - printk(KERN_INFO "Removing vmci device\n"); - - atomic_dec(&guestDeviceActive); - - VMCIQPGuestEndpoints_Exit(); - VMCIUtil_Exit(); - vmci_pdev = NULL; - - compat_mutex_lock(&dev->lock); - - atomic_set(&vmci_dev.datagrams_allowed, 0); - - printk(KERN_INFO "Resetting vmci device\n"); - outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR); - - /* - * Free IRQ and then disable MSI/MSI-X as appropriate. For MSI-X, we might - * have multiple vectors, each with their own IRQ, which we must free too. - */ - - free_irq(dev->irq, dev); - if (dev->intr_type == VMCI_INTR_TYPE_MSIX) { - if (dev->exclusive_vectors) { - free_irq(dev->msix_entries[1].vector, dev); - } - pci_disable_msix(pdev); - } else if (dev->intr_type == VMCI_INTR_TYPE_MSI) { - pci_disable_msi(pdev); - } - dev->exclusive_vectors = FALSE; - dev->intr_type = VMCI_INTR_TYPE_INTX; - - tasklet_disable(&vmci_dg_tasklet); - tasklet_disable(&vmci_bm_tasklet); - tasklet_kill(&vmci_dg_tasklet); - tasklet_kill(&vmci_bm_tasklet); - - release_region(dev->ioaddr, dev->ioaddr_size); - dev->enabled = FALSE; - if (notification_bitmap) { - /* - * The device reset above cleared the bitmap state of the - * device, so we can safely free it here. - */ - - pci_free_consistent(pdev, PAGE_SIZE, notification_bitmap, - notification_base); - notification_bitmap = NULL; - } - - printk(KERN_INFO "Unregistered vmci device.\n"); - compat_mutex_unlock(&dev->lock); - - pci_disable_device(pdev); -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_interrupt -- - * - * Interrupt handler for legacy or MSI interrupt, or for first MSI-X - * interrupt (vector VMCI_INTR_DATAGRAM). - * - * Results: - * COMPAT_IRQ_HANDLED if the interrupt is handled, COMPAT_IRQ_NONE if - * not an interrupt. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static compat_irqreturn_t -vmci_interrupt(int irq, // IN - void *clientdata, // IN - struct pt_regs *regs) // IN -#else -static compat_irqreturn_t -vmci_interrupt(int irq, // IN - void *clientdata) // IN -#endif -{ - vmci_device *dev = clientdata; - - if (dev == NULL) { - printk(KERN_DEBUG "vmci_interrupt(): irq %d for unknown device.\n", irq); - return COMPAT_IRQ_NONE; - } - - /* - * If we are using MSI-X with exclusive vectors then we simply schedule - * the datagram tasklet, since we know the interrupt was meant for us. - * Otherwise we must read the ICR to determine what to do. - */ - - if (dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors) { - tasklet_schedule(&vmci_dg_tasklet); - } else { - unsigned int icr; - - ASSERT(dev->intr_type == VMCI_INTR_TYPE_INTX || - dev->intr_type == VMCI_INTR_TYPE_MSI); - - /* Acknowledge interrupt and determine what needs doing. */ - icr = inl(dev->ioaddr + VMCI_ICR_ADDR); - if (icr == 0 || icr == 0xffffffff) { - return COMPAT_IRQ_NONE; - } - - if (icr & VMCI_ICR_DATAGRAM) { - tasklet_schedule(&vmci_dg_tasklet); - icr &= ~VMCI_ICR_DATAGRAM; - } - if (icr & VMCI_ICR_NOTIFICATION) { - tasklet_schedule(&vmci_bm_tasklet); - icr &= ~VMCI_ICR_NOTIFICATION; - } - if (icr != 0) { - printk(KERN_INFO LGPFX"Ignoring unknown interrupt cause (%d).\n", icr); - } - } - - return COMPAT_IRQ_HANDLED; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmci_interrupt_bm -- - * - * Interrupt handler for MSI-X interrupt vector VMCI_INTR_NOTIFICATION, - * which is for the notification bitmap. Will only get called if we are - * using MSI-X with exclusive vectors. - * - * Results: - * COMPAT_IRQ_HANDLED if the interrupt is handled, COMPAT_IRQ_NONE if - * not an interrupt. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static compat_irqreturn_t -vmci_interrupt_bm(int irq, // IN - void *clientdata, // IN - struct pt_regs *regs) // IN -#else -static compat_irqreturn_t -vmci_interrupt_bm(int irq, // IN - void *clientdata) // IN -#endif -{ - vmci_device *dev = clientdata; - - if (dev == NULL) { - printk(KERN_DEBUG "vmci_interrupt_bm(): irq %d for unknown device.\n", irq); - return COMPAT_IRQ_NONE; - } - - /* For MSI-X we can just assume it was meant for us. */ - ASSERT(dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors); - tasklet_schedule(&vmci_bm_tasklet); - - return COMPAT_IRQ_HANDLED; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_DeviceEnabled -- - * - * Checks whether the VMCI device is enabled. - * - * Results: - * TRUE if device is enabled, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCI_DeviceEnabled(void) -{ - return VMCI_GuestPersonalityActive() || VMCI_HostPersonalityActive(); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_SendDatagram -- - * - * VM to hypervisor call mechanism. We use the standard VMware naming - * convention since shared code is calling this function as well. - * - * Results: - * The result of the hypercall. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCI_SendDatagram(VMCIDatagram *dg) -{ - unsigned long flags; - int result; - - /* Check args. */ - if (dg == NULL) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (atomic_read(&vmci_dev.datagrams_allowed) == 0) { - return VMCI_ERROR_UNAVAILABLE; - } - - /* - * Need to acquire spinlock on the device because - * the datagram data may be spread over multiple pages and the monitor may - * interleave device user rpc calls from multiple VCPUs. Acquiring the - * spinlock precludes that possibility. Disabling interrupts to avoid - * incoming datagrams during a "rep out" and possibly landing up in this - * function. - */ - spin_lock_irqsave(&vmci_dev.dev_spinlock, flags); - - /* - * Send the datagram and retrieve the return value from the result register. - */ - __asm__ __volatile__( - "cld\n\t" - "rep outsb\n\t" - : /* No output. */ - : "d"(vmci_dev.ioaddr + VMCI_DATA_OUT_ADDR), - "c"(VMCI_DG_SIZE(dg)), "S"(dg) - ); - - /* - * XXX Should read result high port as well when updating handlers to - * return 64bit. - */ - result = inl(vmci_dev.ioaddr + VMCI_RESULT_LOW_ADDR); - spin_unlock_irqrestore(&vmci_dev.dev_spinlock, flags); - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * dispatch_datagrams -- - * - * Reads and dispatches incoming datagrams. - * - * Results: - * None. - * - * Side effects: - * Reads data from the device. - * - *----------------------------------------------------------------------------- - */ - -void -dispatch_datagrams(unsigned long data) -{ - vmci_device *dev = (vmci_device *)data; - - if (dev == NULL) { - printk(KERN_DEBUG "vmci: dispatch_datagrams(): no vmci device" - "present.\n"); - return; - } - - if (data_buffer == NULL) { - printk(KERN_DEBUG "vmci: dispatch_datagrams(): no buffer present.\n"); - return; - } - - - VMCI_ReadDatagramsFromPort((VMCIIoHandle) 0, dev->ioaddr + VMCI_DATA_IN_ADDR, - data_buffer, data_buffer_size); -} - - -/* - *----------------------------------------------------------------------------- - * - * process_bitmap -- - * - * Scans the notification bitmap for raised flags, clears them - * and handles the notifications. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -process_bitmap(unsigned long data) -{ - vmci_device *dev = (vmci_device *)data; - - if (dev == NULL) { - printk(KERN_DEBUG "vmci: process_bitmaps(): no vmci device" - "present.\n"); - return; - } - - if (notification_bitmap == NULL) { - printk(KERN_DEBUG "vmci: process_bitmaps(): no bitmap present.\n"); - return; - } - - - VMCI_ScanNotificationBitmap(notification_bitmap); -} - - -/* - *---------------------------------------------------------------------- - * - * Shared functions -- - * - * Functions shared between host and guest personality. - * - *---------------------------------------------------------------------- - */ - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_GuestPersonalityActive -- - * - * Determines whether the VMCI PCI device has been successfully - * initialized. - * - * Results: - * TRUE, if VMCI guest device is operational, FALSE otherwise. - * - * Side effects: - * Reads data from the device. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCI_GuestPersonalityActive(void) -{ - return guestDeviceInit && atomic_read(&guestDeviceActive) > 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_HostPersonalityActive -- - * - * Determines whether the VMCI host personality is - * available. Since the core functionality of the host driver is - * always present, all guests could possibly use the host - * personality. However, to minimize the deviation from the - * pre-unified driver state of affairs, we only consider the host - * device active, if there is no active guest device, or if there - * are VMX'en with active VMCI contexts using the host device. - * - * Results: - * TRUE, if VMCI host driver is operational, FALSE otherwise. - * - * Side effects: - * Reads data from the device. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCI_HostPersonalityActive(void) -{ - return hostDeviceInit && - (!VMCI_GuestPersonalityActive() || - atomic_read(&linuxState.activeContexts) > 0); -} - - -/* - *---------------------------------------------------------------------- - * - * Module definitions -- - * - * Implements support for module load/unload. - * - *---------------------------------------------------------------------- - */ - - -/* - *---------------------------------------------------------------------- - * - * vmci_init -- - * - * linux module entry point. Called by /sbin/insmod command - * - * Results: - * registers a device driver for a major # that depends - * on the uid. Add yourself to that list. List is now in - * private/driver-private.c. - * - *---------------------------------------------------------------------- - */ - -static int __init -vmci_init(void) -{ - int retval; - - retval = VMCI_SharedInit(); - if (retval != VMCI_SUCCESS) { - Warning(LGPFX"Failed to initialize VMCI common components (err=%d).\n", - retval); - return -ENOMEM; - } - - if (!vmci_disable_guest) { - retval = vmci_guest_init(); - if (retval != 0) { - Warning(LGPFX"VMCI PCI device not initialized (err=%d).\n", retval); - } else { - guestDeviceInit = TRUE; - if (VMCI_GuestPersonalityActive()) { - Log(LGPFX"Using guest personality\n"); - } - } - } - - if (!vmci_disable_host) { - retval = vmci_host_init(); - if (retval != 0) { - Warning(LGPFX"Unable to initialize host personality (err=%d).\n", - retval); - } else { - hostDeviceInit = TRUE; - Log(LGPFX"Using host personality\n"); - } - } - - if (!guestDeviceInit && !hostDeviceInit) { - VMCI_SharedCleanup(); - return -ENODEV; - } - - Log(LGPFX"Module (name=%s) is initialized\n", VMCI_MODULE_NAME); - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * vmci_exit -- - * - * Called by /sbin/rmmod - * - * - *---------------------------------------------------------------------- - */ - -static void __exit -vmci_exit(void) -{ - int retval; - - if (guestDeviceInit) { - pci_unregister_driver(&vmci_driver); - vfree(data_buffer); - data_buffer = NULL; - guestDeviceInit = FALSE; - } - - if (hostDeviceInit) { - unregister_ioctl32_handlers(); - - VMCI_HostCleanup(); - - retval = misc_deregister(&linuxState.misc); - if (retval) { - Warning(LGPFX "Module %s: error unregistering\n", VMCI_MODULE_NAME); - } else { - Log(LGPFX"Module %s: unloaded\n", VMCI_MODULE_NAME); - } - - hostDeviceInit = FALSE; - } - - VMCI_SharedCleanup(); -} - - -module_init(vmci_init); -module_exit(vmci_exit); -MODULE_DEVICE_TABLE(pci, vmci_ids); - -module_param_named(disable_host, vmci_disable_host, bool, 0); -MODULE_PARM_DESC(disable_host, "Disable driver host personality - (default=0)"); - -module_param_named(disable_guest, vmci_disable_guest, bool, 0); -MODULE_PARM_DESC(disable_guest, "Disable driver guest personality - (default=0)"); - -module_param_named(disable_msi, vmci_disable_msi, bool, 0); -MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); - -module_param_named(disable_msix, vmci_disable_msix, bool, 0); -MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=" - __stringify(VMCI_DISABLE_MSIX) ")"); - -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface (VMCI)."); -MODULE_VERSION(VMCI_DRIVER_VERSION_STRING); -MODULE_LICENSE("GPL v2"); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); diff --git a/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c b/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c deleted file mode 100644 index 2b274a09f..000000000 --- a/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c +++ /dev/null @@ -1,2145 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmciKernelIf.c -- - * - * This file implements defines and helper functions for VMCI - * host _and_ guest kernel code. This is the linux specific - * implementation. - */ - -/* Must come before any kernel header file */ -#include "driver-config.h" - -#if !defined(__linux__) || defined(VMKERNEL) -#error "Wrong platform." -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) -# error "Linux kernels before 2.6.9 are not supported." -#endif - -#include /* For vmalloc_to_page() and get_user_pages()*/ -#include /* For page_cache_release() */ -#include /* For memcpy_{to,from}iovec(). */ -#include -#include - -#include "compat_highmem.h" -#include "compat_interrupt.h" -#include "compat_mm.h" -#include "compat_module.h" -#include "compat_page.h" -#include "compat_pci.h" -#include "compat_sched.h" -#include "compat_semaphore.h" -#include "compat_slab.h" -#include "compat_spinlock.h" -#include "compat_version.h" -#include "compat_workqueue.h" - -#include "vm_assert.h" -#include "vm_basic_types.h" -#include "vmci_iocontrols.h" -#include "vmci_kernel_if.h" -#include "vmciQueue.h" -#include "vmciQueuePair.h" - - -/* - * The Kernel specific component of the VMCIQueue structure. - */ - -struct VMCIQueueKernelIf { - VMCIMutex __mutex; /* Protects the queue. */ - VMCIMutex *mutex; /* Shared by producer/consumer queues. */ - size_t numPages; /* Number of pages incl. header. */ - Bool host; /* Host or guest? */ - union { - struct { - dma_addr_t *pas; /* Physical addresses. */ - void **vas; /* Virtual addresses. */ - } g; /* Guest. */ - struct { - struct page **headerPage; /* Guest queue header pages. */ - struct page **page; /* Guest queue pages. */ - } h; /* Host. */ - } u; -}; - -typedef struct VMCIDelayedWorkInfo { - compat_work work; - VMCIWorkFn *workFn; - void *data; -} VMCIDelayedWorkInfo; - -extern struct pci_dev *vmci_pdev; - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_InitLock - * - * Initializes the lock. Must be called before use. - * - * Results: - * Always VMCI_SUCCESS. - * - * Side effects: - * Thread can block. - * - *----------------------------------------------------------------------------- - */ - -int -VMCI_InitLock(VMCILock *lock, // IN: - char *name, // IN: Unused on Linux - VMCILockRank rank) // IN: Unused on Linux -{ - spin_lock_init(lock); - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_CleanupLock - * - * Cleanup the lock. Must be called before deallocating lock. - * - * Results: - * None - * - * Side effects: - * Deletes kernel lock state - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_CleanupLock(VMCILock *lock) -{ -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_GrabLock - * - * Grabs the given lock. XXX Fill in specific lock requirements. XXX Move - * locking code into hostif if VMCI stays in vmmon. - * - * Results: - * None - * - * Side effects: - * Thread can block. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_GrabLock(VMCILock *lock, // IN - VMCILockFlags *flags) // OUT: used to restore irql on windows -{ - spin_lock(lock); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_ReleaseLock - * - * Releases the given lock. XXX Move locking code into hostif if VMCI - * stays in vmmon. - * - * Results: - * None - * - * Side effects: - * A thread blocked on this lock may wake up. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_ReleaseLock(VMCILock *lock, // IN - VMCILockFlags flags) // IN -{ - spin_unlock(lock); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_GrabLock_BH - * - * Grabs the given lock and for linux kernels disables bottom half execution. - * This should be used with locks accessed both from bottom half/tasklet - * contexts, ie. guestcall handlers, and from process contexts to avoid - * deadlocks where the process has the lock and gets descheduled due to a - * bh/tasklet coming in. - * - * Results: - * None - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_GrabLock_BH(VMCILock *lock, // IN - VMCILockFlags *flags) // OUT: used to restore -{ - spin_lock_bh(lock); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_ReleaseLock_BH - * - * Releases the given lock and for linux kernels reenables bottom half - * execution. - * This should be used with locks accessed both from bottom half/tasklet - * contexts, ie. guestcall handlers, and from process contexts to avoid - * deadlocks where the process has the lock and get descheduled due to a - * bh/tasklet coming in. - * - * Results: - * None - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_ReleaseLock_BH(VMCILock *lock, // IN - VMCILockFlags flags) // IN -{ - spin_unlock_bh(lock); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIHost_InitContext -- - * - * Host-specific initialization of VMCI context state. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIHost_InitContext(VMCIHost *hostContext, // IN - uintptr_t eventHnd) // IN: Unused -{ - init_waitqueue_head(&hostContext->waitQueue); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIHost_ReleaseContext -- - * - * Host-specific release of state allocated by - * VMCIHost_InitContext. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIHost_ReleaseContext(VMCIHost *hostContext) // IN -{ -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIHost_SignalCall -- - * - * Signal to userlevel that a VMCI call is waiting. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIHost_SignalCall(VMCIHost *hostContext) // IN -{ - wake_up(&hostContext->waitQueue); -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIHost_WaitForCallLocked -- - * - * Wait until a VMCI call is pending or the waiting thread is - * interrupted. It is assumed that a lock is held prior to - * calling this function. The lock will be released during the - * wait. The correctnes of this funtion depends on that the same - * lock is held when the call is signalled. - * - * Results: - * TRUE on success - * FALSE if the wait was interrupted. - * - * Side effects: - * The call may block. - * - *---------------------------------------------------------------------- - */ - -Bool -VMCIHost_WaitForCallLocked(VMCIHost *hostContext, // IN - VMCILock *lock, // IN - VMCILockFlags *flags, // IN - Bool useBH) // IN - -{ - DECLARE_WAITQUEUE(wait, current); - - /* - * The thread must be added to the wait queue and have its state - * changed while holding the lock - otherwise a signal may change - * the state in between and have it overwritten causing a loss of - * the event. - */ - - add_wait_queue(&hostContext->waitQueue, &wait); - current->state = TASK_INTERRUPTIBLE; - - if (useBH) { - VMCI_ReleaseLock_BH(lock, *flags); - } else { - VMCI_ReleaseLock(lock, *flags); - } - - schedule(); - - if (useBH) { - VMCI_GrabLock_BH(lock, flags); - } else { - VMCI_GrabLock(lock, flags); - } - - current->state = TASK_RUNNING; - - remove_wait_queue(&hostContext->waitQueue, &wait); - - if (signal_pending(current)) { - return FALSE; - } - - return TRUE; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCIHost_ClearCall -- - * - * Clear the pending call signal. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -VMCIHost_ClearCall(VMCIHost *hostContext) // IN -{ -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_CompareUser -- - * - * Determines whether the two users are the same. - * - * Results: - * VMCI_SUCCESS if equal, error code otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int VMCIHost_CompareUser(VMCIHostUser *user1, - VMCIHostUser *user2) -{ - if (!user1 || !user2) { - return VMCI_ERROR_INVALID_ARGS; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) -# define vmw_uid_eq(a, b) uid_eq(a, b) -#else -# define vmw_uid_eq(a, b) ((a) == (b)) -#endif - - return vmw_uid_eq(*user1, *user2) ? VMCI_SUCCESS : VMCI_ERROR_GENERIC; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_AllocKernelMem - * - * Allocate some kernel memory for the VMCI driver. - * - * Results: - * The address allocated or NULL on error. - * - * - * Side effects: - * memory is malloced - *---------------------------------------------------------------------- - */ - -void * -VMCI_AllocKernelMem(size_t size, int flags) -{ - void *ptr; - - if ((flags & VMCI_MEMORY_ATOMIC) != 0) { - ptr = kmalloc(size, GFP_ATOMIC); - } else { - ptr = kmalloc(size, GFP_KERNEL); - } - - return ptr; -} - - -/* - *---------------------------------------------------------------------- - * - * VMCI_FreeKernelMem - * - * Free kernel memory allocated for the VMCI driver. - * - * Results: - * None. - * - * Side effects: - * memory is freed. - *---------------------------------------------------------------------- - */ - -void -VMCI_FreeKernelMem(void *ptr, // IN: - size_t size) // IN: Unused on Linux -{ - kfree(ptr); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_CopyToUser -- - * - * Copy memory to the user application from a kernel buffer. This - * function may block, so don't call it while holding any kind of - * lock. - * - * Results: - * 0 on success. - * Nonzero on failure. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -int -VMCI_CopyToUser(VA64 dst, // OUT: Destination user VA. - const void *src, // IN: Source kernel VA. - size_t len) // IN: Number of bytes to copy. -{ - return copy_to_user(VMCIVA64ToPtr(dst), src, len) ? -EFAULT : 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_CopyFromUser -- - * - * Copy memory from the user application to a kernel buffer. This - * function may block, so don't call it while holding any kind of - * lock. - * - * Results: - * 0 on success. - * Nonzero on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCI_CopyFromUser(void *dst, // OUT: Kernel VA - VA64 src, // IN: User VA - size_t len) // IN -{ - return copy_from_user(dst, VMCIVA64ToPtr(src), len); -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCIDelayedWorkCB - * - * Called in a worker thread context. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VMCIDelayedWorkCB(compat_work_arg work) // IN -{ - VMCIDelayedWorkInfo *delayedWorkInfo; - - delayedWorkInfo = COMPAT_WORK_GET_DATA(work, VMCIDelayedWorkInfo, work); - ASSERT(delayedWorkInfo); - ASSERT(delayedWorkInfo->workFn); - - delayedWorkInfo->workFn(delayedWorkInfo->data); - - VMCI_FreeKernelMem(delayedWorkInfo, sizeof *delayedWorkInfo); -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCI_CanScheduleDelayedWork -- - * - * Checks to see if the given platform supports delayed work callbacks. - * - * Results: - * TRUE if it does. FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VMCI_CanScheduleDelayedWork(void) -{ - return TRUE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCI_ScheduleDelayedWork -- - * - * Schedule the specified callback. - * - * Results: - * Zero on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMCI_ScheduleDelayedWork(VMCIWorkFn *workFn, // IN - void *data) // IN -{ - VMCIDelayedWorkInfo *delayedWorkInfo; - - ASSERT(workFn); - - delayedWorkInfo = VMCI_AllocKernelMem(sizeof *delayedWorkInfo, - VMCI_MEMORY_ATOMIC); - if (!delayedWorkInfo) { - return VMCI_ERROR_NO_MEM; - } - - delayedWorkInfo->workFn = workFn; - delayedWorkInfo->data = data; - - COMPAT_INIT_WORK(&delayedWorkInfo->work, VMCIDelayedWorkCB, - delayedWorkInfo); - - compat_schedule_work(&delayedWorkInfo->work); - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_CreateEvent -- - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_CreateEvent(VMCIEvent *event) // IN: -{ - init_waitqueue_head(event); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_DestroyEvent -- - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_DestroyEvent(VMCIEvent *event) // IN: -{ - /* Nothing to do. */ -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_SignalEvent -- - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_SignalEvent(VMCIEvent *event) // IN: -{ - wake_up(event); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_WaitOnEvent -- - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_WaitOnEvent(VMCIEvent *event, // IN: - VMCIEventReleaseCB releaseCB, // IN: - void *clientData) // IN: -{ - /* - * XXX Should this be a TASK_UNINTERRUPTIBLE wait? I'm leaving it - * as it was for now. - */ - VMCI_WaitOnEventInterruptible(event, releaseCB, clientData); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_WaitOnEventInterruptible -- - * - * Results: - * True if the wait was interrupted by a signal, false otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCI_WaitOnEventInterruptible(VMCIEvent *event, // IN: - VMCIEventReleaseCB releaseCB, // IN: - void *clientData) // IN: -{ - DECLARE_WAITQUEUE(wait, current); - - if (event == NULL || releaseCB == NULL) { - return FALSE; - } - - add_wait_queue(event, &wait); - current->state = TASK_INTERRUPTIBLE; - - /* - * Release the lock or other primitive that makes it possible for us to - * put the current thread on the wait queue without missing the signal. - * Ie. on Linux we need to put ourselves on the wait queue and set our - * stateto TASK_INTERRUPTIBLE without another thread signalling us. - * The releaseCB is used to synchronize this. - */ - releaseCB(clientData); - - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(event, &wait); - - return signal_pending(current); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMutex_Init -- - * - * Initializes the mutex. Must be called before use. - * - * Results: - * Success. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIMutex_Init(VMCIMutex *mutex, // IN - char *name, // IN: Unused - VMCILockRank rank) // IN: Unused -{ - sema_init(mutex, 1); - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMutex_Destroy -- - * - * Destroys the mutex. Does nothing on Linux. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIMutex_Destroy(VMCIMutex *mutex) // IN: Unused -{ -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMutex_Acquire -- - * - * Acquires the mutex. - * - * Results: - * None. - * - * Side effects: - * Thread may block. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIMutex_Acquire(VMCIMutex *mutex) // IN: -{ - down(mutex); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMutex_Release -- - * - * Releases the mutex. - * - * Results: - * None. - * - * Side effects: - * May wake up the thread blocking on this mutex. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIMutex_Release(VMCIMutex *mutex) // IN: -{ - up(mutex); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_AllocQueue -- - * - * Allocates kernel queue pages of specified size with IOMMU mappings, - * plus space for the queue structure/kernel interface and the queue - * header. - * - * Results: - * Pointer to the queue on success, NULL otherwise. - * - * Side effects: - * Memory is allocated. - * - *----------------------------------------------------------------------------- - */ - -void * -VMCI_AllocQueue(uint64 size, // IN: size of queue (not including header) - uint32 flags) // IN: queuepair flags -{ - size_t i; - VMCIQueue *queue; - const size_t numPages = CEILING(size, PAGE_SIZE) + 1; - const size_t pasSize = numPages * sizeof *queue->kernelIf->u.g.pas; - const size_t vasSize = numPages * sizeof *queue->kernelIf->u.g.vas; - const size_t queueSize = - sizeof *queue + sizeof *(queue->kernelIf) + pasSize + vasSize; - - /* - * Size should be enforced by VMCIQPair_Alloc(), double-check here. - * Allocating too much on Linux can cause the system to become - * unresponsive, because we allocate page-by-page, and we allow the - * system to wait for pages rather than fail. - */ - - if (size > VMCI_MAX_GUEST_QP_MEMORY) { - ASSERT(FALSE); - return NULL; - } - - queue = vmalloc(queueSize); - if (!queue) { - return NULL; - } - - queue->qHeader = NULL; - queue->savedHeader = NULL; - queue->kernelIf = (VMCIQueueKernelIf *)(queue + 1); - queue->kernelIf->mutex = NULL; - queue->kernelIf->numPages = numPages; - queue->kernelIf->u.g.pas = (dma_addr_t *)(queue->kernelIf + 1); - queue->kernelIf->u.g.vas = - (void **)((uint8 *)queue->kernelIf->u.g.pas + pasSize); - queue->kernelIf->host = FALSE; - - for (i = 0; i < numPages; i++) { - queue->kernelIf->u.g.vas[i] = - dma_alloc_coherent(&vmci_pdev->dev, PAGE_SIZE, - &queue->kernelIf->u.g.pas[i], GFP_KERNEL); - if (!queue->kernelIf->u.g.vas[i]) { - VMCI_FreeQueue(queue, i * PAGE_SIZE); /* Size excl. the header. */ - return NULL; - } - } - - /* Queue header is the first page. */ - queue->qHeader = queue->kernelIf->u.g.vas[0]; - - return (void *)queue; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_FreeQueue -- - * - * Frees kernel VA space for a given queue and its queue header, and - * frees physical data pages. - * - * Results: - * None. - * - * Side effects: - * Memory is freed. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_FreeQueue(void *q, // IN: - uint64 size) // IN: size of queue (not including header) -{ - VMCIQueue *queue = q; - - if (queue) { - uint64 i; - - /* Given size does not include header, so add in a page here. */ - for (i = 0; i < CEILING(size, PAGE_SIZE) + 1; i++) { - dma_free_coherent(&vmci_pdev->dev, PAGE_SIZE, - queue->kernelIf->u.g.vas[i], - queue->kernelIf->u.g.pas[i]); - } - vfree(queue); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_AllocPPNSet -- - * - * Allocates two list of PPNs --- one for the pages in the produce queue, - * and the other for the pages in the consume queue. Intializes the list - * of PPNs with the page frame numbers of the KVA for the two queues (and - * the queue headers). - * - * Results: - * Success or failure. - * - * Side effects: - * Memory may be allocated. - * - *----------------------------------------------------------------------------- - */ - -int -VMCI_AllocPPNSet(void *prodQ, // IN: - uint64 numProducePages, // IN: for queue plus header - void *consQ, // IN: - uint64 numConsumePages, // IN: for queue plus header - PPNSet *ppnSet) // OUT: -{ - VMCIPpnList producePPNs; - VMCIPpnList consumePPNs; - VMCIQueue *produceQ = prodQ; - VMCIQueue *consumeQ = consQ; - uint64 i; - - if (!produceQ || !numProducePages || !consumeQ || !numConsumePages || - !ppnSet) { - return VMCI_ERROR_INVALID_ARGS; - } - - if (ppnSet->initialized) { - return VMCI_ERROR_ALREADY_EXISTS; - } - - producePPNs = - VMCI_AllocKernelMem(numProducePages * sizeof *producePPNs, - VMCI_MEMORY_NORMAL); - if (!producePPNs) { - return VMCI_ERROR_NO_MEM; - } - - consumePPNs = - VMCI_AllocKernelMem(numConsumePages * sizeof *consumePPNs, - VMCI_MEMORY_NORMAL); - if (!consumePPNs) { - VMCI_FreeKernelMem(producePPNs, numProducePages * sizeof *producePPNs); - return VMCI_ERROR_NO_MEM; - } - - for (i = 0; i < numProducePages; i++) { - unsigned long pfn; - - producePPNs[i] = pfn = produceQ->kernelIf->u.g.pas[i] >> PAGE_SHIFT; - - /* - * Fail allocation if PFN isn't supported by hypervisor. - */ - - if (sizeof pfn > sizeof *producePPNs && pfn != producePPNs[i]) { - goto ppnError; - } - } - for (i = 0; i < numConsumePages; i++) { - unsigned long pfn; - - consumePPNs[i] = pfn = consumeQ->kernelIf->u.g.pas[i] >> PAGE_SHIFT; - - /* - * Fail allocation if PFN isn't supported by hypervisor. - */ - - if (sizeof pfn > sizeof *consumePPNs && pfn != consumePPNs[i]) { - goto ppnError; - } - } - - ppnSet->numProducePages = numProducePages; - ppnSet->numConsumePages = numConsumePages; - ppnSet->producePPNs = producePPNs; - ppnSet->consumePPNs = consumePPNs; - ppnSet->initialized = TRUE; - return VMCI_SUCCESS; - -ppnError: - VMCI_FreeKernelMem(producePPNs, numProducePages * sizeof *producePPNs); - VMCI_FreeKernelMem(consumePPNs, numConsumePages * sizeof *consumePPNs); - return VMCI_ERROR_INVALID_ARGS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_FreePPNSet -- - * - * Frees the two list of PPNs for a queue pair. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_FreePPNSet(PPNSet *ppnSet) // IN: -{ - ASSERT(ppnSet); - if (ppnSet->initialized) { - /* Do not call these functions on NULL inputs. */ - ASSERT(ppnSet->producePPNs && ppnSet->consumePPNs); - VMCI_FreeKernelMem(ppnSet->producePPNs, - ppnSet->numProducePages * sizeof *ppnSet->producePPNs); - VMCI_FreeKernelMem(ppnSet->consumePPNs, - ppnSet->numConsumePages * sizeof *ppnSet->consumePPNs); - } - memset(ppnSet, 0, sizeof *ppnSet); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_PopulatePPNList -- - * - * Populates the list of PPNs in the hypercall structure with the PPNS - * of the produce queue and the consume queue. - * - * Results: - * VMCI_SUCCESS. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCI_PopulatePPNList(uint8 *callBuf, // OUT: - const PPNSet *ppnSet) // IN: -{ - ASSERT(callBuf && ppnSet && ppnSet->initialized); - memcpy(callBuf, ppnSet->producePPNs, - ppnSet->numProducePages * sizeof *ppnSet->producePPNs); - memcpy(callBuf + ppnSet->numProducePages * sizeof *ppnSet->producePPNs, - ppnSet->consumePPNs, - ppnSet->numConsumePages * sizeof *ppnSet->consumePPNs); - - return VMCI_SUCCESS; -} - - -#ifdef __KERNEL__ - - -/* - *----------------------------------------------------------------------------- - * - * __VMCIMemcpyToQueue -- - * - * Copies from a given buffer or iovector to a VMCI Queue. Uses - * kmap()/kunmap() to dynamically map/unmap required portions of the queue - * by traversing the offset -> page translation structure for the queue. - * Assumes that offset + size does not wrap around in the queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -__VMCIMemcpyToQueue(VMCIQueue *queue, // OUT: - uint64 queueOffset, // IN: - const void *src, // IN: - size_t size, // IN: - Bool isIovec) // IN: if src is a struct iovec * -{ - VMCIQueueKernelIf *kernelIf = queue->kernelIf; - size_t bytesCopied = 0; - - while (bytesCopied < size) { - const uint64 pageIndex = (queueOffset + bytesCopied) / PAGE_SIZE; - const size_t pageOffset = (queueOffset + bytesCopied) & (PAGE_SIZE - 1); - void *va; - size_t toCopy; - - if (kernelIf->host) { - va = kmap(kernelIf->u.h.page[pageIndex]); - } else { - va = kernelIf->u.g.vas[pageIndex + 1]; /* Skip header. */ - } - - ASSERT(va); - if (size - bytesCopied > PAGE_SIZE - pageOffset) { - /* Enough payload to fill up from this page. */ - toCopy = PAGE_SIZE - pageOffset; - } else { - toCopy = size - bytesCopied; - } - - if (isIovec) { - struct iovec *iov = (struct iovec *)src; - int err; - - /* The iovec will track bytesCopied internally. */ - err = memcpy_fromiovec((uint8 *)va + pageOffset, iov, toCopy); - if (err != 0) { - if (kernelIf->host) { - kunmap(kernelIf->u.h.page[pageIndex]); - } - return VMCI_ERROR_INVALID_ARGS; - } - } else { - memcpy((uint8 *)va + pageOffset, (uint8 *)src + bytesCopied, toCopy); - } - - bytesCopied += toCopy; - if (kernelIf->host) { - kunmap(kernelIf->u.h.page[pageIndex]); - } - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * __VMCIMemcpyFromQueue -- - * - * Copies to a given buffer or iovector from a VMCI Queue. Uses - * kmap()/kunmap() to dynamically map/unmap required portions of the queue - * by traversing the offset -> page translation structure for the queue. - * Assumes that offset + size does not wrap around in the queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -__VMCIMemcpyFromQueue(void *dest, // OUT: - const VMCIQueue *queue, // IN: - uint64 queueOffset, // IN: - size_t size, // IN: - Bool isIovec) // IN: if dest is a struct iovec * -{ - VMCIQueueKernelIf *kernelIf = queue->kernelIf; - size_t bytesCopied = 0; - - while (bytesCopied < size) { - const uint64 pageIndex = (queueOffset + bytesCopied) / PAGE_SIZE; - const size_t pageOffset = (queueOffset + bytesCopied) & (PAGE_SIZE - 1); - void *va; - size_t toCopy; - - if (kernelIf->host) { - va = kmap(kernelIf->u.h.page[pageIndex]); - } else { - va = kernelIf->u.g.vas[pageIndex + 1]; /* Skip header. */ - } - - ASSERT(va); - if (size - bytesCopied > PAGE_SIZE - pageOffset) { - /* Enough payload to fill up this page. */ - toCopy = PAGE_SIZE - pageOffset; - } else { - toCopy = size - bytesCopied; - } - - if (isIovec) { - struct iovec *iov = (struct iovec *)dest; - int err; - - /* The iovec will track bytesCopied internally. */ - err = memcpy_toiovec(iov, (uint8 *)va + pageOffset, toCopy); - if (err != 0) { - if (kernelIf->host) { - kunmap(kernelIf->u.h.page[pageIndex]); - } - return VMCI_ERROR_INVALID_ARGS; - } - } else { - memcpy((uint8 *)dest + bytesCopied, (uint8 *)va + pageOffset, toCopy); - } - - bytesCopied += toCopy; - if (kernelIf->host) { - kunmap(kernelIf->u.h.page[pageIndex]); - } - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpyToQueue -- - * - * Copies from a given buffer to a VMCI Queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIMemcpyToQueue(VMCIQueue *queue, // OUT: - uint64 queueOffset, // IN: - const void *src, // IN: - size_t srcOffset, // IN: - size_t size, // IN: - int bufType, // IN: Unused - Bool canBlock) // IN: Unused -{ - ASSERT(canBlock || !queue->kernelIf->host); - - return __VMCIMemcpyToQueue(queue, queueOffset, - (uint8 *)src + srcOffset, size, FALSE); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpyFromQueue -- - * - * Copies to a given buffer from a VMCI Queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIMemcpyFromQueue(void *dest, // OUT: - size_t destOffset, // IN: - const VMCIQueue *queue, // IN: - uint64 queueOffset, // IN: - size_t size, // IN: - int bufType, // IN: Unused - Bool canBlock) // IN: Unused -{ - ASSERT(canBlock || !queue->kernelIf->host); - - return __VMCIMemcpyFromQueue((uint8 *)dest + destOffset, - queue, queueOffset, size, FALSE); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpyToQueueLocal -- - * - * Copies from a given buffer to a local VMCI queue. On Linux, this is the - * same as a regular copy. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIMemcpyToQueueLocal(VMCIQueue *queue, // OUT - uint64 queueOffset, // IN - const void *src, // IN - size_t srcOffset, // IN - size_t size, // IN - int bufType, // IN: Unused - Bool canBlock) // IN: Unused -{ - ASSERT(canBlock || !queue->kernelIf->host); - - return __VMCIMemcpyToQueue(queue, queueOffset, - (uint8 *)src + srcOffset, size, FALSE);; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpyFromQueueLocal -- - * - * Copies to a given buffer from a VMCI Queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIMemcpyFromQueueLocal(void *dest, // OUT: - size_t destOffset, // IN: - const VMCIQueue *queue, // IN: - uint64 queueOffset, // IN: - size_t size, // IN: - int bufType, // IN: Unused - Bool canBlock) // IN: Unused -{ - ASSERT(canBlock || !queue->kernelIf->host); - - return __VMCIMemcpyFromQueue((uint8 *)dest + destOffset, - queue, queueOffset, size, FALSE); -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCIMemcpyToQueueV -- - * - * Copies from a given iovec from a VMCI Queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMCIMemcpyToQueueV(VMCIQueue *queue, // OUT: - uint64 queueOffset, // IN: - const void *src, // IN: iovec - size_t srcOffset, // IN: ignored - size_t size, // IN: - int bufType, // IN: Unused - Bool canBlock) // IN: Unused -{ - ASSERT(canBlock || !queue->kernelIf->host); - - /* - * We ignore srcOffset because src is really a struct iovec * and will - * maintain offset internally. - */ - return __VMCIMemcpyToQueue(queue, queueOffset, src, size, TRUE); -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCIMemcpyFromQueueV -- - * - * Copies to a given iovec from a VMCI Queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMCIMemcpyFromQueueV(void *dest, // OUT: iovec - size_t destOffset, // IN: ignored - const VMCIQueue *queue, // IN: - uint64 queueOffset, // IN: - size_t size, // IN: - int bufType, // IN: Unused - Bool canBlock) // IN: Unused -{ - ASSERT(canBlock || !queue->kernelIf->host); - - /* - * We ignore destOffset because dest is really a struct iovec * and will - * maintain offset internally. - */ - return __VMCIMemcpyFromQueue(dest, queue, queueOffset, size, TRUE); -} - -#endif - - -/* - *----------------------------------------------------------------------------- - * - * VMCIWellKnownID_AllowMap -- - * - * Checks whether the calling context is allowed to register for the given - * well known service ID. Currently returns FALSE if the service ID is - * within the reserved range and VMCI_PRIVILEGE_FLAG_TRUSTED is not - * provided as the input privilege flags. Otherwise returns TRUE. - * XXX TODO access control based on host configuration information; this - * will be platform specific implementation. - * - * Results: - * Boolean value indicating access granted or denied. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -VMCIWellKnownID_AllowMap(VMCIId wellKnownID, // IN: - VMCIPrivilegeFlags privFlags) // IN: -{ - if (wellKnownID < VMCI_RESERVED_RESOURCE_ID_MAX && - !(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) { - return FALSE; - } - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_AllocQueue -- - * - * Allocates kernel VA space of specified size plus space for the queue - * and kernel interface. This is different from the guest queue allocator, - * because we do not allocate our own queue header/data pages here but - * share those of the guest. - * - * Results: - * A pointer to an allocated and initialized VMCIQueue structure or NULL. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -VMCIQueue * -VMCIHost_AllocQueue(uint64 size) // IN: -{ - VMCIQueue *queue; - const size_t numPages = CEILING(size, PAGE_SIZE) + 1; - const size_t queueSize = sizeof *queue + sizeof *(queue->kernelIf); - const size_t queuePageSize = numPages * sizeof *queue->kernelIf->u.h.page; - - queue = VMCI_AllocKernelMem(queueSize + queuePageSize, VMCI_MEMORY_NORMAL); - if (queue) { - queue->qHeader = NULL; - queue->savedHeader = NULL; - queue->kernelIf = (VMCIQueueKernelIf *)(queue + 1); - queue->kernelIf->host = TRUE; - queue->kernelIf->mutex = NULL; - queue->kernelIf->numPages = numPages; - queue->kernelIf->u.h.headerPage = - (struct page **)((uint8*)queue + queueSize); - queue->kernelIf->u.h.page = &queue->kernelIf->u.h.headerPage[1]; - memset(queue->kernelIf->u.h.headerPage, 0, - (sizeof *queue->kernelIf->u.h.headerPage * - queue->kernelIf->numPages)); - } - - return queue; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_FreeQueue -- - * - * Frees kernel memory for a given queue (header plus translation - * structure). - * - * Results: - * None. - * - * Side effects: - * Memory is freed. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIHost_FreeQueue(VMCIQueue *queue, // IN: - uint64 queueSize) // IN: -{ - if (queue) { - const uint queueSize = sizeof *queue + sizeof *(queue->kernelIf); - VMCI_FreeKernelMem(queue, queueSize); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_InitQueueMutex() - * - * Initialize the mutex for the pair of queues. This mutex is used to - * protect the qHeader and the buffer from changing out from under any - * users of either queue. Of course, it's only any good if the mutexes - * are actually acquired. Queue structure must lie on non-paged memory - * or we cannot guarantee access to the mutex. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMCI_InitQueueMutex(VMCIQueue *produceQ, // IN/OUT - VMCIQueue *consumeQ) // IN/OUT -{ - ASSERT(produceQ); - ASSERT(consumeQ); - ASSERT(produceQ->kernelIf); - ASSERT(consumeQ->kernelIf); - - /* - * Only the host queue has shared state - the guest queues do not - * need to synchronize access using a queue mutex. - */ - - if (produceQ->kernelIf->host) { - produceQ->kernelIf->mutex = &produceQ->kernelIf->__mutex; - consumeQ->kernelIf->mutex = &produceQ->kernelIf->__mutex; - sema_init(produceQ->kernelIf->mutex, 1); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_CleanupQueueMutex() - * - * Cleans up the mutex for the pair of queues. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMCI_CleanupQueueMutex(VMCIQueue *produceQ, // IN/OUT - VMCIQueue *consumeQ) // IN/OUT -{ - ASSERT(produceQ); - ASSERT(consumeQ); - ASSERT(produceQ->kernelIf); - ASSERT(consumeQ->kernelIf); - - if (produceQ->kernelIf->host) { - produceQ->kernelIf->mutex = NULL; - consumeQ->kernelIf->mutex = NULL; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_AcquireQueueMutex() - * - * Acquire the mutex for the queue. Note that the produceQ and - * the consumeQ share a mutex. So, only one of the two need to - * be passed in to this routine. Either will work just fine. - * - * Results: - * VMCI_SUCCESS always. - * - * Side Effects: - * May block the caller. - * - *---------------------------------------------------------------------------- - */ - -int -VMCI_AcquireQueueMutex(VMCIQueue *queue, // IN - Bool canBlock) // IN: Unused -{ - ASSERT(queue); - ASSERT(queue->kernelIf); - - if (queue->kernelIf->host) { - ASSERT(canBlock); - ASSERT(queue->kernelIf->mutex); - down(queue->kernelIf->mutex); - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_ReleaseQueueMutex() - * - * Release the mutex for the queue. Note that the produceQ and - * the consumeQ share a mutex. So, only one of the two need to - * be passed in to this routine. Either will work just fine. - * - * Results: - * None. - * - * Side Effects: - * May block the caller. - * - *---------------------------------------------------------------------------- - */ - -void -VMCI_ReleaseQueueMutex(VMCIQueue *queue) // IN -{ - ASSERT(queue); - ASSERT(queue->kernelIf); - - if (queue->kernelIf->host) { - ASSERT(queue->kernelIf->mutex); - up(queue->kernelIf->mutex); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_LockQueueHeader() - * - * Acquire a spinlock guarding the queue header. Note that the produceQ - * and the consumeQ share the lock mutex. So, only one of the two need to - * be passed in to this routine. Either will work just fine. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMCI_LockQueueHeader(VMCIQueue *queue) // IN -{ - ASSERT(queue); - ASSERT(queue->kernelIf); - ASSERT(!queue->kernelIf->host); - - /* - * We don't support non-blocking on the host right now, so we won't get - * here for a host queue. And there's no lock required on the guest. So - * this is a NOP. - */ -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_UnlockQueueHeader() - * - * Release the spinlock guarding the queue header. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMCI_UnlockQueueHeader(VMCIQueue *queue) // IN -{ - ASSERT(queue); - ASSERT(queue->kernelIf); - ASSERT(!queue->kernelIf->host); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIReleasePageStorePages -- - * - * Helper function to release pages in the PageStoreAttachInfo - * previously obtained using get_user_pages. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VMCIReleasePages(struct page **pages, // IN - uint64 numPages, // IN - Bool dirty) // IN -{ - int i; - - for (i = 0; i < numPages; i++) { - ASSERT(pages[i]); - if (dirty) { - set_page_dirty(pages[i]); - } - page_cache_release(pages[i]); - pages[i] = NULL; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_RegisterUserMemory -- - * - * Registers the specification of the user pages used for backing a queue - * pair. Enough information to map in pages is stored in the OS specific - * part of the VMCIQueue structure. - * - * Results: - * VMCI_SUCCESS on sucess, negative error code on failure. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIHost_RegisterUserMemory(QueuePairPageStore *pageStore, // IN - VMCIQueue *produceQ, // OUT - VMCIQueue *consumeQ) // OUT -{ - VA64 produceUVA; - VA64 consumeUVA; - - ASSERT(produceQ->kernelIf->u.h.headerPage && - consumeQ->kernelIf->u.h.headerPage); - - /* - * The new style and the old style mapping only differs in that we either - * get a single or two UVAs, so we split the single UVA range at the - * appropriate spot. - */ - - produceUVA = pageStore->pages; - consumeUVA = pageStore->pages + produceQ->kernelIf->numPages * PAGE_SIZE; - return VMCIHost_GetUserMemory(produceUVA, consumeUVA, produceQ, consumeQ); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_UnregisterUserMemory -- - * - * Releases and removes the references to user pages stored in the attach - * struct. - * - * Results: - * None - * - * Side Effects: - * Pages are released from the page cache and may become - * swappable again. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIHost_UnregisterUserMemory(VMCIQueue *produceQ, // IN/OUT - VMCIQueue *consumeQ) // IN/OUT -{ - ASSERT(produceQ->kernelIf); - ASSERT(consumeQ->kernelIf); - ASSERT(!produceQ->qHeader && !consumeQ->qHeader); - - VMCIReleasePages(produceQ->kernelIf->u.h.headerPage, - produceQ->kernelIf->numPages, TRUE); - memset(produceQ->kernelIf->u.h.headerPage, 0, - (sizeof *produceQ->kernelIf->u.h.headerPage * - produceQ->kernelIf->numPages)); - VMCIReleasePages(consumeQ->kernelIf->u.h.headerPage, - consumeQ->kernelIf->numPages, TRUE); - memset(consumeQ->kernelIf->u.h.headerPage, 0, - (sizeof *consumeQ->kernelIf->u.h.headerPage * - consumeQ->kernelIf->numPages)); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_MapQueues -- - * - * Once VMCIHost_RegisterUserMemory has been performed on a - * queue, the queue pair headers can be mapped into the - * kernel. Once mapped, they must be unmapped with - * VMCIHost_UnmapQueues prior to calling - * VMCIHost_UnregisterUserMemory. - * - * Results: - * VMCI_SUCCESS if pages are mapped, appropriate error code otherwise. - * - * Side Effects: - * Pages are pinned. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIHost_MapQueues(VMCIQueue *produceQ, // IN/OUT - VMCIQueue *consumeQ, // IN/OUT - uint32 flags) // UNUSED -{ - int result; - - if (!produceQ->qHeader || !consumeQ->qHeader) { - struct page *headers[2]; - - if (produceQ->qHeader != consumeQ->qHeader) { - return VMCI_ERROR_QUEUEPAIR_MISMATCH; - } - - if (produceQ->kernelIf->u.h.headerPage == NULL || - *produceQ->kernelIf->u.h.headerPage == NULL) { - return VMCI_ERROR_UNAVAILABLE; - } - - ASSERT(*produceQ->kernelIf->u.h.headerPage && - *consumeQ->kernelIf->u.h.headerPage); - - headers[0] = *produceQ->kernelIf->u.h.headerPage; - headers[1] = *consumeQ->kernelIf->u.h.headerPage; - - produceQ->qHeader = vmap(headers, 2, VM_MAP, PAGE_KERNEL); - if (produceQ->qHeader != NULL) { - consumeQ->qHeader = - (VMCIQueueHeader *)((uint8 *)produceQ->qHeader + PAGE_SIZE); - result = VMCI_SUCCESS; - } else { - Log("vmap failed\n"); - result = VMCI_ERROR_NO_MEM; - } - } else { - result = VMCI_SUCCESS; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_UnmapQueues -- - * - * Unmaps previously mapped queue pair headers from the kernel. - * - * Results: - * VMCI_SUCCESS always. - * - * Side Effects: - * Pages are unpinned. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIHost_UnmapQueues(VMCIGuestMemID gid, // IN - VMCIQueue *produceQ, // IN/OUT - VMCIQueue *consumeQ) // IN/OUT -{ - if (produceQ->qHeader) { - ASSERT(consumeQ->qHeader); - - if (produceQ->qHeader < consumeQ->qHeader) { - vunmap(produceQ->qHeader); - } else { - vunmap(consumeQ->qHeader); - } - produceQ->qHeader = NULL; - consumeQ->qHeader = NULL; - } - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_GetUserMemory -- - * - * - * Lock the user pages referenced by the {produce,consume}Buffer - * struct into memory and populate the {produce,consume}Pages - * arrays in the attach structure with them. - * - * Results: - * VMCI_SUCCESS on sucess, negative error code on failure. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -VMCIHost_GetUserMemory(VA64 produceUVA, // IN - VA64 consumeUVA, // IN - VMCIQueue *produceQ, // OUT - VMCIQueue *consumeQ) // OUT -{ - int retval; - int err = VMCI_SUCCESS; - - down_write(¤t->mm->mmap_sem); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) - retval = get_user_pages((VA)produceUVA, - produceQ->kernelIf->numPages, - 1, 0, - produceQ->kernelIf->u.h.headerPage, - NULL); -#else - retval = get_user_pages(current, - current->mm, - (VA)produceUVA, - produceQ->kernelIf->numPages, - 1, 0, - produceQ->kernelIf->u.h.headerPage, - NULL); -#endif - if (retval < produceQ->kernelIf->numPages) { - Log("get_user_pages(produce) failed (retval=%d)\n", retval); - VMCIReleasePages(produceQ->kernelIf->u.h.headerPage, retval, FALSE); - err = VMCI_ERROR_NO_MEM; - goto out; - } - - retval = get_user_pages(current, - current->mm, - (VA)consumeUVA, - consumeQ->kernelIf->numPages, - 1, 0, - consumeQ->kernelIf->u.h.headerPage, - NULL); - if (retval < consumeQ->kernelIf->numPages) { - Log("get_user_pages(consume) failed (retval=%d)\n", retval); - VMCIReleasePages(consumeQ->kernelIf->u.h.headerPage, retval, FALSE); - VMCIReleasePages(produceQ->kernelIf->u.h.headerPage, - produceQ->kernelIf->numPages, FALSE); - err = VMCI_ERROR_NO_MEM; - } - -out: - up_write(¤t->mm->mmap_sem); - - return err; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_ReleaseUserMemory -- - * Release the reference to user pages stored in the attach - * struct - * - * Results: - * None - * - * Side Effects: - * Pages are released from the page cache and may become - * swappable again. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIHost_ReleaseUserMemory(VMCIQueue *produceQ, // IN/OUT - VMCIQueue *consumeQ) // IN/OUT -{ - ASSERT(produceQ->kernelIf->u.h.headerPage); - - VMCIHost_UnregisterUserMemory(produceQ, consumeQ); -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCI_ReadPortBytes -- - * - * Copy memory from an I/O port to kernel memory. - * - * Results: - * No results. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCI_ReadPortBytes(VMCIIoHandle handle, // IN: Unused - VMCIIoPort port, // IN - uint8 *buffer, // OUT - size_t bufferLength) // IN -{ - insb(port, buffer, bufferLength); -} diff --git a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h deleted file mode 100644 index b472a66b2..000000000 --- a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2014,2017 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_version.h -- - * - * Version definitions for the Linux vmci driver. - */ - -#ifndef _VMCI_VERSION_H_ -#define _VMCI_VERSION_H_ - -#define VMCI_DRIVER_VERSION 9.8.2.0 -#define VMCI_DRIVER_VERSION_COMMAS 9,8,2,0 -#define VMCI_DRIVER_VERSION_STRING "9.8.2.0" - -#endif /* _VMCI_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vmci/shared/pgtbl.h b/open-vm-tools/modules/linux/vmci/shared/pgtbl.h deleted file mode 100644 index 39ef4e19b..000000000 --- a/open-vm-tools/modules/linux/vmci/shared/pgtbl.h +++ /dev/null @@ -1,382 +0,0 @@ -/********************************************************* - * Copyright (C) 2002,2014 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 - * - *********************************************************/ - -#ifndef __PGTBL_H__ -# define __PGTBL_H__ - - -#include - -#include "compat_pgtable.h" -#include "compat_spinlock.h" -#include "compat_page.h" - -/* - *----------------------------------------------------------------------------- - * - * PgtblPte2MPN -- - * - * Returns the page structure associated to a Page Table Entry. - * - * This function is not allowed to schedule() because it can be called while - * holding a spinlock --hpreg - * - * Results: - * INVALID_MPN on failure - * mpn on success - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblPte2MPN(pte_t *pte) // IN -{ - MPN mpn; - if (pte_present(*pte) == 0) { - return INVALID_MPN; - } - mpn = pte_pfn(*pte); - if (mpn >= INVALID_MPN) { - return INVALID_MPN; - } - return mpn; -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblPte2Page -- - * - * Returns the page structure associated to a Page Table Entry. - * - * This function is not allowed to schedule() because it can be called while - * holding a spinlock --hpreg - * - * Results: - * The page structure if the page table entry points to a physical page - * NULL if the page table entry does not point to a physical page - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -PgtblPte2Page(pte_t *pte) // IN -{ - if (pte_present(*pte) == 0) { - return NULL; - } - - return compat_pte_page(*pte); -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblPGD2PTELocked -- - * - * Walks through the hardware page tables to try to find the pte - * associated to a virtual address. - * - * Results: - * pte. Caller must call pte_unmap if valid pte returned. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE pte_t * -PgtblPGD2PTELocked(compat_pgd_t *pgd, // IN: PGD to start with - VA addr) // IN: Address in the virtual address - // space of that process -{ - compat_pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - if (compat_pgd_present(*pgd) == 0) { - return NULL; - } - - pud = compat_pud_offset(pgd, addr); - if (compat_pud_present(*pud) == 0) { - return NULL; - } - - pmd = pmd_offset_map(pud, addr); - if (pmd_present(*pmd) == 0) { - pmd_unmap(pmd); - return NULL; - } - - pte = pte_offset_map(pmd, addr); - pmd_unmap(pmd); - return pte; -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2PTELocked -- - * - * Walks through the hardware page tables to try to find the pte - * associated to a virtual address. - * - * Results: - * pte. Caller must call pte_unmap if valid pte returned. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE pte_t * -PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address - // space of that process -{ - return PgtblPGD2PTELocked(compat_pgd_offset(mm, addr), addr); -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2MPNLocked -- - * - * Retrieve MPN for a given va. - * - * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock - * must be held, so this function is not allowed to schedule() --hpreg - * - * Results: - * INVALID_MPN on failure - * mpn on success - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address -{ - pte_t *pte; - - pte = PgtblVa2PTELocked(mm, addr); - if (pte != NULL) { - MPN mpn = PgtblPte2MPN(pte); - pte_unmap(pte); - return mpn; - } - return INVALID_MPN; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -/* - *----------------------------------------------------------------------------- - * - * PgtblKVa2MPNLocked -- - * - * Retrieve MPN for a given kernel va. - * - * Caller must call pte_unmap if valid pte returned. The mm->page_table_lock - * must be held, so this function is not allowed to schedule() --hpreg - * - * Results: - * INVALID_MPN on failure - * mpn on success - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblKVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a caller - VA addr) // IN: Address in the virtual address -{ - pte_t *pte; - - pte = PgtblPGD2PTELocked(compat_pgd_offset_k(mm, addr), addr); - if (pte != NULL) { - MPN mpn = PgtblPte2MPN(pte); - pte_unmap(pte); - return mpn; - } - return INVALID_MPN; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2PageLocked -- - * - * Return the "page" struct for a given va. - * - * Results: - * struct page or NULL. The mm->page_table_lock must be held, so this - * function is not allowed to schedule() --hpreg - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -PgtblVa2PageLocked(struct mm_struct *mm, // IN: Mm structure of a process - VA addr) // IN: Address in the virtual address -{ - pte_t *pte; - - pte = PgtblVa2PTELocked(mm, addr); - if (pte != NULL) { - struct page *page = PgtblPte2Page(pte); - pte_unmap(pte); - return page; - } else { - return NULL; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2MPN -- - * - * Walks through the hardware page tables of the current process to try to - * find the page structure associated to a virtual address. - * - * Results: - * Same as PgtblVa2MPNLocked() - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblVa2MPN(VA addr) // IN -{ - struct mm_struct *mm; - MPN mpn; - - /* current->mm is NULL for kernel threads, so use active_mm. */ - mm = current->active_mm; - if (compat_get_page_table_lock(mm)) { - spin_lock(compat_get_page_table_lock(mm)); - } - mpn = PgtblVa2MPNLocked(mm, addr); - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } - return mpn; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -/* - *----------------------------------------------------------------------------- - * - * PgtblKVa2MPN -- - * - * Walks through the hardware page tables of the current process to try to - * find the page structure associated to a virtual address. - * - * Results: - * Same as PgtblVa2MPNLocked() - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE MPN -PgtblKVa2MPN(VA addr) // IN -{ - struct mm_struct *mm = current->active_mm; - MPN mpn; - - if (compat_get_page_table_lock(mm)) { - spin_lock(compat_get_page_table_lock(mm)); - } - mpn = PgtblKVa2MPNLocked(mm, addr); - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } - return mpn; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * PgtblVa2Page -- - * - * Walks through the hardware page tables of the current process to try to - * find the page structure associated to a virtual address. - * - * Results: - * Same as PgtblVa2PageLocked() - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE struct page * -PgtblVa2Page(VA addr) // IN -{ - struct mm_struct *mm = current->active_mm; - struct page *page; - - if (compat_get_page_table_lock(mm)) { - spin_lock(compat_get_page_table_lock(mm)); - } - page = PgtblVa2PageLocked(mm, addr); - if (compat_get_page_table_lock(mm)) { - spin_unlock(compat_get_page_table_lock(mm)); - } - return page; -} - - -#endif /* __PGTBL_H__ */ diff --git a/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h b/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h deleted file mode 100644 index 067ac6d44..000000000 --- a/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h +++ /dev/null @@ -1,214 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -#ifndef _VMCI_QUEUE_H_ -#define _VMCI_QUEUE_H_ - -/* - * - * vmciQueue.h -- - * - * Defines the queue structure, and helper functions to enqueue and dequeue - * items. XXX needs checksumming? - */ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_VMK_MODULE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#if defined(__APPLE__) -# include -#endif - -#if defined VMKERNEL -# include "vm_atomic.h" -# include "return_status.h" -# include "util_copy_dist.h" -#endif - -#if defined __cplusplus -extern "C" { -#endif - - -/* - * VMCIQueue - * - * This data type contains the information about a queue. - * - * There are two queues (hence, queue pairs) per transaction model between a - * pair of end points, A & B. One queue is used by end point A to transmit - * commands and responses to B. The other queue is used by B to transmit - * commands and responses. - * - * VMCIQueueKernelIf is a per-OS defined Queue structure. It contains either a - * direct pointer to the linear address of the buffer contents or a pointer to - * structures which help the OS locate those data pages. See vmciKernelIf.c - * for each platform for its definition. - */ - -typedef struct VMCIQueueKernelIf VMCIQueueKernelIf; - -typedef struct VMCIQueue { - VMCIQueueHeader *qHeader; - VMCIQueueHeader *savedHeader; - VMCIQueueKernelIf *kernelIf; -} VMCIQueue; - - -/* - * ESX uses a buffer type for the memcpy functions. Currently, none - * of the hosted products use such a field. And, to keep the function - * definitions simple, we use a define to declare the type parameter. - */ - -#ifdef VMKERNEL -#define BUF_TYPE Util_BufferType -#else -#define BUF_TYPE int -#endif - -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these - * types are passed around to enqueue and dequeue routines. Note that - * often the functions passed are simply wrappers around memcpy - * itself. - * - * Note: In order for the memcpy typedefs to be compatible with the VMKernel, - * there's an unused last parameter for the hosted side. In - * ESX, that parameter holds a buffer type. - * - *----------------------------------------------------------------------------- - */ -typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset, - const void *src, size_t srcOffset, - size_t size, BUF_TYPE bufType, - Bool canBlock); -typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset, - const VMCIQueue *queue, uint64 queueOffset, - size_t size, BUF_TYPE bufType, - Bool canBlock); - - -#if defined(_WIN32) && defined(WINNT_DDK) -/* - * Windows needs iovec for the V functions. We use an MDL for the actual - * buffers, but we also have an offset that comes from WSK_BUF. - */ -struct iovec { - PMDL mdl; // List of memory descriptors. - ULONG offset; // Base offset. -}; -#endif // _WIN32 && WINNT_DDK - - -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpy{To,From}Queue[V][Local]() prototypes - * - * Note that these routines are NOT SAFE to call on a host end-point - * until the guest end of the queue pair has attached -AND- - * SetPageStore(). The VMX crosstalk device will issue the - * SetPageStore() on behalf of the guest when the guest creates a - * QueuePair or attaches to one created by the host. So, if the guest - * notifies the host that it's attached then the queue is safe to use. - * Also, if the host registers notification of the connection of the - * guest, then it will only receive that notification when the guest - * has issued the SetPageStore() call and not before (when the guest - * had attached). - * - *----------------------------------------------------------------------------- - */ - -int VMCIMemcpyToQueue(VMCIQueue *queue, uint64 queueOffset, const void *src, - size_t srcOffset, size_t size, BUF_TYPE bufType, - Bool canBlock); -int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue, - uint64 queueOffset, size_t size, BUF_TYPE bufType, - Bool canBlock); - -int VMCIMemcpyToQueueLocal(VMCIQueue *queue, uint64 queueOffset, const void *src, - size_t srcOffset, size_t size, BUF_TYPE bufType, - Bool canBlock); -int VMCIMemcpyFromQueueLocal(void *dest, size_t destOffset, const VMCIQueue *queue, - uint64 queueOffset, size_t size, BUF_TYPE bufType, - Bool canBlock); - -#if defined VMKERNEL || \ - (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ - (defined(__linux__) && defined(__KERNEL__)) || \ - (defined(_WIN32) && defined(WINNT_DDK)) -int VMCIMemcpyToQueueV(VMCIQueue *queue, uint64 queueOffset, const void *src, - size_t srcOffset, size_t size, BUF_TYPE bufType, - Bool canBlock); -int VMCIMemcpyFromQueueV(void *dest, size_t destOffset, const VMCIQueue *queue, - uint64 queueOffset, size_t size, BUF_TYPE bufType, - Bool canBlock); -# if defined(VMKERNEL) -int VMCIMemcpyToQueueVLocal(VMCIQueue *queue, uint64 queueOffset, - const void *src, size_t srcOffset, size_t size, - BUF_TYPE bufType, Bool canBlock); -int VMCIMemcpyFromQueueVLocal(void *dest, size_t destOffset, - const VMCIQueue *queue, uint64 queueOffset, - size_t size, BUF_TYPE bufType, Bool canBlock); -# else -/* - * For non-vmkernel platforms, the local versions are identical to the - * non-local ones. - */ - -static INLINE int -VMCIMemcpyToQueueVLocal(VMCIQueue *queue, // IN/OUT - uint64 queueOffset, // IN - const void *src, // IN: iovec - size_t srcOffset, // IN - size_t size, // IN - BUF_TYPE bufType, // IN - Bool canBlock) // IN -{ - return VMCIMemcpyToQueueV(queue, queueOffset, src, srcOffset, size, bufType, - canBlock); -} - -static INLINE int -VMCIMemcpyFromQueueVLocal(void *dest, // IN/OUT: iovec - size_t destOffset, // IN - const VMCIQueue *queue, // IN - uint64 queueOffset, // IN - size_t size, // IN - BUF_TYPE bufType, // IN - Bool canBlock) // IN -{ - return VMCIMemcpyFromQueueV(dest, destOffset, queue, queueOffset, size, bufType, - canBlock); -} -# endif /* !VMKERNEL */ -#endif /* Does the O/S support iovec? */ - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif /* !_VMCI_QUEUE_H_ */ - diff --git a/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h b/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h deleted file mode 100644 index 3a78778d6..000000000 --- a/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h +++ /dev/null @@ -1,377 +0,0 @@ -/********************************************************* - * Copyright (C) 2006 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_handle_array.h -- - * - * Simple dynamic array. - */ - -#ifndef _VMCI_HANDLE_ARRAY_H_ -#define _VMCI_HANDLE_ARRAY_H_ - -#define INCLUDE_ALLOW_VMMON -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_VMKERNEL -#include "includeCheck.h" - -#include "vmci_kernel_if.h" -#include "vmware.h" - -#include "vmci_defs.h" -#include "vm_assert.h" -#ifdef VMKERNEL -#include "vm_libc.h" -#endif // VMKERNEL - -#if defined __cplusplus -extern "C" { -#endif - - -#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4 - -typedef struct VMCIHandleArray { - uint32 capacity; - uint32 size; - VMCIHandle entries[1]; -} VMCIHandleArray; - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_Create -- - * - * Results: - * Array if successful, NULL if not. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE VMCIHandleArray * -VMCIHandleArray_Create(uint32 capacity) -{ - VMCIHandleArray *array; - - if (capacity == 0) { - capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE; - } - - array = (VMCIHandleArray *)VMCI_AllocKernelMem(sizeof array->capacity + - sizeof array->size + - capacity * sizeof(VMCIHandle), - VMCI_MEMORY_NONPAGED | - VMCI_MEMORY_ATOMIC); - if (array == NULL) { - return NULL; - } - array->capacity = capacity; - array->size = 0; - - return array; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_Destroy -- - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE void -VMCIHandleArray_Destroy(VMCIHandleArray *array) -{ - VMCI_FreeKernelMem(array, - sizeof array->capacity + sizeof array->size + - array->capacity * sizeof(VMCIHandle)); -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_AppendEntry -- - * - * Results: - * None. - * - * Side effects: - * Array may be reallocated. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE void -VMCIHandleArray_AppendEntry(VMCIHandleArray **arrayPtr, - VMCIHandle handle) -{ - VMCIHandleArray *array; - - ASSERT(arrayPtr && *arrayPtr); - array = *arrayPtr; - - if (UNLIKELY(array->size >= array->capacity)) { - /* reallocate. */ - uint32 arraySize = sizeof array->capacity + sizeof array->size + - array->capacity * sizeof(VMCIHandle); - VMCIHandleArray *newArray = (VMCIHandleArray *) - VMCI_AllocKernelMem(arraySize + array->capacity * sizeof(VMCIHandle), - VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC); - if (newArray == NULL) { - return; - } - memcpy(newArray, array, arraySize); - newArray->capacity *= 2; - VMCI_FreeKernelMem(array, arraySize); - *arrayPtr = newArray; - array = newArray; - } - array->entries[array->size] = handle; - array->size++; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_RemoveEntry -- - * - * Results: - * Handle that was removed, VMCI_INVALID_HANDLE if entry not found. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE VMCIHandle -VMCIHandleArray_RemoveEntry(VMCIHandleArray *array, - VMCIHandle entryHandle) -{ - uint32 i; - VMCIHandle handle = VMCI_INVALID_HANDLE; - - ASSERT(array); - for (i = 0; i < array->size; i++) { - if (VMCI_HANDLE_EQUAL(array->entries[i], entryHandle)) { - handle = array->entries[i]; - array->entries[i] = array->entries[array->size-1]; - array->entries[array->size-1] = VMCI_INVALID_HANDLE; - array->size--; - break; - } - } - - return handle; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_RemoveTail -- - * - * Results: - * Handle that was removed, VMCI_INVALID_HANDLE if array was empty. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE VMCIHandle -VMCIHandleArray_RemoveTail(VMCIHandleArray *array) -{ - VMCIHandle handle; - - if (array->size == 0) { - return VMCI_INVALID_HANDLE; - } - handle = array->entries[array->size-1]; - array->entries[array->size-1] = VMCI_INVALID_HANDLE; - array->size--; - - return handle; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_GetEntry -- - * - * Results: - * Handle at given index, VMCI_INVALID_HANDLE if invalid index. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE VMCIHandle -VMCIHandleArray_GetEntry(const VMCIHandleArray *array, - uint32 index) -{ - ASSERT(array); - if (UNLIKELY(index >= array->size)) { - return VMCI_INVALID_HANDLE; - } - - return array->entries[index]; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_GetSize -- - * - * Results: - * Number of entries in array. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE uint32 -VMCIHandleArray_GetSize(const VMCIHandleArray *array) -{ - ASSERT(array); - return array->size; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_HasEntry -- - * - * Results: - * TRUE is entry exists in array, FALSE if not. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE Bool -VMCIHandleArray_HasEntry(const VMCIHandleArray *array, - VMCIHandle entryHandle) -{ - uint32 i; - - ASSERT(array); - for (i = 0; i < array->size; i++) { - if (VMCI_HANDLE_EQUAL(array->entries[i], entryHandle)) { - return TRUE; - } - } - - return FALSE; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_GetCopy -- - * - * Results: - * Returns pointer to copy of array on success or NULL, if memory allocation - * fails. - * - * Side effects: - * Allocates nonpaged memory. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE VMCIHandleArray * -VMCIHandleArray_GetCopy(const VMCIHandleArray *array) -{ - VMCIHandleArray *arrayCopy; - - ASSERT(array); - - arrayCopy = (VMCIHandleArray *)VMCI_AllocKernelMem(sizeof array->capacity + - sizeof array->size + - array->size * sizeof(VMCIHandle), - VMCI_MEMORY_NONPAGED | - VMCI_MEMORY_ATOMIC); - if (arrayCopy != NULL) { - memcpy(&arrayCopy->size, &array->size, - sizeof array->size + array->size * sizeof(VMCIHandle)); - arrayCopy->capacity = array->size; - } - - return arrayCopy; -} - - -/* - *----------------------------------------------------------------------------------- - * - * VMCIHandleArray_GetHandles -- - * - * Results: - * NULL if the array is empty. Otherwise, a pointer to the array - * of VMCI handles in the handle array. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------------- - */ - -static INLINE VMCIHandle * -VMCIHandleArray_GetHandles(VMCIHandleArray *array) // IN -{ - ASSERT(array); - - if (array->size) { - return array->entries; - } else { - return NULL; - } -} - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // _VMCI_HANDLE_ARRAY_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/COPYING b/open-vm-tools/modules/linux/vmhgfs/COPYING deleted file mode 100644 index d511905c1..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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; either version 2 of the License, or - (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/open-vm-tools/modules/linux/vmhgfs/Makefile b/open-vm-tools/modules/linux/vmhgfs/Makefile deleted file mode 100644 index 2313270d8..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/Makefile +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware kernel module Makefile to be distributed externally -#### - -#### -#### SRCROOT _must_ be a relative path. -#### -SRCROOT = . - -# -# open-vm-tools doesn't replicate shared source files for different modules; -# instead, files are kept in shared locations. So define a few useful macros -# to be able to handle both cases cleanly. -# -INCLUDE := -ifdef OVT_SOURCE_DIR -AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf -VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1) -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared -INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include -else -AUTOCONF_DIR := $(SRCROOT)/shared/autoconf -INCLUDE += -I$(SRCROOT)/shared -endif - - -VM_UNAME = $(shell uname -r) - -# Header directory for the running kernel -ifdef LINUXINCLUDE -HEADER_DIR = $(LINUXINCLUDE) -else -HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include -endif - -BUILD_DIR = $(HEADER_DIR)/.. - -DRIVER := vmhgfs -PRODUCT := tools - -# Grep program -GREP = /bin/grep - -vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) -vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi) - -ifndef VM_KBUILD -VM_KBUILD := no -ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes) -VM_KBUILD := yes -endif -export VM_KBUILD -endif - -ifndef VM_KBUILD_SHOWN -ifeq ($(VM_KBUILD), no) -VM_DUMMY := $(shell echo >&2 "Using standalone build system.") -else -VM_DUMMY := $(shell echo >&2 "Using kernel build system.") -endif -VM_KBUILD_SHOWN := yes -export VM_KBUILD_SHOWN -endif - -ifneq ($(VM_KBUILD), no) - -VMCCVER := $(shell $(CC) -dumpversion) - -# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles... -ifeq ($(VERSION),) - -DRIVER_KO := $(DRIVER).ko - -.PHONY: $(DRIVER_KO) - -auto-build: $(DRIVER_KO) - cp -f $< $(SRCROOT)/../$(DRIVER).o - -# $(DRIVER_KO) is a phony target, so compare file times explicitly -$(DRIVER): $(DRIVER_KO) - if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi - -# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler -VM_CCVER := $(VMCCVER) -export VM_CCVER -VM_CC := $(CC) -export VM_CC - -MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES)) - -# -# Define a setup target that gets built before the actual driver. -# This target may not be used at all, but if it is then it will be defined -# in Makefile.kernel -# -prebuild:: ; -postbuild:: ; - -$(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) modules - $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild -endif - -vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \ - $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \ - -DKBUILD_BASENAME=\"$(DRIVER)\" \ - -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -CC_WARNINGS := -Wall -Wstrict-prototypes -CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD -ifdef VMX86_DEVEL -CC_OPTS += -DVMX86_DEVEL -endif -ifdef VMX86_DEBUG -CC_OPTS += -DVMX86_DEBUG -endif - -include $(SRCROOT)/Makefile.kernel - -else - -include $(SRCROOT)/Makefile.normal - -endif - -#.SILENT: diff --git a/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel b/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel deleted file mode 100644 index 0efef44f3..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware vmhgfs Makefile to be distributed externally -#### - -INCLUDE += -I. - -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, ) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/file_operations_flush.c, -DVMW_FLUSH_HAS_1_ARG, ) - -# Note: These tests are inverted -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/getsb1.c,, -DVMW_GETSB_2618) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/statfs1.c,, -DVMW_STATFS_2618) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/inode1.c,, -DVMW_INODE_2618) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/dcount.c,, -DVMW_DCOUNT_311) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/dalias.c,, -DVMW_DALIAS_319) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/dalias1.c,, -DVMW_DALIAS_319) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/truncate_pagecache.c,, -DVMW_PAGECACHE_312) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/wait_on_bit.c,, -DVMW_WAITONBIT_317) - -obj-m += $(DRIVER).o - -$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, $(wildcard $(SRCROOT)/*.c))) - -# -# In open-vm-tools, need to compile the common sources from the lib directory. -# -VMHGFS_PATH := $(shell cd $(SRCROOT) && pwd) - -ifdef OVT_SOURCE_DIR -LIBBACKDOOR_PATH := $(call VMLIB_PATH,backdoor) -LIBHGFS_PATH := $(call VMLIB_PATH,hgfs) -LIBHGFSBD_PATH := $(call VMLIB_PATH,hgfsBd) -LIBMESSAGE_PATH := $(call VMLIB_PATH,message) -LIBRPCOUT_PATH := $(call VMLIB_PATH,rpcOut) -STUBS_PATH := $(OVT_SOURCE_DIR)/modules/linux/shared - -INCLUDE += -I$(LIBBACKDOOR_PATH) -INCLUDE += -I$(LIBHGFS_PATH) - -LIBBACKDOOR := backdoor.o -LIBBACKDOOR += backdoorGcc32.o -LIBBACKDOOR += backdoorGcc64.o - -LIBHGFS := cpName.o -LIBHGFS += cpNameLinux.o -LIBHGFS += cpNameLite.o -LIBHGFS += hgfsEscape.o -LIBHGFS += hgfsUtil.o - -LIBHGFSBD := hgfsBd.o - -LIBMESSAGE := message.o - -LIBRPCOUT := rpcout.o - -$(addprefix $(VMHGFS_PATH)/,$(LIBBACKDOOR)): $(VMHGFS_PATH)/%.o: $(LIBBACKDOOR_PATH)/%.c - $(Q)$(rule_cc_o_c) - -$(addprefix $(VMHGFS_PATH)/,$(LIBHGFS)): $(VMHGFS_PATH)/%.o: $(LIBHGFS_PATH)/%.c - $(Q)$(rule_cc_o_c) - -$(addprefix $(VMHGFS_PATH)/,$(LIBHGFSBD)): $(VMHGFS_PATH)/%.o: $(LIBHGFSBD_PATH)/%.c - $(Q)$(rule_cc_o_c) - -$(addprefix $(VMHGFS_PATH)/,$(LIBMESSAGE)): $(VMHGFS_PATH)/%.o: $(LIBMESSAGE_PATH)/%.c - $(Q)$(rule_cc_o_c) - -$(addprefix $(VMHGFS_PATH)/,$(LIBRPCOUT)): $(VMHGFS_PATH)/%.o: $(LIBRPCOUT_PATH)/%.c - $(Q)$(rule_cc_o_c) - - -$(DRIVER)-y += $(LIBBACKDOOR) -$(DRIVER)-y += $(LIBHGFS) -$(DRIVER)-y += $(LIBHGFSBD) -$(DRIVER)-y += $(LIBMESSAGE) -$(DRIVER)-y += $(LIBRPCOUT) -else -STUBS_PATH := $(VMHGFS_PATH)/shared -endif - -STUBS := kernelStubsLinux.o -$(DRIVER)-y += $(STUBS) -$(addprefix $(VMHGFS_PATH)/,$(STUBS)): $(VMHGFS_PATH)/%.o: $(STUBS_PATH)/%.c - $(Q)$(rule_cc_o_c) - -# -# On a 32-bit machine, strip out 64-bit backdoor code, and vice versa. -# -ifeq ($(CONFIG_X86_64),y) -$(DRIVER)-y := $(filter-out backdoorGcc32.o, $($(DRIVER)-y)) -else -$(DRIVER)-y := $(filter-out backdoorGcc64.o, $($(DRIVER)-y)) -endif - -clean: - rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ - Module.symvers Modules.symvers Module.markers modules.order \ - $(foreach dir,./,$(addprefix $(dir),.*.cmd .*.o.flags *.o))) diff --git a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c deleted file mode 100644 index d815f7d0d..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c +++ /dev/null @@ -1,246 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * bdhandler.c -- - * - * Background thread for handling backdoor requests and replies. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include - -#include "transport.h" -#include "hgfsBd.h" -#include "hgfsDevLinux.h" -#include "hgfsProto.h" -#include "module.h" -#include "request.h" -#include "rpcout.h" -#include "vm_assert.h" - - -static Bool HgfsBdChannelOpen(HgfsTransportChannel *channel); -static void HgfsBdChannelClose(HgfsTransportChannel *channel); -static HgfsReq * HgfsBdChannelAllocate(size_t payloadSize); -void HgfsBdChannelFree(HgfsReq *req); -static int HgfsBdChannelSend(HgfsTransportChannel *channel, HgfsReq *req); - -static HgfsTransportChannel channel = { - .name = "backdoor", - .ops.open = HgfsBdChannelOpen, - .ops.close = HgfsBdChannelClose, - .ops.allocate = HgfsBdChannelAllocate, - .ops.free = HgfsBdChannelFree, - .ops.send = HgfsBdChannelSend, - .priv = NULL, - .status = HGFS_CHANNEL_NOTCONNECTED -}; - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBdChannelOpen -- - * - * Open the backdoor in an idempotent way. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static Bool -HgfsBdChannelOpen(HgfsTransportChannel *channel) // IN: Channel -{ - Bool ret = FALSE; - - ASSERT(channel->status == HGFS_CHANNEL_NOTCONNECTED); - - if (HgfsBd_OpenBackdoor((RpcOut **)&channel->priv)) { - LOG(8, ("VMware hgfs: %s: backdoor opened.\n", __func__)); - ret = TRUE; - ASSERT(channel->priv != NULL); - } - - return ret; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBdChannelClose -- - * - * Close the backdoor in an idempotent way. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsBdChannelClose(HgfsTransportChannel *channel) // IN: Channel -{ - ASSERT(channel->priv != NULL); - - HgfsBd_CloseBackdoor((RpcOut **)&channel->priv); - ASSERT(channel->priv == NULL); - - LOG(8, ("VMware hgfs: %s: backdoor closed.\n", __func__)); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBdChannelAllocate -- - * - * Allocate request in a way that is suitable for sending through - * backdoor. - * - * Results: - * NULL on failure; otherwise address of the new request. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static HgfsReq * -HgfsBdChannelAllocate(size_t payloadSize) // IN: size of requests payload -{ - HgfsReq *req; - - req = kmalloc(sizeof(*req) + HGFS_SYNC_REQREP_CLIENT_CMD_LEN + payloadSize, - GFP_KERNEL); - if (likely(req)) { - /* Setup the packet prefix. */ - memcpy(req->buffer, HGFS_SYNC_REQREP_CLIENT_CMD, - HGFS_SYNC_REQREP_CLIENT_CMD_LEN); - - req->payload = req->buffer + HGFS_SYNC_REQREP_CLIENT_CMD_LEN; - req->bufferSize = payloadSize; - } - - return req; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBdChannelFree -- - * - * Free previously allocated request. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -HgfsBdChannelFree(HgfsReq *req) -{ - ASSERT(req); - kfree(req); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsBdChannelSend -- - * - * Send a request via backdoor. - * - * Results: - * 0 on success, negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsBdChannelSend(HgfsTransportChannel *channel, // IN: Channel - HgfsReq *req) // IN: request to send -{ - char const *replyPacket = NULL; - size_t payloadSize; - int ret; - - ASSERT(req); - ASSERT(req->state == HGFS_REQ_STATE_UNSENT); - ASSERT(req->payloadSize <= req->bufferSize); - - LOG(8, ("VMware hgfs: %s: backdoor sending.\n", __func__)); - payloadSize = req->payloadSize; - ret = HgfsBd_Dispatch(channel->priv, HGFS_REQ_PAYLOAD(req), &payloadSize, - &replyPacket); - if (ret == 0) { - LOG(8, ("VMware hgfs: %s: Backdoor reply received.\n", __func__)); - /* Request sent successfully. Copy the reply and wake the client. */ - ASSERT(replyPacket); - ASSERT(payloadSize <= req->bufferSize); - memcpy(HGFS_REQ_PAYLOAD(req), replyPacket, payloadSize); - req->payloadSize = payloadSize; - HgfsCompleteReq(req); - } - - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetBdChannel -- - * - * Initialize backdoor channel. - * - * Results: - * Always return pointer to back door channel. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsTransportChannel* -HgfsGetBdChannel(void) -{ - return &channel; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/dentry.c b/open-vm-tools/modules/linux/vmhgfs/dentry.c deleted file mode 100644 index 84bd3af81..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/dentry.c +++ /dev/null @@ -1,117 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * dentry.c -- - * - * Dentry operations for the filesystem portion of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include "compat_fs.h" -#include "compat_kernel.h" -#include "compat_namei.h" -#include "compat_version.h" - -#include "inode.h" -#include "module.h" -#include "vm_assert.h" - -/* HGFS dentry operations. */ -static int HgfsDentryRevalidate(struct dentry *dentry, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - unsigned int flags -#else - struct nameidata *nd -#endif -); - -/* HGFS dentry operations structure. */ -struct dentry_operations HgfsDentryOperations = { - .d_revalidate = HgfsDentryRevalidate, -}; - -/* - * HGFS dentry operations. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsDentryRevalidate -- - * - * Called by namei.c every time a dentry is looked up in the dcache - * to determine if it is still valid. - * - * If the entry is found to be invalid, namei calls dput on it and - * returns NULL, which causes a new lookup to be done in the actual - * filesystem, which in our case means that HgfsLookup is called. - * - * Results: - * Positive value if the entry IS valid. - * Zero if the entry is NOT valid. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsDentryRevalidate(struct dentry *dentry, // IN: Dentry to revalidate -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - unsigned int flags // IN: Lookup flags & intent -#else - struct nameidata *nd // IN: Lookup flags & intent -#endif -) -{ - int error; - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDentryRevalidate: calling " - "HgfsRevalidate\n")); - - ASSERT(dentry); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - if (flags & LOOKUP_RCU) { - return -ECHILD; - } -#elif 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; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDentryRevalidate: valid\n")); - return 1; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/dir.c b/open-vm-tools/modules/linux/vmhgfs/dir.c deleted file mode 100644 index 227bdcb8d..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/dir.c +++ /dev/null @@ -1,1481 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * dir.c -- - * - * Directory operations for the filesystem portion of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include "compat_fs.h" -#include "compat_kernel.h" -#include "compat_slab.h" -#include "compat_mutex.h" - -#include "cpName.h" -#include "hgfsEscape.h" -#include "hgfsProto.h" -#include "hgfsUtil.h" -#include "module.h" -#include "request.h" -#include "fsutil.h" -#include "vm_assert.h" -#include "vm_basic_types.h" - -/* Private functions. */ -static int HgfsPrivateDirReOpen(struct file *file); -static int HgfsPrivateDirOpen(struct file *file, - HgfsHandle *handle); -static int HgfsPrivateDirRelease(struct file *file, - HgfsHandle handle); -static int HgfsUnpackSearchReadReply(HgfsReq *req, - HgfsAttrInfo *attr, - char **entryName); -static int HgfsGetNextDirEntry(HgfsSuperInfo *si, - HgfsHandle searchHandle, - uint32 offset, - HgfsAttrInfo *attr, - char **entryName, - Bool *done); -static int HgfsPackDirOpenRequest(struct file *file, - HgfsOp opUsed, - HgfsReq *req); -static Bool -HgfsReaddirFillEntry(filldir_t filldirCb, - void *context, - char *entryName, - uint32 entryNameLength, - loff_t entryPos, - ino_t entryIno, - uint32 entryType); - -/* HGFS file operations for directories. */ -static int HgfsDirOpen(struct inode *inode, - struct file *file); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) -static int HgfsReaddir(struct file *file, - struct dir_context *ctx); -#else -static int HgfsReaddir(struct file *file, - void *dirent, - filldir_t filldir); -#endif -static int HgfsDirRelease(struct inode *inode, - struct file *file); -static loff_t HgfsDirLlseek(struct file *file, - loff_t offset, - int origin); - -/* HGFS file operations structure for directories. */ -struct file_operations HgfsDirFileOperations = { - .llseek = HgfsDirLlseek, - .owner = THIS_MODULE, - .open = HgfsDirOpen, - .read = generic_read_dir, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) - .iterate = HgfsReaddir, -#else - .readdir = HgfsReaddir, -#endif - .release = HgfsDirRelease, -}; - -/* - * Private function implementations. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsUnpackSearchReadReply -- - * - * This function abstracts the differences between a SearchReadV1 and - * a SearchReadV2. The caller provides the packet containing the reply - * and we populate the AttrInfo with version-independent information. - * - * Note that attr->requestType has already been populated so that we - * know whether to expect a V1 or V2 reply. - * - * Results: - * 0 on success, anything else on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ -static int -HgfsUnpackSearchReadReply(HgfsReq *req, // IN: Reply packet - HgfsAttrInfo *attr, // IN/OUT: Attributes - char **entryName) // OUT: file name -{ - char *fileName; - uint32 fileNameLength; - uint32 replySize; - int result; - - ASSERT(req); - ASSERT(attr); - - result = HgfsUnpackCommonAttr(req, attr); - if (result != 0) { - return result; - } - - switch(attr->requestType) { - case HGFS_OP_SEARCH_READ_V3: { - HgfsReplySearchReadV3 *replyV3; - HgfsDirEntry *dirent; - - /* Currently V3 returns only 1 entry. */ - replyV3 = (HgfsReplySearchReadV3 *)(HGFS_REP_PAYLOAD_V3(req)); - replyV3->count = 1; - replySize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3) + sizeof *dirent; - dirent = (HgfsDirEntry *)replyV3->payload; - fileName = dirent->fileName.name; - fileNameLength = dirent->fileName.length; - break; - } - case HGFS_OP_SEARCH_READ_V2: { - HgfsReplySearchReadV2 *replyV2; - - replyV2 = (HgfsReplySearchReadV2 *)(HGFS_REQ_PAYLOAD(req)); - replySize = sizeof *replyV2; - fileName = replyV2->fileName.name; - fileNameLength = replyV2->fileName.length; - break; - } - case HGFS_OP_SEARCH_READ: { - HgfsReplySearchRead *replyV1; - - replyV1 = (HgfsReplySearchRead *)(HGFS_REQ_PAYLOAD(req)); - replySize = sizeof *replyV1; - fileName = replyV1->fileName.name; - fileNameLength = replyV1->fileName.length; - break; - } - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackSearchReadReply: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - /* - * Make sure name length is legal. - */ - if (fileNameLength > NAME_MAX || - fileNameLength > req->bufferSize - replySize) { - return -ENAMETOOLONG; - } - - /* - * If the size of the name is valid (meaning the end of the directory has - * not yet been reached), copy the name to the AttrInfo struct. - * - * XXX: This operation happens often and the length of the filename is - * bounded by NAME_MAX. Perhaps I should just put a statically-sized - * array in HgfsAttrInfo and use a slab allocator to allocate the struct. - */ - if (fileNameLength > 0) { - /* Sanity check on name length. */ - if (fileNameLength != strlen(fileName)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackSearchReadReply: name " - "length mismatch %u/%Zu, name \"%s\"\n", - fileNameLength, strlen(fileName), fileName)); - return -EPROTO; - } - *entryName = kmalloc(fileNameLength + 1, GFP_KERNEL); - if (*entryName == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackSearchReadReply: out of " - "memory allocating filename, ignoring\n")); - return -ENOMEM; - } - memcpy(*entryName, fileName, fileNameLength + 1); - } else { - *entryName = NULL; - } - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetNextDirEntry -- - * - * Get the directory entry with the given offset from the server. - * - * fileName gets allocated and must be freed by the caller. - * - * Results: - * Returns zero on success, negative error on failure. If the - * dentry's name is too long, -ENAMETOOLONG is returned. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsGetNextDirEntry(HgfsSuperInfo *si, // IN: Superinfo for this SB - HgfsHandle searchHandle, // IN: Handle of dir - uint32 offset, // IN: Offset of next dentry to get - HgfsAttrInfo *attr, // OUT: File attributes of dentry - char **entryName, // OUT: File name - Bool *done) // OUT: Set true when there are - // no more dentries -{ - HgfsReq *req; - HgfsOp opUsed; - HgfsStatus replyStatus; - int result = 0; - - ASSERT(si); - ASSERT(attr); - ASSERT(done); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: out of memory " - "while getting new request\n")); - return -ENOMEM; - } - - retry: - opUsed = hgfsVersionSearchRead; - if (opUsed == HGFS_OP_SEARCH_READ_V3) { - HgfsRequest *header; - HgfsRequestSearchReadV3 *request; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->op = attr->requestType = opUsed; - header->id = req->id; - - request = (HgfsRequestSearchReadV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->search = searchHandle; - request->offset = offset; - request->flags = 0; - request->reserved = 0; - req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - } else { - HgfsRequestSearchRead *request; - - request = (HgfsRequestSearchRead *)(HGFS_REQ_PAYLOAD(req)); - request->header.op = attr->requestType = opUsed; - request->header.id = req->id; - request->search = searchHandle; - request->offset = offset; - req->payloadSize = sizeof *request; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: got reply\n")); - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch(result) { - case 0: - result = HgfsUnpackSearchReadReply(req, attr, entryName); - if (result == 0 && *entryName == NULL) { - /* We're at the end of the directory. */ - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: end of " - "dir\n")); - *done = TRUE; - } - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (attr->requestType == HGFS_OP_SEARCH_READ_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: Version 3 " - "not supported. Falling back to version 2.\n")); - hgfsVersionSearchRead = HGFS_OP_SEARCH_READ_V2; - goto retry; - } else if (attr->requestType == HGFS_OP_SEARCH_READ_V2) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: Version 2 " - "not supported. Falling back to version 1.\n")); - hgfsVersionSearchRead = HGFS_OP_SEARCH_READ; - goto retry; - } - - /* Fallthrough. */ - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: unknown error: " - "%d\n", result)); - } - - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackDirOpenRequest -- - * - * Setup the directory open request, depending on the op version. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackDirOpenRequest(struct file *file, // IN: File pointer for this open - HgfsOp opUsed, // IN: Op to be used - HgfsReq *req) // IN/OUT: Packet to write into -{ - char *name; - uint32 *nameLength; - size_t requestSize; - int result; - - ASSERT(file); - ASSERT(req); - - switch (opUsed) { - case HGFS_OP_SEARCH_OPEN_V3: { - HgfsRequest *requestHeader; - HgfsRequestSearchOpenV3 *requestV3; - - requestHeader = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestSearchOpenV3 *)HGFS_REQ_PAYLOAD_V3(req); - - /* We'll use these later. */ - name = requestV3->dirName.name; - nameLength = &requestV3->dirName.length; - requestV3->dirName.flags = 0; - requestV3->dirName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - requestV3->dirName.fid = HGFS_INVALID_HANDLE; - requestV3->reserved = 0; - requestSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - break; - } - - case HGFS_OP_SEARCH_OPEN: { - HgfsRequestSearchOpen *request; - - request = (HgfsRequestSearchOpen *)(HGFS_REQ_PAYLOAD(req)); - request->header.op = opUsed; - request->header.id = req->id; - - /* We'll use these later. */ - name = request->dirName.name; - nameLength = &request->dirName.length; - requestSize = sizeof *request; - break; - } - - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - /* Build full name to send to server. */ - if (HgfsBuildPath(name, req->bufferSize - (requestSize - 1), - file->f_dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: build path failed\n")); - return -EINVAL; - } - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: opening \"%s\"\n", - name)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(name, - req->bufferSize - (requestSize - 1), - name); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: CP conversion failed\n")); - return -EINVAL; - } - - *nameLength = (uint32) result; - req->payloadSize = requestSize + result; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPrivateDirOpen -- - * - * Called by HgfsDirOpen() and HgfsReaddir() routines. - * - * Results: - * Returns zero if on success, error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPrivateDirOpen(struct file *file, // IN: File pointer for this open - HgfsHandle *handle) // IN: Hgfs handle -{ - HgfsReq *req; - int result; - HgfsOp opUsed; - HgfsStatus replyStatus; - HgfsHandle *replySearch; - - ASSERT(file); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionSearchOpen; - if (opUsed == HGFS_OP_SEARCH_OPEN_V3) { - replySearch = &((HgfsReplySearchOpenV3 *)HGFS_REP_PAYLOAD_V3(req))->search; - } else { - replySearch = &((HgfsReplySearchOpen *)HGFS_REQ_PAYLOAD(req))->search; - } - - result = HgfsPackDirOpenRequest(file, opUsed, req); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen error packing request\n")); - goto out; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply and check return status. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - /* Save the handle value */ - *handle = *replySearch; - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: Handle returned = %u\n", - *replySearch)); - break; - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_SEARCH_OPEN_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionSearchOpen = HGFS_OP_SEARCH_OPEN; - goto retry; - } - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: server " - "returned error: %d\n", result)); - break; - - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: server " - "returned error: %d\n", result)); - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirOpen: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPrivateDirRelease -- - * - * Called by HgfsDirRelease() and HgfsReaddir() routines. - * - * Results: - * Returns zero on success, or an error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPrivateDirRelease(struct file *file, // IN: File for the dir getting released - HgfsHandle handle) // IN: Hgfs handle -{ - HgfsReq *req; - HgfsStatus replyStatus; - HgfsOp opUsed; - int result = 0; - - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_sb); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: close fh %u\n", handle)); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionSearchClose; - if (opUsed == HGFS_OP_SEARCH_CLOSE_V3) { - HgfsRequestSearchCloseV3 *request; - HgfsRequest *header; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestSearchCloseV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->search = handle; - request->reserved = 0; - req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - } else { - HgfsRequestSearchClose *request; - - request = (HgfsRequestSearchClose *)(HGFS_REQ_PAYLOAD(req)); - request->header.id = req->id; - request->header.op = opUsed; - request->search = handle; - req->payloadSize = sizeof *request; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: release handle %u\n", - handle)); - break; - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_SEARCH_CLOSE_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionSearchClose = HGFS_OP_SEARCH_CLOSE; - goto retry; - } - break; - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: failed handle %u\n", - handle)); - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateDirRelease: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPrivateDirReOpen -- - * - * Reopens the file. Called by HgfsReaddir() routine. - * - * Results: - * Returns zero if on success, error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPrivateDirReOpen(struct file *file) // IN: File pointer for this open -{ - int result = 0; - HgfsHandle *handle = &FILE_GET_FI_P(file)->handle; - LOG(4, (KERN_DEBUG "HgfsPrivateDirReOpen: Directory handle in invalid;" - "Reopening ...\n")); - - result = HgfsPrivateDirRelease(file, *handle); - if (result) { - return result; - } - - result = HgfsPrivateDirOpen(file, handle); - if (result) { - return result; - } - - FILE_GET_FI_P(file)->isStale = FALSE; - - return result; -} - - -/* - * HGFS file operations for directories. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsDirLlseek -- - * - * Called whenever a process does rewinddir() or telldir()/seekdir(). - * - * Results: - * Returns zero if on success, error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static loff_t -HgfsDirLlseek(struct file *file, - loff_t offset, - int origin) -{ - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; - compat_mutex_t *mtx; - - LOG(4, (KERN_DEBUG "Got llseek call with origin = %d, offset = %u," - "pos = %u\n", origin, (uint32)offset, (uint32)file->f_pos)); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) - mtx = &inode->i_sem; -#else - mtx = &inode->i_mutex; -#endif - - compat_mutex_lock(mtx); - - switch(origin) { - - /* SEEK_CUR */ - case 1: offset += file->f_pos; - break; - /* SEEK_SET */ - case 0: break; - - /* SEEK_END */ - case 2: - default: offset = -EINVAL; - break; - } - - if (offset < 0) { - offset = -EINVAL; - goto out; - } - - if (offset != file->f_pos) { - file->f_pos = offset; - } - - /* - * rewinddir() semantics says that It causes the directory stream - * to refer to the current state of the corresponding directory, - * as a call to opendir would have done. So when rewinddir() happens, - * we mark current directory as stale, so that subsequent readdir() - * call will reopen() the directory. - * - * XXX telldir()/seekdir() semantics does not say that we need to refer - * to the current state of a directory. However, an application that does - * following: telldir() -> rmdir(current_entry) -> seekdir() and checking - * whether entry was deleted or not, will break. I have no evidence of an - * application relying on above behavior, so let's not incur extra cost - * by reopening directory on telldir()/seekdir() combination. Note: A special - * case of telldir()/seekdir() to offset 0 will behave same as rewinddir(). - */ - if (!file->f_pos) { - FILE_GET_FI_P(file)->isStale = TRUE; - } - -out: - compat_mutex_unlock(mtx); - return offset; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsDirOpen -- - * - * Called whenever a process opens a directory in our filesystem. - * - * We send a "Search Open" request to the server with the name - * stored in this file's inode. If the Open succeeds, we store the - * search handle sent by the server in the file struct so it can be - * accessed by readdir and close. - * - * Results: - * Returns zero if on success, error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsDirOpen(struct inode *inode, // IN: Inode of the dir to open - struct file *file) // IN: File pointer for this open -{ - int result; - - HgfsHandle handle; - - ASSERT(inode); - ASSERT(inode->i_sb); - ASSERT(file); - - result = HgfsPrivateDirOpen(file, &handle); - if (!result) { - result = HgfsCreateFileInfo(file, handle); - } - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsReaddirRefreshEntries -- - * - * refresh the file entries if the handle is stale by reopening. - * - * Results: - * Zero on success, otherwise failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsReaddirRefreshEntries(struct file *file) // IN: File pointer for this open -{ - int result = 0; - - /* - * rm -rf 6.10+ breaks because it does following: - * an 'fd = open()' on a directory, followed by unlinkat() - * which removes an entry from the directory it and then - * fdopendir(fd). We get a call on open() but not on fdopendir(), - * which means that we do not reflect the action of unlinkat(), - * and thus rm -rf gets confused and marking entry as unremovable. - * Note that this problem exists because hgfsServer reads all - * the directory entries at open(). Interested reader may look at - * coreutils/src/remove.c file. - * - * So as a workaround, we ask the server to populate entries on - * first readdir() call rather than opendir(). This effect is - * achieved by closing and reopening the directory. Grrr! - * - * XXX We should get rid of this code when/if we remove the above - * behavior from hgfsServer. - */ - if (FILE_GET_FI_P(file)->isStale) { - result = HgfsPrivateDirReOpen(file); - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: error: stale handle (%s) return %d)\n", - __func__, file->f_dentry->d_name.name, result)); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetFileInode -- - * - * Get file inode from the hgfs attributes or generate from the super block. - * - * Results: - * The inode entry. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static ino_t -HgfsGetFileInode(HgfsAttrInfo const *attr, // IN: Attrs to use - struct super_block *sb) // IN: Superblock of this fs -{ - ino_t inodeEntry; - uint64 tempIno; - HgfsSuperInfo *si; - - ASSERT(attr); - ASSERT(sb); - - si = HGFS_SB_TO_COMMON(sb); - - if ((si->mntFlags & HGFS_MNT_SERVER_INUM) != 0 && - (attr->mask & HGFS_ATTR_VALID_FILEID) != 0) { - tempIno = attr->hostFileId; - } else { - tempIno = iunique(sb, HGFS_RESERVED_INO); - } - - inodeEntry = HgfsUniqueidToIno(tempIno); - LOG(4, (KERN_DEBUG "VMware hgfs: %s: return %lu\n", __func__, inodeEntry)); - return inodeEntry; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetFileType -- - * - * Get file type according to the hgfs attributes. - * - * Results: - * The file type. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static uint32 -HgfsGetFileType(HgfsAttrInfo const *attr) // IN: Attrs to use -{ - uint32 type; - - ASSERT(attr); - - switch (attr->type) { - case HGFS_FILE_TYPE_SYMLINK: - type = DT_LNK; - break; - - case HGFS_FILE_TYPE_REGULAR: - type = DT_REG; - break; - - case HGFS_FILE_TYPE_DIRECTORY: - type = DT_DIR; - break; - - default: - /* - * XXX Should never happen. I'd put NOT_IMPLEMENTED() here - * but if the driver ever goes in the host it's probably not - * a good idea for an attacker to be able to hang the host - * simply by using a bogus file type in a reply. [bac] - * - * Well it happens! Refer bug 548177 for details. In short, - * when the user deletes a share, we hit this code path. - * - */ - type = DT_UNKNOWN; - break; - } - - LOG(4, (KERN_DEBUG "VMware hgfs: %s: return %d\n", __func__, type)); - return type; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsReaddirNextEntry -- - * - * Called whenever a process opens a directory in our filesystem. - * - * We send a "Search Open" request to the server with the name - * stored in this file's inode. If the Open succeeds, we store the - * search handle sent by the server in the file struct so it can be - * accessed by readdir and close. - * - * Results: - * Returns zero if on success, error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsReaddirNextEntry(struct file *file, // IN: file - loff_t entryPos, // IN: position - Bool dotAndDotDotIgnore, // IN: ignore "." and ".." - size_t entryNameBufLen, // IN: name buffer length - char *entryName, // OUT: entry name - uint32 *entryNameLength, // OUT: max name length - ino_t *entryIno, // OUT: inode entry number - uint32 *entryType, // OUT: entry type - Bool *entryIgnore, // OUT: ignore this entry or not - Bool *entryEnd) // OUT: no more entries -{ - HgfsSuperInfo *si; - HgfsAttrInfo entryAttrs; - char *fileName = NULL; - int result; - - ASSERT(file->f_dentry->d_inode->i_sb); - - si = HGFS_SB_TO_COMMON(file->f_dentry->d_inode->i_sb); - *entryIgnore = FALSE; - - /* - * Nonzero result = we failed to get valid reply from server. - * Zero result: - * - done == TRUE means we hit the end of the directory - * - Otherwise, fileName has the name of the next dirent - * - */ - - result = HgfsGetNextDirEntry(si, - FILE_GET_FI_P(file)->handle, - (uint32)entryPos, - &entryAttrs, - &fileName, - entryEnd); - if (result == -ENAMETOOLONG) { - /* - * Skip dentry if its name is too long (see below). - * - * XXX: If a bad server sends us bad packets, we can loop here - * forever, as I did while testing *grumble*. Maybe we should error - * in that case. - */ - LOG(4, (KERN_DEBUG "VMware hgfs: %s: error getnextdentry name %d\n", - __func__, result)); - *entryIgnore = TRUE; - result = 0; - goto exit; - } else if (result) { - /* Error */ - LOG(4, (KERN_DEBUG "VMware hgfs: %s: error getnextdentry %d\n", - __func__, result)); - goto exit; - } - - if (*entryEnd) { - LOG(10, (KERN_DEBUG "VMware hgfs: %s: end of dir reached\n", __func__)); - goto exit; - } - - /* - * Escape all non-printable characters (which for linux is just - * "/"). - * - * Note that normally we would first need to convert from the - * CP name format, but that is done implicitely here since we - * are guaranteed to have just one path component per dentry. - */ - result = HgfsEscape_Do(fileName, strlen(fileName), - entryNameBufLen, entryName); - kfree(fileName); - fileName = NULL; - - /* - * Check the filename length. - * - * If the name is too long to be represented in linux, we simply - * skip it (i.e., that file is not visible to our filesystem). - * - * HgfsEscape_Do returns a negative value if the escaped - * output didn't fit in the specified output size, so we can - * just check its return value. - */ - if (result < 0) { - /* - * XXX: Another area where a bad server could cause us to loop - * forever. - */ - *entryIgnore = TRUE; - result = 0; - goto exit; - } - - *entryNameLength = result; - result = 0; - - /* - * It is unfortunate, but the HGFS server sends back '.' and ".." - * when we do a SearchRead. In an ideal world, these would be faked - * on the client, but it would be a real backwards-compatibility - * hassle to change the behavior at this point. - * - * So instead, we'll take the '.' and ".." and modify their inode - * numbers so they match what the client expects. - */ - if (!strncmp(entryName, ".", sizeof ".")) { - if (!dotAndDotDotIgnore) { - *entryIno = file->f_dentry->d_inode->i_ino; - } else { - *entryIgnore = TRUE; - } - } else if (!strncmp(entryName, "..", sizeof "..")) { - if (!dotAndDotDotIgnore) { - *entryIno = compat_parent_ino(file->f_dentry); - } else { - *entryIgnore = TRUE; - } - } else { - *entryIno = HgfsGetFileInode(&entryAttrs, file->f_dentry->d_inode->i_sb); - } - - if (*entryIgnore) { - goto exit; - } - - /* Assign the correct dentry type. */ - *entryType = HgfsGetFileType(&entryAttrs); - -exit: - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsDoReaddir -- - * - * Handle a readdir request. See details below if interested. - * - * Readdir is a bit complicated, and is best understood by reading - * the code. For the impatient, here is an overview of the major - * moving parts [bac]: - * - * - Getdents syscall calls readdir, which is supposed to call - * filldir some number of times. - * - Each time it's called, filldir updates a struct with the - * number of bytes copied thus far, and sets an error code if - * appropriate. - * - When readdir returns, getdents checks the struct to see if - * any dentries were copied, and if so returns the byte count. - * Otherwise, it returns the error from the struct (which should - * still be zero if filldir was never called). - * - * A consequence of this last fact is that if there are no more - * dentries, then readdir should NOT call filldir, and should - * return from readdir with a non-error. - * - * Other notes: - * - * - Passing an inum of zero to filldir doesn't work. At a minimum, - * you have to make up a bogus inum for each dentry. - * - Passing the correct entryType to filldir seems to be non-critical; - * apparently most programs (such as ls) stat each file if they - * really want to know what type it is. However, passing the - * correct type means that ls doesn't bother calling stat on - * directories, and that saves an entire round trip per dirctory - * dentry. - * - * Results: - * Returns zero if on success, negative error on failure. - * (According to /fs/readdir.c, any non-negative return value - * means it succeeded). - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsDoReaddir(struct file *file, // IN: - Bool dotAndDotDotIgnore, // IN: ignore "." and ".." - filldir_t filldirCb, // IN: system filler callback - void *filldirCtx, // IN/OUT: system filler context - loff_t *fillPos, // IN/OUT: fill entry position - loff_t *currentPos) // IN/OUT: current position -{ - char *entryName = NULL; // buf for escaped version of name - size_t entryNameBufLen = NAME_MAX + 1; - int entryNameLength = 0; - int result = 0; - Bool entryEnd = FALSE; - - ASSERT(file); - ASSERT(filldirCtx); - - if (!file || - !(file->f_dentry) || - !(file->f_dentry->d_inode)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsReaddir: null input\n")); - return -EFAULT; - } - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s, inum %lu, pos %Lu)\n", - __func__, - file->f_dentry->d_name.name, - file->f_dentry->d_inode->i_ino, - *currentPos)); - - /* - * Refresh entries if required. See rm -rf 6.10+ breaking issue. - */ - result = HgfsReaddirRefreshEntries(file); - if (result != 0) { - return result; - } - - /* - * Some day when we're out of things to do we can move this to a slab - * allocator. - */ - entryName = kmalloc(entryNameBufLen, GFP_KERNEL); - if (entryName == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsReaddir: out of memory allocating " - "escaped name buffer\n")); - return -ENOMEM; - } - - while (!entryEnd) { - Bool entryIgnore; - ino_t entryIno = 0; - uint32 entryType = DT_UNKNOWN; - - result = HgfsReaddirNextEntry(file, - *currentPos, - dotAndDotDotIgnore, - entryNameBufLen, - entryName, - &entryNameLength, - &entryIno, - &entryType, - &entryIgnore, - &entryEnd); - - if (result != 0) { - /* An error occurred retrieving the entry, so exit. */ - break; - } - - if (entryEnd) { - LOG(10, (KERN_DEBUG "VMware hgfs: %s: end of dir reached\n", __func__)); - continue; - } - - if (entryIgnore) { - *currentPos += 1; - continue; - } - - /* - * Call the HGFS wrapper to the system fill function to set this dentry. - */ - LOG(6, (KERN_DEBUG "VMware hgfs: %s: dir_emit(%s, %u, @ (fill %Lu HGFS %Lu)\n", - __func__, entryName, entryNameLength, *fillPos, *currentPos)); - if (!HgfsReaddirFillEntry(filldirCb, /* filldir callback function */ - filldirCtx, /* filldir callback struct */ - entryName, /* name of dirent */ - entryNameLength, /* length of name */ - *fillPos, /* fill entry position */ - entryIno, /* inode number (0 makes it not show) */ - entryType)) { /* type of dirent */ - /* - * This means that dir_emit ran out of room in the user buffer - * it was copying into; we just break out and return, but - * don't increment f_pos. So the next time the user calls - * getdents, this dentry will be requested again, will get - * retrieved again, and get copied properly to the user. - */ - result = 0; - break; - } - *currentPos += 1; - *fillPos += 1; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: return\n",__func__)); - kfree(entryName); - return 0; -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) -/* - *---------------------------------------------------------------------- - * - * HgfsReaddir -- - * - * Handle a readdir request. - * - * Results: - * Returns zero on success, or an error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsReaddir(struct file *file, // IN: - struct dir_context *ctx) // IN: -{ - HgfsFileInfo *fInfo = FILE_GET_FI_P(file); - - if (0 == ctx->pos) { - fInfo->direntPos = 0; - } - - /* If either dot and dotdot are filled in for us we can exit. */ - if (!dir_emit_dots(file, ctx)) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: dir_emit_dots(%s, @ %Lu)\n", - __func__, file->f_dentry->d_name.name, ctx->pos)); - return 0; - } - - /* It is sufficient to pass the context as it contains the filler function. */ - return HgfsDoReaddir(file, TRUE, NULL, ctx, &ctx->pos, &fInfo->direntPos); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsReaddirFillEntry -- - * - * Fill a readdir entry. - * - * Failure means that fill ran out of room in the user buffer - * it was copying into. - * - * Results: - * Returns TRUE on success, or FALSE on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsReaddirFillEntry(filldir_t filldirCb, // IN: System filler callback - void *filldirCtx, // IN/OUT: System filler context - char *entryName, // IN: entry name - uint32 entryNameLength, // IN: max name length - loff_t entryPos, // IN: position = (ctx-pos) - ino_t entryIno, // IN: inode entry number - uint32 entryType) // IN: entry type -{ - struct dir_context *ctx = filldirCtx; - Bool result; - - ASSERT(filldirCb == NULL); /* Contained within the context structure. */ - ASSERT(ctx != NULL); - ASSERT(ctx->pos == entryPos); - ASSERT(entryName != NULL); - ASSERT(entryNameLength != 0); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: dir_emit(%s, %u, %Lu)\n", - __func__, entryName, entryNameLength, ctx->pos)); - - result = dir_emit(ctx, /* filldir callback struct */ - entryName, /* name of dirent */ - entryNameLength, /* length of name */ - entryIno, /* inode number (0 makes it not show) */ - entryType); /* type of dirent */ - return result; -} -#else - - -/* - *---------------------------------------------------------------------- - * - * HgfsReaddir -- - * - * Handle a readdir request. - * - * Results: - * Returns zero on success, or an error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsReaddir(struct file *file, // IN: Directory to read from - void *dirent, // OUT: Buffer to copy dentries into - filldir_t filldir) // IN: Filler function -{ - HgfsFileInfo *fInfo = FILE_GET_FI_P(file); - - if (0 == file->f_pos) { - fInfo->direntPos = 0; - } - - return HgfsDoReaddir(file, FALSE, filldir, dirent, &file->f_pos, &fInfo->direntPos); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsReaddirFillEntry -- - * - * Fill a readdir entry. - * - * Failure means that fill ran out of room in the user buffer - * it was copying into. - * - * Results: - * Returns TRUE on success, or FALSE on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsReaddirFillEntry(filldir_t filldirCb, // IN: System filler callback - void *filldirCtx, // IN/OUT: System filler context - char *entryName, // IN: entry name - uint32 entryNameLength, // IN: max name length - loff_t entryPos, // IN: position - ino_t entryIno, // IN: inode entry number - uint32 entryType) // IN: entry type -{ - Bool result = TRUE; - int fillResult; - - ASSERT(filldirCb != NULL); - ASSERT(filldirCtx != NULL); - ASSERT(entryName != NULL); - ASSERT(entryNameLength != 0); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling filldir(%s, %u, %Lu\n", - __func__, entryName, entryNameLength, entryPos)); - - fillResult = filldirCb(filldirCtx, /* filldir callback struct */ - entryName, /* name of dirent */ - entryNameLength, /* length of name */ - entryPos, /* offset of dirent */ - entryIno, /* inode number (0 makes it not show) */ - entryType); /* type of dirent */ - - if (fillResult != 0) { - result = FALSE; - } - LOG(6, (KERN_DEBUG "VMware hgfs: %s: return %d\n", __func__, result)); - return result; -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * HgfsDirRelease -- - * - * Called when the last reader of a directory closes it, i.e. when - * the directory's file f_count field becomes zero. - * - * Results: - * Returns zero on success, or an error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsDirRelease(struct inode *inode, // IN: Inode that the file* points to - struct file *file) // IN: File for the dir getting released -{ - HgfsHandle handle; - - ASSERT(inode); - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_sb); - - handle = FILE_GET_FI_P(file)->handle; - - HgfsReleaseFileInfo(file); - - return HgfsPrivateDirRelease(file, handle); -} diff --git a/open-vm-tools/modules/linux/vmhgfs/file.c b/open-vm-tools/modules/linux/vmhgfs/file.c deleted file mode 100644 index 073f2848e..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/file.c +++ /dev/null @@ -1,1550 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * file.c -- - * - * File operations for the filesystem portion of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) -#include /* iov_iter_count */ -#endif -#include "compat_cred.h" -#include "compat_fs.h" -#include "compat_kernel.h" -#include "compat_slab.h" - -/* Must be after compat_fs.h */ -#if defined VMW_USE_AIO -#include -#endif - -#include "cpName.h" -#include "hgfsProto.h" -#include "module.h" -#include "request.h" -#include "hgfsUtil.h" -#include "fsutil.h" -#include "vm_assert.h" -#include "vm_basic_types.h" - -/* - * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using - * the O_SYNC flag. We continue to use the existing numerical value - * for O_DSYNC semantics now, but using the correct symbolic name for it. - * This new value is used to request true Posix O_SYNC semantics. It is - * defined in this strange way to make sure applications compiled against - * new headers get at least O_DSYNC semantics on older kernels. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) -#define HGFS_FILECTL_SYNC(flags) ((flags) & O_DSYNC) -#else -#define HGFS_FILECTL_SYNC(flags) ((flags) & O_SYNC) -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -typedef struct iov_iter *hgfs_iov; -#define HGFS_IOV_TO_COUNT(iov, nr_segs) (iov_iter_count(iov)) -#define HGFS_IOV_TO_SEGS(iov, nr_segs) (0) -#define HGFS_IOCB_TO_POS(iocb, pos) (iocb->ki_pos) -#else -typedef const struct iovec *hgfs_iov; -#define HGFS_IOV_TO_COUNT(iov, nr_segs) (iov_length(iov, nr_segs)) -#define HGFS_IOV_TO_SEGS(iov, nr_segs) (nr_segs) -#define HGFS_IOCB_TO_POS(iocb, pos) (pos) -#endif - -/* Private functions. */ -static int HgfsPackOpenRequest(struct inode *inode, - struct file *file, - HgfsOp opUsed, - HgfsReq *req); -static int HgfsUnpackOpenReply(HgfsReq *req, - HgfsOp opUsed, - HgfsHandle *file, - HgfsLockType *lock); - -/* HGFS file operations for files. */ -static int HgfsOpen(struct inode *inode, - struct file *file); -#if defined VMW_USE_AIO -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -static ssize_t HgfsFileRead(struct kiocb *iocb, - struct iov_iter *to); -static ssize_t HgfsFileWrite(struct kiocb *iocb, - struct iov_iter *from); -#else // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -static ssize_t HgfsFileRead(struct kiocb *iocb, - const struct iovec *iov, - unsigned long numSegs, - loff_t offset); -static ssize_t HgfsFileWrite(struct kiocb *iocb, - const struct iovec *iov, - unsigned long numSegs, - loff_t offset); -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -#else -static ssize_t HgfsRead(struct file *file, - char __user *buf, - size_t count, - loff_t *offset); -static ssize_t HgfsWrite(struct file *file, - const char __user *buf, - size_t count, - loff_t *offset); -#endif - -static loff_t HgfsSeek(struct file *file, - loff_t offset, - int origin); -static int HgfsFlush(struct file *file -#if !defined VMW_FLUSH_HAS_1_ARG - ,fl_owner_t id -#endif - ); - -#if !defined VMW_FSYNC_31 -static int HgfsDoFsync(struct inode *inode); -#endif - -static int HgfsFsync(struct file *file, -#if defined VMW_FSYNC_OLD - struct dentry *dentry, -#elif defined VMW_FSYNC_31 - loff_t start, - loff_t end, -#endif - int datasync); -static int HgfsMmap(struct file *file, - struct vm_area_struct *vma); -static int HgfsRelease(struct inode *inode, - struct file *file); - -#ifndef VMW_SENDFILE_NONE -#if defined VMW_SENDFILE_OLD -static ssize_t HgfsSendfile(struct file *file, - loff_t *offset, - size_t count, - read_actor_t actor, - void __user *target); -#else /* defined VMW_SENDFILE_NEW */ -static ssize_t HgfsSendfile(struct file *file, - loff_t *offset, - size_t count, - read_actor_t actor, - void *target); -#endif -#endif -#ifdef VMW_SPLICE_READ -static ssize_t HgfsSpliceRead(struct file *file, - loff_t *offset, - struct pipe_inode_info *pipe, - size_t len, - unsigned int flags); -#endif - -/* HGFS file operations structure for files. */ -struct file_operations HgfsFileFileOperations = { - .owner = THIS_MODULE, - .open = HgfsOpen, - .llseek = HgfsSeek, - .flush = HgfsFlush, -#if defined VMW_USE_AIO -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) - /* Fallback to async counterpart, check kernel source read_write.c */ - .read = NULL, - .write = NULL, - .read_iter = HgfsFileRead, - .write_iter = HgfsFileWrite, -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) - .read = new_sync_read, - .write = new_sync_write, - .read_iter = HgfsFileRead, - .write_iter = HgfsFileWrite, -#else // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) - .read = do_sync_read, - .write = do_sync_write, - .aio_read = HgfsFileRead, - .aio_write = HgfsFileWrite, -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -#else - .read = HgfsRead, - .write = HgfsWrite, -#endif - .fsync = HgfsFsync, - .mmap = HgfsMmap, - .release = HgfsRelease, -#ifndef VMW_SENDFILE_NONE - .sendfile = HgfsSendfile, -#endif -#ifdef VMW_SPLICE_READ - .splice_read = HgfsSpliceRead, -#endif -}; - -/* File open mask. */ -#define HGFS_FILE_OPEN_MASK (HGFS_OPEN_VALID_MODE | \ - HGFS_OPEN_VALID_FLAGS | \ - HGFS_OPEN_VALID_SPECIAL_PERMS | \ - HGFS_OPEN_VALID_OWNER_PERMS | \ - HGFS_OPEN_VALID_GROUP_PERMS | \ - HGFS_OPEN_VALID_OTHER_PERMS | \ - HGFS_OPEN_VALID_FILE_NAME | \ - HGFS_OPEN_VALID_SERVER_LOCK) - - -/* - * Private functions. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsPackOpenRequest -- - * - * Setup the Open request, depending on the op version. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackOpenRequest(struct inode *inode, // IN: Inode of the file to open - struct file *file, // IN: File pointer for this open - HgfsOp opUsed, // IN: Op to use - HgfsReq *req) // IN/OUT: Packet to write into -{ - char *name; - uint32 *nameLength; - size_t requestSize; - int result; - - ASSERT(inode); - ASSERT(file); - ASSERT(req); - - switch (opUsed) { - case HGFS_OP_OPEN_V3: { - HgfsRequest *requestHeader; - HgfsRequestOpenV3 *requestV3; - - requestHeader = (HgfsRequest *)HGFS_REQ_PAYLOAD(req); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestOpenV3 *)HGFS_REQ_PAYLOAD_V3(req); - requestSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - - /* We'll use these later. */ - name = requestV3->fileName.name; - nameLength = &requestV3->fileName.length; - - requestV3->mask = HGFS_FILE_OPEN_MASK; - - /* Linux clients need case-sensitive lookups. */ - requestV3->fileName.flags = 0; - requestV3->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - requestV3->fileName.fid = HGFS_INVALID_HANDLE; - - /* Set mode. */ - result = HgfsGetOpenMode(file->f_flags); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: failed to get " - "open mode\n")); - return -EINVAL; - } - requestV3->mode = result; - - /* Set flags. */ - result = HgfsGetOpenFlags(file->f_flags); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: failed to get " - "open flags\n")); - return -EINVAL; - } - requestV3->flags = result; - - LOG(4, (KERN_DEBUG "VMware hgfs: %s: mode file %o inode %o -> user %o\n", - __func__, file->f_mode, inode->i_mode, (inode->i_mode & S_IRWXU) >> 6)); - /* Set permissions. */ - requestV3->specialPerms = (inode->i_mode & (S_ISUID | S_ISGID | S_ISVTX)) - >> 9; - requestV3->ownerPerms = (inode->i_mode & S_IRWXU) >> 6; - requestV3->groupPerms = (inode->i_mode & S_IRWXG) >> 3; - requestV3->otherPerms = (inode->i_mode & S_IRWXO); - - /* XXX: Request no lock for now. */ - requestV3->desiredLock = HGFS_LOCK_NONE; - - requestV3->reserved1 = 0; - requestV3->reserved2 = 0; - break; - } - - case HGFS_OP_OPEN_V2: { - HgfsRequestOpenV2 *requestV2; - - requestV2 = (HgfsRequestOpenV2 *)(HGFS_REQ_PAYLOAD(req)); - requestV2->header.op = opUsed; - requestV2->header.id = req->id; - - /* We'll use these later. */ - name = requestV2->fileName.name; - nameLength = &requestV2->fileName.length; - requestSize = sizeof *requestV2; - - requestV2->mask = HGFS_FILE_OPEN_MASK; - - /* Set mode. */ - result = HgfsGetOpenMode(file->f_flags); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: failed to get " - "open mode\n")); - return -EINVAL; - } - requestV2->mode = result; - - /* Set flags. */ - result = HgfsGetOpenFlags(file->f_flags); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: failed to get " - "open flags\n")); - return -EINVAL; - } - requestV2->flags = result; - - /* Set permissions. */ - requestV2->specialPerms = (inode->i_mode & (S_ISUID | S_ISGID | S_ISVTX)) - >> 9; - requestV2->ownerPerms = (inode->i_mode & S_IRWXU) >> 6; - requestV2->groupPerms = (inode->i_mode & S_IRWXG) >> 3; - requestV2->otherPerms = (inode->i_mode & S_IRWXO); - - /* XXX: Request no lock for now. */ - requestV2->desiredLock = HGFS_LOCK_NONE; - break; - } - case HGFS_OP_OPEN: { - HgfsRequestOpen *request; - - request = (HgfsRequestOpen *)(HGFS_REQ_PAYLOAD(req)); - request->header.op = opUsed; - request->header.id = req->id; - - /* We'll use these later. */ - name = request->fileName.name; - nameLength = &request->fileName.length; - requestSize = sizeof *request; - - /* Set mode. */ - result = HgfsGetOpenMode(file->f_flags); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: failed to get " - "open mode\n")); - return -EINVAL; - } - request->mode = result; - - /* Set flags. */ - result = HgfsGetOpenFlags(file->f_flags); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: failed to get " - "open flags\n")); - return -EINVAL; - } - request->flags = result; - - /* Set permissions. */ - request->permissions = (inode->i_mode & S_IRWXU) >> 6; - break; - } - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - /* Build full name to send to server. */ - if (HgfsBuildPath(name, - req->bufferSize - (requestSize - 1), - file->f_dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: build path " - "failed\n")); - return -EINVAL; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: opening \"%s\", " - "flags %o, create perms %o\n", name, - file->f_flags, file->f_mode)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(name, - req->bufferSize - (requestSize - 1), - name); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: CP conversion " - "failed\n")); - return -EINVAL; - } - - *nameLength = (uint32) result; - req->payloadSize = requestSize + result; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsUnpackOpenReply -- - * - * Get interesting fields out of the Open reply, depending on the op - * version. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsUnpackOpenReply(HgfsReq *req, // IN: Packet with reply inside - HgfsOp opUsed, // IN: What request op did we send - HgfsHandle *file, // OUT: Handle in reply packet - HgfsLockType *lock) // OUT: The server lock we got -{ - HgfsReplyOpenV3 *replyV3; - HgfsReplyOpenV2 *replyV2; - HgfsReplyOpen *replyV1; - size_t replySize; - - ASSERT(req); - ASSERT(file); - ASSERT(lock); - - switch (opUsed) { - case HGFS_OP_OPEN_V3: - replyV3 = (HgfsReplyOpenV3 *)HGFS_REP_PAYLOAD_V3(req); - replySize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3); - *file = replyV3->file; - *lock = replyV3->acquiredLock; - break; - case HGFS_OP_OPEN_V2: - replyV2 = (HgfsReplyOpenV2 *)(HGFS_REQ_PAYLOAD(req)); - replySize = sizeof *replyV2; - *file = replyV2->file; - *lock = replyV2->acquiredLock; - break; - case HGFS_OP_OPEN: - replyV1 = (HgfsReplyOpen *)(HGFS_REQ_PAYLOAD(req)); - replySize = sizeof *replyV1; - *file = replyV1->file; - *lock = HGFS_LOCK_NONE; - break; - default: - - /* This really shouldn't happen since we set opUsed ourselves. */ - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackOpenReply: unexpected " - "OP type encountered\n")); - ASSERT(FALSE); - return -EPROTO; - } - - if (req->payloadSize != replySize) { - /* - * The reply to Open is a fixed size. So the size of the payload - * really ought to match the expected size of an HgfsReplyOpen[V2]. - */ - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackOpenReply: wrong packet " - "size\n")); - return -EPROTO; - } - return 0; -} - - -/* - * HGFS file operations for files. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsOpen -- - * - * Called whenever a process opens a file in our filesystem. - * - * We send an "Open" request to the server with the name stored in - * this file's inode. If the Open succeeds, we store the filehandle - * sent by the server in the file struct so it can be accessed by - * read/write/close. - * - * Results: - * Returns zero if on success, error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsOpen(struct inode *inode, // IN: Inode of the file to open - struct file *file) // IN: File pointer for this open -{ - HgfsReq *req; - HgfsOp opUsed; - HgfsStatus replyStatus; - HgfsHandle replyFile; - HgfsLockType replyLock; - HgfsInodeInfo *iinfo; - int result = 0; - - ASSERT(inode); - ASSERT(inode->i_sb); - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_inode); - - iinfo = INODE_GET_II_P(inode); - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name)); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - /* - * Set up pointers using the proper struct This lets us check the - * version exactly once and use the pointers later. - */ - - opUsed = hgfsVersionOpen; - result = HgfsPackOpenRequest(inode, file, opUsed, req); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: error packing request\n")); - goto out; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply and check return status. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - iinfo->createdAndUnopened = FALSE; - LOG(10, (KERN_DEBUG "VMware hgfs: HgfsOpen: old hostFileId = " - "%"FMT64"u\n", iinfo->hostFileId)); - /* - * Invalidate the hostFileId as we need to retrieve it from - * the server. - */ - iinfo->hostFileId = 0; - result = HgfsUnpackOpenReply(req, opUsed, &replyFile, &replyLock); - if (result != 0) { - break; - } - result = HgfsCreateFileInfo(file, replyFile); - if (result != 0) { - break; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsOpen: set handle to %u\n", - replyFile)); - - /* - * HgfsCreate faked all of the inode's attributes, so by the time - * we're done in HgfsOpen, we need to make sure that the attributes - * in the inode are real. The following is only necessary when - * O_CREAT is set, otherwise we got here after HgfsLookup (which sent - * a getattr to the server and got the real attributes). - * - * In particular, we'd like to at least try and set the inode's - * uid/gid to match the caller's. We don't expect this to work, - * because Windows servers will ignore it, and Linux servers running - * as non-root won't be able to change it, but we're forward thinking - * people. - * - * Either way, we force a revalidate following the setattr so that - * we'll get the actual uid/gid from the server. - */ - if (file->f_flags & O_CREAT) { - struct dentry *dparent; - struct inode *iparent; - - /* - * This is not the root of our file system so there should always - * be a parent. - */ - ASSERT(file->f_dentry->d_parent); - - /* - * Here we obtain a reference on the parent to make sure it doesn't - * go away. This might not be necessary, since the existence of - * a child (which we hold a reference to in this call) should - * account for a reference in the parent, but it's safe to do so. - * Overly cautious and safe is better than risky and broken. - * - * XXX Note that this and a handful of other hacks wouldn't be - * necessary if we actually created the file in our create - * implementation (where references and locks are properly held). - * We could do this if we were willing to give up support for - * O_EXCL on 2.4 kernels. - */ - dparent = dget(file->f_dentry->d_parent); - iparent = dparent->d_inode; - - HgfsSetUidGid(iparent, file->f_dentry, - current_fsuid(), current_fsgid()); - - dput(dparent); - } - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_OPEN_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: Version 3 not " - "supported. Falling back to version 2.\n")); - hgfsVersionOpen = HGFS_OP_OPEN_V2; - goto retry; - } - - /* Retry with Version 1 of Open. Set globally. */ - if (opUsed == HGFS_OP_OPEN_V2) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: Version 2 not " - "supported. Falling back to version 1.\n")); - hgfsVersionOpen = HGFS_OP_OPEN; - goto retry; - } - - /* Fallthrough. */ - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: unknown error: " - "%d\n", result)); - } -out: - HgfsFreeRequest(req); - - /* - * If the open failed (for any reason) and we tried to open a newly created - * file, we must ensure that the next operation on this inode triggers a - * revalidate to the server. This is because the file wasn't created on the - * server, yet we currently believe that it was, because we created a fake - * inode with a hashed dentry for it in HgfsCreate. We will continue to - * believe this until the dentry's ttl expires, which will cause a - * revalidate to the server that will reveal the truth. So in order to find - * the truth as soon as possible, we'll reset the dentry's last revalidate - * time now to force a revalidate the next time someone uses the dentry. - * - * We're using our own flag to track this case because using O_CREAT isn't - * good enough: HgfsOpen will be called with O_CREAT even if the file exists - * on the server, and if that's the case, there's no need to revalidate. - * - * XXX: Note that this will need to be reworked if/when we support hard - * links, because multiple dentries will point to the same inode, and - * forcing a revalidate on one will not force it on any others. - */ - if (result != 0 && iinfo->createdAndUnopened == TRUE) { - HgfsDentryAgeForce(file->f_dentry); - } - return result; -} - - -#if defined VMW_USE_AIO -/* - *---------------------------------------------------------------------- - * - * HgfsGenericFileRead -- - * - * Called when the kernel initiates an asynchronous read from a file in - * our filesystem. Our function is just a thin wrapper around - * system generic read function. - * - * - * Results: - * Returns the number of bytes read on success, or an error on - * failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static ssize_t -HgfsGenericFileRead(struct kiocb *iocb, // IN: I/O control block - hgfs_iov iov, // IN: Array of I/O vectors - unsigned long iovSegs, // IN: Count of I/O vectors - loff_t pos) // IN: Position at which to read -{ - ssize_t result; - - LOG(8, (KERN_DEBUG "VMware hgfs: %s(%lu@%Ld)\n", - __func__, (unsigned long)HGFS_IOV_TO_COUNT(iov, iovSegs), - (long long) pos)); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) - result = generic_file_read_iter(iocb, iov); -#else - result = generic_file_aio_read(iocb, iov, iovSegs, pos); -#endif - - LOG(8, (KERN_DEBUG "VMware hgfs: %s return %"FMTSZ"d\n", - __func__, result)); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsFileRead -- - * - * Called when the kernel initiates an asynchronous read to a file in - * our filesystem. Our function is just a thin wrapper around - * generic_file_aio_read() that tries to validate the dentry first. - * - * Results: - * Returns the number of bytes read on success, or an error on - * failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -static ssize_t -HgfsFileRead(struct kiocb *iocb, // IN: I/O control block - struct iov_iter *iov) // OUT: Array of I/O buffers -#else // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -static ssize_t -HgfsFileRead(struct kiocb *iocb, // IN: I/O control block - const struct iovec *iov, // OUT: Array of I/O buffers - unsigned long numSegs, // IN: Number of buffers - loff_t offset) // IN: Offset at which to read -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -{ - ssize_t result; - struct dentry *readDentry; - loff_t pos; - unsigned long iovSegs; - - ASSERT(iocb); - ASSERT(iocb->ki_filp); - ASSERT(iocb->ki_filp->f_dentry); - ASSERT(iov); - - pos = HGFS_IOCB_TO_POS(iocb, offset); - iovSegs = HGFS_IOV_TO_SEGS(iov, numSegs); - - readDentry = iocb->ki_filp->f_dentry; - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", - __func__, readDentry->d_parent->d_name.name, - readDentry->d_name.name)); - - result = HgfsRevalidate(readDentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); - goto out; - } - - result = HgfsGenericFileRead(iocb, iov, iovSegs, pos); - -out: - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGenericFileWrite -- - * - * Called when the kernel initiates an asynchronous write to a file in - * our filesystem. Our function is just a thin wrapper around - * system generic write function. - * - * - * Results: - * Returns the number of bytes written on success, or an error on - * failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static ssize_t -HgfsGenericFileWrite(struct kiocb *iocb, // IN: I/O control block - hgfs_iov iov, // IN: Array of I/O vectors - unsigned long iovSegs, // IN: Count of I/O vectors - loff_t pos) // IN: Position at which to write -{ - ssize_t result; - - LOG(8, (KERN_DEBUG "VMware hgfs: %s(%lu@%Ld)\n", - __func__, (unsigned long)HGFS_IOV_TO_COUNT(iov, iovSegs), - (long long) pos)); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) - result = generic_file_write_iter(iocb, iov); -#else - result = generic_file_aio_write(iocb, iov, iovSegs, pos); -#endif - - LOG(8, (KERN_DEBUG "VMware hgfs: %s return %"FMTSZ"d\n", - __func__, result)); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsFileWrite -- - * - * Called when the kernel initiates an asynchronous write to a file in - * our filesystem. Our function is just a thin wrapper around - * generic_file_aio_write() that tries to validate the dentry first. - * - * Note that files opened with O_SYNC (or superblocks mounted with - * "sync") are synchronously written to by the VFS. - * - * Results: - * Returns the number of bytes written on success, or an error on - * failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -ssize_t -HgfsFileWrite(struct kiocb *iocb, // IN: I/O control block - struct iov_iter *iov) // IN: Array of I/O buffers -#else // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -static ssize_t -HgfsFileWrite(struct kiocb *iocb, // IN: I/O control block - const struct iovec *iov, // IN: Array of I/O buffers - unsigned long numSegs, // IN: Number of buffers - loff_t offset) // IN: Offset at which to write -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -{ - ssize_t result; - struct dentry *writeDentry; - HgfsInodeInfo *iinfo; - loff_t pos; - unsigned long iovSegs; - - ASSERT(iocb); - ASSERT(iocb->ki_filp); - ASSERT(iocb->ki_filp->f_dentry); - ASSERT(iov); - - pos = HGFS_IOCB_TO_POS(iocb, offset); - iovSegs = HGFS_IOV_TO_SEGS(iov, numSegs); - - writeDentry = iocb->ki_filp->f_dentry; - iinfo = INODE_GET_II_P(writeDentry->d_inode); - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", - __func__, writeDentry->d_parent->d_name.name, - writeDentry->d_name.name)); - - - spin_lock(&writeDentry->d_inode->i_lock); - /* - * Guard against dentry revalidation invalidating the inode underneath us. - * - * Data is being written and may have valid data in a page in the cache. - * This action prevents any invalidating of the inode when a flushing of - * cache data occurs prior to syncing the file with the server's attributes. - * The flushing of cache data would empty our in memory write pages list and - * would cause the inode modified write time to be updated and so the inode - * would also be invalidated. - */ - iinfo->numWbPages++; - spin_unlock(&writeDentry->d_inode->i_lock); - - result = HgfsRevalidate(writeDentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); - goto out; - } - - result = HgfsGenericFileWrite(iocb, iov, iovSegs, pos); - - if (result >= 0) { - if (IS_SYNC(writeDentry->d_inode) || - HGFS_FILECTL_SYNC(iocb->ki_filp->f_flags)) { - int error; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - error = vfs_fsync(iocb->ki_filp, 0); -#else - error = HgfsDoFsync(writeDentry->d_inode); -#endif - if (error < 0) { - result = error; - } - } - } - -out: - spin_lock(&writeDentry->d_inode->i_lock); - iinfo->numWbPages--; - spin_unlock(&writeDentry->d_inode->i_lock); - return result; -} - - -#else -/* - *---------------------------------------------------------------------- - * - * HgfsRead -- - * - * Called whenever a process reads from a file in our filesystem. Our - * function is just a thin wrapper around generic_read_file() that - * tries to validate the dentry first. - * - * Results: - * Returns the number of bytes read on success, or an error on - * failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static ssize_t -HgfsRead(struct file *file, // IN: File to read from - char __user *buf, // OUT: User buffer to copy data into - size_t count, // IN: Number of bytes to read - loff_t *offset) // IN: Offset at which to read -{ - int result; - - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(buf); - ASSERT(offset); - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s,%Zu@%lld)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, count, (long long) *offset)); - - result = HgfsRevalidate(file->f_dentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRead: invalid dentry\n")); - goto out; - } - - result = generic_file_read(file, buf, count, offset); - out: - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWrite -- - * - * Called whenever a process writes to a file in our filesystem. Our - * function is just a thin wrapper around generic_write_file() that - * tries to validate the dentry first. - * - * Note that files opened with O_SYNC (or superblocks mounted with - * "sync") are synchronously written to by the VFS. - * - * Results: - * Returns the number of bytes written on success, or an error on - * failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static ssize_t -HgfsWrite(struct file *file, // IN: File to write to - const char __user *buf, // IN: User buffer where the data is - size_t count, // IN: Number of bytes to write - loff_t *offset) // IN: Offset to begin writing at -{ - int result; - - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_inode); - ASSERT(buf); - ASSERT(offset); - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s,%Zu@%lld)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, count, (long long) *offset)); - - result = HgfsRevalidate(file->f_dentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsWrite: invalid dentry\n")); - goto out; - } - - result = generic_file_write(file, buf, count, offset); - out: - return result; -} -#endif - -/* - *---------------------------------------------------------------------- - * - * HgfsSeek -- - * - * Called whenever a process moves the file pointer for a file in our - * filesystem. Our function is just a thin wrapper around - * generic_file_llseek() that tries to validate the dentry first. - * - * Results: - * Returns the new position of the file pointer on success, - * or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static loff_t -HgfsSeek(struct file *file, // IN: File to seek - loff_t offset, // IN: Number of bytes to seek - int origin) // IN: Position to seek from - -{ - loff_t result = -1; - - ASSERT(file); - ASSERT(file->f_dentry); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s(%s/%s, %u, %lld, %d)\n", - __func__, - file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - FILE_GET_FI_P(file)->handle, offset, origin)); - - result = (loff_t) HgfsRevalidate(file->f_dentry); - if (result) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); - goto out; - } - - result = generic_file_llseek(file, offset, origin); - - out: - return result; -} - - -#if !defined VMW_FSYNC_31 -/* - *---------------------------------------------------------------------- - * - * HgfsDoFsync -- - * - * Helper for HgfsFlush() and HgfsFsync(). - * - * The hgfs protocol doesn't support fsync explicityly yet. - * So for now, we flush all the pages to presumably honor the - * intent of an app calling fsync() which is to get the - * data onto persistent storage. As things stand now we're at - * the whim of the hgfs server code running on the host to fsync or - * not if and when it pleases. - * - * - * Results: - * Returns zero on success. Otherwise an error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -HgfsDoFsync(struct inode *inode) // IN: File we operate on -{ - int ret; - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%"FMT64"u)\n", - __func__, INODE_GET_II_P(inode)->hostFileId)); - - ret = compat_filemap_write_and_wait(inode->i_mapping); - - LOG(4, (KERN_DEBUG "VMware hgfs: %s: returns %d\n", - __func__, ret)); - - return ret; -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * HgfsFlush -- - * - * Called when user process calls fflush() on an hgfs file. - * Flush all dirty pages and check for write errors. - * - * - * Results: - * Returns zero on success. (Currently always succeeds). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -HgfsFlush(struct file *file // IN: file to flush -#if !defined VMW_FLUSH_HAS_1_ARG - ,fl_owner_t id // IN: id not used -#endif - ) -{ - int ret = 0; - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name)); - - if ((file->f_mode & FMODE_WRITE) == 0) { - goto exit; - } - - - /* Flush writes to the server and return any errors */ - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling vfs_sync ... \n", - __func__)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - ret = vfs_fsync(file, 0); -#else - ret = HgfsDoFsync(file->f_dentry->d_inode); -#endif - -exit: - LOG(4, (KERN_DEBUG "VMware hgfs: %s: returns %d\n", - __func__, ret)); - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsFsync -- - * - * Called when user process calls fsync() on hgfs file. - * - * The hgfs protocol doesn't support fsync explicitly yet, - * so for now, we flush all the pages to presumably honor the - * intent of an app calling fsync() which is to get the - * data onto persistent storage, and as things stand now we're at - * the whim of the hgfs server code running on the host to fsync or - * not if and when it pleases. - * - * Results: - * Returns zero on success. (Currently always succeeds). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -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 defined VMW_FSYNC_31 - loff_t start, // IN: start of range to sync - loff_t end, // IN: end of range to sync -#endif - int datasync) // IN: fdatasync or fsync -{ - int ret = 0; - loff_t startRange; - loff_t endRange; - struct inode *inode; - -#if defined VMW_FSYNC_31 - startRange = start; - endRange = end; -#else - startRange = 0; - endRange = MAX_INT64; -#endif - - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s, %lld, %lld, %d)\n", - __func__, - file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - startRange, endRange, - datasync)); - - /* Flush writes to the server and return any errors */ - inode = file->f_dentry->d_inode; -#if defined VMW_FSYNC_31 - ret = filemap_write_and_wait_range(inode->i_mapping, startRange, endRange); -#else - ret = HgfsDoFsync(inode); -#endif - - LOG(4, (KERN_DEBUG "VMware hgfs: %s: written pages %lld, %lld returns %d)\n", - __func__, startRange, endRange, ret)); - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsMmap -- - * - * Called when user process calls mmap() on hgfs file. This is a very - * thin wrapper function- we simply attempt to revalidate the - * dentry prior to calling generic_file_mmap(). - * - * Results: - * Returns zero on success. - * Returns negative error value on failure - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -HgfsMmap(struct file *file, // IN: File we operate on - struct vm_area_struct *vma) // IN/OUT: VM area information -{ - int result; - - ASSERT(file); - ASSERT(vma); - ASSERT(file->f_dentry); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", - __func__, - file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name)); - - result = HgfsRevalidate(file->f_dentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); - goto out; - } - - result = generic_file_mmap(file, vma); - out: - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsRelease -- - * - * Called when the last user of a file closes it, i.e. when the - * file's f_count becomes zero. - * - * Results: - * Returns zero on success, or an error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsRelease(struct inode *inode, // IN: Inode that this file points to - struct file *file) // IN: File that is getting released -{ - HgfsReq *req; - HgfsHandle handle; - HgfsOp opUsed; - HgfsStatus replyStatus; - int result = 0; - - ASSERT(inode); - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_sb); - - handle = FILE_GET_FI_P(file)->handle; - LOG(6, (KERN_DEBUG "VMware hgfs: %s(%s/%s, %u)\n", - __func__, - file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - handle)); - - /* - * This may be our last open handle to an inode, so we should flush our - * dirty pages before closing it. - */ - compat_filemap_write_and_wait(inode->i_mapping); - - HgfsReleaseFileInfo(file); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionClose; - if (opUsed == HGFS_OP_CLOSE_V3) { - HgfsRequest *header; - HgfsRequestCloseV3 *request; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestCloseV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->file = handle; - request->reserved = 0; - req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - } else { - HgfsRequestClose *request; - - request = (HgfsRequestClose *)(HGFS_REQ_PAYLOAD(req)); - request->header.id = req->id; - request->header.op = opUsed; - request->file = handle; - req->payloadSize = sizeof *request; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: released handle %u\n", - handle)); - break; - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_CLOSE_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionClose = HGFS_OP_CLOSE; - goto retry; - } - break; - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: failed handle %u\n", - handle)); - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRelease: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - return result; -} - - -#ifndef VMW_SENDFILE_NONE -/* - *----------------------------------------------------------------------------- - * - * HgfsSendfile -- - * - * sendfile() wrapper for HGFS. Note that this is for sending a file - * from HGFS to another filesystem (or socket). To use HGFS as the - * destination file in a call to sendfile(), we must implement sendpage() - * as well. - * - * Like mmap(), we're just interested in validating the dentry and then - * calling into generic_file_sendfile(). - * - * Results: - * Returns number of bytes written on success, or an error on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -#if defined VMW_SENDFILE_OLD -static ssize_t -HgfsSendfile(struct file *file, // IN: File to read from - loff_t *offset, // IN/OUT: Where to start reading - size_t count, // IN: How much to read - read_actor_t actor, // IN: Routine to send a page of data - void __user *target) // IN: Destination file/socket -#elif defined VMW_SENDFILE_NEW -static ssize_t -HgfsSendfile(struct file *file, // IN: File to read from - loff_t *offset, // IN/OUT: Where to start reading - size_t count, // IN: How much to read - read_actor_t actor, // IN: Routine to send a page of data - void *target) // IN: Destination file/socket -#endif -{ - ssize_t result; - - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(target); - ASSERT(offset); - ASSERT(actor); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsSendfile: was called\n")); - - result = HgfsRevalidate(file->f_dentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSendfile: invalid dentry\n")); - goto out; - } - - result = generic_file_sendfile (file, offset, count, actor, target); - out: - return result; - -} -#endif - - -#ifdef VMW_SPLICE_READ -/* - *----------------------------------------------------------------------------- - * - * HgfsSpliceRead -- - * - * splice_read() wrapper for HGFS. Note that this is for sending a file - * from HGFS to another filesystem (or socket). To use HGFS as the - * destination file in a call to splice, we must implement splice_write() - * as well. - * - * Like mmap(), we're just interested in validating the dentry and then - * calling into generic_file_splice_read(). - * - * Results: - * Returns number of bytes written on success, or an error on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static ssize_t -HgfsSpliceRead(struct file *file, // IN: File to read from - loff_t *offset, // IN/OUT: Where to start reading - struct pipe_inode_info *pipe, // IN: Pipe where to write data - size_t len, // IN: How much to read - unsigned int flags) // IN: Various flags -{ - ssize_t result; - - ASSERT(file); - ASSERT(file->f_dentry); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s(%s/%s, %lu@%Lu)\n", - __func__, - file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - (unsigned long) len, (unsigned long long) *offset)); - - result = HgfsRevalidate(file->f_dentry); - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); - goto out; - } - - result = generic_file_splice_read(file, offset, pipe, len, flags); -out: - return result; - -} -#endif - - diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.c b/open-vm-tools/modules/linux/vmhgfs/filesystem.c deleted file mode 100644 index 2bda108d0..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.c +++ /dev/null @@ -1,956 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * filesystem.c -- - * - * High-level filesystem operations for the filesystem portion of - * the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include -#include -#include -#include "compat_cred.h" -#include "compat_dcache.h" -#include "compat_fs.h" -#include "compat_kernel.h" -#include "compat_sched.h" -#include "compat_semaphore.h" -#include "compat_slab.h" -#include "compat_spinlock.h" -#include "compat_string.h" -#include "compat_uaccess.h" -#include "compat_version.h" - -#include "filesystem.h" -#include "transport.h" -#include "hgfsDevLinux.h" -#include "hgfsProto.h" -#include "hgfsUtil.h" -#include "module.h" -#include "request.h" -#include "fsutil.h" -#include "vm_assert.h" -#include "vm_basic_types.h" -#include "rpcout.h" -#include "hgfs.h" - -/* Synchronization primitives. */ -DEFINE_SPINLOCK(hgfsBigLock); - -/* Other variables. */ -compat_kmem_cache *hgfsInodeCache; - -/* Global protocol version switch. */ -HgfsOp hgfsVersionOpen; -HgfsOp hgfsVersionRead; -HgfsOp hgfsVersionWrite; -HgfsOp hgfsVersionClose; -HgfsOp hgfsVersionSearchOpen; -HgfsOp hgfsVersionSearchRead; -HgfsOp hgfsVersionSearchClose; -HgfsOp hgfsVersionGetattr; -HgfsOp hgfsVersionSetattr; -HgfsOp hgfsVersionCreateDir; -HgfsOp hgfsVersionDeleteFile; -HgfsOp hgfsVersionDeleteDir; -HgfsOp hgfsVersionRename; -HgfsOp hgfsVersionQueryVolumeInfo; -HgfsOp hgfsVersionCreateSymlink; - -/* Private functions. */ -static inline unsigned long HgfsComputeBlockBits(unsigned long blockSize); -static compat_kmem_cache_ctor HgfsInodeCacheCtor; -static HgfsSuperInfo *HgfsInitSuperInfo(void *rawData, - uint32 mountInfoVersion); -static int HgfsReadSuper(struct super_block *sb, - void *rawData, - int flags); -static void HgfsResetOps(void); - - -/* HGFS filesystem high-level operations. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) -static struct dentry *HgfsMount(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *rawData); -#elif defined(VMW_GETSB_2618) -static int HgfsGetSb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *rawData, - struct vfsmount *mnt); -#else -static struct super_block *HgfsGetSb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *rawData); -#endif - -/* HGFS filesystem type structure. */ -static struct file_system_type hgfsType = { - .owner = THIS_MODULE, - .name = HGFS_NAME, - - .fs_flags = FS_BINARY_MOUNTDATA, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) - .mount = HgfsMount, -#else - .get_sb = HgfsGetSb, -#endif - .kill_sb = kill_anon_super, -}; - -/* - * Private functions implementations. - */ - -/* - *----------------------------------------------------------------------------- - * - * HgfsComputeBlockBits -- - * - * Given a block size, returns the number of bits in the block, rounded - * down. This approach of computing the number of bits per block and - * saving it for later use is the same used in NFS. - * - * Results: - * The number of bits in the block. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static inline unsigned long -HgfsComputeBlockBits(unsigned long blockSize) -{ - uint8 numBits; - - for (numBits = 31; numBits && !(blockSize & (1 << numBits)); numBits--); - return numBits; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsInodeCacheCtor -- - * - * Constructor for HGFS inode structures that runs once at slab - * allocation. It is called once for each piece of memory that - * is used to satisfy HGFS inode allocations; it should only be - * used to initialize items that will naturally return to their - * initialized state before deallocation (such as locks, list_heads). - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsInodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem)) // IN: slab item to initialize -{ - HgfsInodeInfo *iinfo = (HgfsInodeInfo *)slabElem; - - /* - * VFS usually calls this as part of allocating inodes for us, but since - * we're doing the allocation now, we need to call it. It'll set up - * much of the VFS inode members. - */ - inode_init_once(&iinfo->inode); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsValidateMountInfo -- - * - * Validate the the user mode mounter information. - * - * Results: - * Zero on success or -EINVAL if we pass in an unknown version. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsValidateMountInfo(void *rawData, // IN: Fs-specific mount data - uint32 *mountInfoVersion) // OUT: Mount flags -{ - HgfsMountInfoV1 *infoV1; - HgfsMountInfo *info; - uint32 *magicNumber; - int retVal = -EINVAL; - - ASSERT(mountInfoVersion); - - /* Sanity check the incoming user data. */ - if (rawData == NULL) { - printk(KERN_WARNING LGPFX "%s: error: no user supplied mount data\n", - __func__); - goto exit; - } - - /* Magic number is always first 4 bytes of the header. */ - magicNumber = rawData; - if (*magicNumber != HGFS_SUPER_MAGIC) { - printk(KERN_WARNING LGPFX "%s: error: user supplied mount data is not valid!\n", - __func__); - goto exit; - } - - /* - * Looks like HGFS data, now validate the version so that we can - * proceed and extract the required settings from the user. - */ - info = rawData; - infoV1 = rawData; - if ((info->version == HGFS_MOUNTINFO_VERSION_1 || - info->version == HGFS_MOUNTINFO_VERSION_2) && - info->infoSize == sizeof *info) { - /* - * The current version is validated with the size and magic number. - * Note the version can be either 1 or 2 as it was not bumped initially. - * Furthermore, return the version as HGFS_MOUNTINFO_VERSION_2 only since - * the objects are the same and it simplifies field extractions. - */ - LOG(4, (KERN_DEBUG LGPFX "%s: mount data version %d passed\n", - __func__, info->version)); - *mountInfoVersion = HGFS_MOUNTINFO_VERSION_2; - retVal = 0; - } else if (infoV1->version == HGFS_MOUNTINFO_VERSION_1) { - /* - * The version 1 is validated with the version and magic number. - * Note the version can be only be 1 and if so does not collide with version 2 of - * the header (which would be the info size field). - */ - LOG(4, (KERN_DEBUG LGPFX "%s: mount data version %d passed\n", - __func__, infoV1->version)); - *mountInfoVersion = infoV1->version; - retVal = 0; - } else { - /* - * The version and info size fields could not be validated - * for the known structure. It is probably a newer version. - */ - printk(KERN_WARNING LGPFX "%s: error: user supplied mount data version %d\n", - __func__, infoV1->version); - } - -exit: - return retVal; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsGetMountInfoV1 -- - * - * Gets the fields of interest from the user mode mounter version 1. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsGetMountInfoV1(HgfsMountInfoV1 *mountInfo, // IN: version 1 mount data - uint32 *mntFlags, // OUT: Mount flags - uint32 *ttl, // OUT: seconds until revalidate - uid_t *uid, // OUT: owner - gid_t *gid, // OUT: group - mode_t *fmask, // OUT: file mask - mode_t *dmask, // OUT: directory mask - const char **shareHost, // OUT: share host name - const char **shareDir) // OUT: share directory -{ - ASSERT(mountInfo); - - *mntFlags = 0; - /* - * If the mounter specified a uid or gid, we will prefer them over any uid - * or gid given to us by the server. - */ - if (mountInfo->uidSet) { - *mntFlags |= HGFS_MNT_SET_UID; - *uid = mountInfo->uid; - } - - if (mountInfo->gidSet) { - *mntFlags |= HGFS_MNT_SET_GID; - *gid = mountInfo->gid; - } - - *fmask = mountInfo->fmask; - *dmask = mountInfo->dmask; - *ttl = mountInfo->ttl; - *shareHost = mountInfo->shareNameHost; - *shareDir = mountInfo->shareNameDir; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsGetMountInfoV2 -- - * - * Gets the fields of interest from the user mode mounter version 2. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsGetMountInfoV2(HgfsMountInfo *mountInfo, // IN: version 2 mount data - uint32 *mntFlags, // OUT: Mount flags - uint32 *ttl, // OUT: seconds until revalidate - uid_t *uid, // OUT: owner - gid_t *gid, // OUT: group - mode_t *fmask, // OUT: file mask - mode_t *dmask, // OUT: directory mask - const char **shareHost, // OUT: share host name - const char **shareDir) // OUT: share directory -{ - ASSERT(mountInfo); - - *mntFlags = 0; - - if ((mountInfo->flags & HGFS_MNTINFO_SERVER_INO) != 0) { - *mntFlags |= HGFS_MNT_SERVER_INUM; - } - - /* - * If the mounter specified a uid or gid, we will prefer them over any uid - * or gid given to us by the server. - */ - if (mountInfo->uidSet) { - *mntFlags |= HGFS_MNT_SET_UID; - *uid = mountInfo->uid; - } - - if (mountInfo->gidSet) { - *mntFlags |= HGFS_MNT_SET_GID; - *gid = mountInfo->gid; - } - - *fmask = mountInfo->fmask; - *dmask = mountInfo->dmask; - *ttl = mountInfo->ttl; - *shareHost = mountInfo->shareNameHost; - *shareDir = mountInfo->shareNameDir; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsGetMountInfo -- - * - * Gets the fields of interest from the user mode mounter. - * - * Results: - * Zero on success or -EINVAL if we pass in an unknown version. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsGetMountInfo(void *rawData, // IN: Fs-specific mount data - uint32 mountInfoVersion, // IN: mount information version - uint32 *mntFlags, // OUT: Mount flags - uint32 *ttl, // OUT: seconds until revalidate - uid_t *uid, // OUT: owner - gid_t *gid, // OUT: group - mode_t *fmask, // OUT: file mask - mode_t *dmask, // OUT: directory mask - const char **shareHost, // OUT: share host name - const char **shareDir) // OUT: share path -{ - int result = 0; - - switch (mountInfoVersion) { - case HGFS_MOUNTINFO_VERSION_1: - HgfsGetMountInfoV1(rawData, - mntFlags, - ttl, - uid, - gid, - fmask, - dmask, - shareHost, - shareDir); - break; - case HGFS_MOUNTINFO_VERSION_2: - HgfsGetMountInfoV2(rawData, - mntFlags, - ttl, - uid, - gid, - fmask, - dmask, - shareHost, - shareDir); - break; - default: - ASSERT(FALSE); - result = -EINVAL; - } - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInitSuperInfo -- - * - * Allocate and initialize a new HgfsSuperInfo object - * - * Results: - * Returns a new HgfsSuperInfo object with all its fields initialized, - * or an error code cast as a pointer. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static HgfsSuperInfo * -HgfsInitSuperInfo(void *rawData, // IN: Passed down from the user - uint32 mountInfoVersion) // IN: version -{ - HgfsSuperInfo *si = NULL; - int result = 0; - int len; - char *tmpName = NULL; - Bool hostValid; - uint32 mntFlags = 0; - uint32 ttl = 0; - uid_t uid = 0; - gid_t gid = 0; - mode_t fmask = 0; - mode_t dmask = 0; - const char *shareHost; - const char *shareDir; - - si = kmalloc(sizeof *si, GFP_KERNEL); - if (!si) { - result = -ENOMEM; - goto out_error_si; - } - memset(si, 0, sizeof *si); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - result = bdi_setup_and_register(&si->bdi, HGFS_NAME); - if (result) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: initialize backing device info" - "failed. (%d)\n", __func__, result)); - goto out_error_si; - } -#endif - - result = HgfsGetMountInfo(rawData, - mountInfoVersion, - &mntFlags, - &ttl, - &uid, - &gid, - &fmask, - &dmask, - &shareHost, - &shareDir); - if (result < 0) { - LOG(6, (KERN_DEBUG LGPFX "%s: error: get mount info %d\n", __func__, result)); - goto out_error_last; - } - - /* - * Initialize with the default flags. - */ - si->mntFlags = mntFlags; - - si->uid = current_uid(); - if ((si->mntFlags & HGFS_MNT_SET_UID) != 0) { - kuid_t mntUid = make_kuid(current_user_ns(), uid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) - if (uid_valid(mntUid)) -#endif - si->uid = mntUid; - } - - si->gid = current_gid(); - if ((si->mntFlags & HGFS_MNT_SET_GID) != 0) { - kgid_t mntGid = make_kgid(current_user_ns(), gid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) - if (gid_valid(mntGid)) -#endif - si->gid = mntGid; - } - si->fmask = fmask; - si->dmask = dmask; - si->ttl = ttl * HZ; // in ticks - - /* - * We don't actually care about this field (though we may care in the - * future). For now, just make sure it is set to ".host" as a sanity check. - * - * We can't call getname() directly because on certain kernels we can't call - * putname() directly. For more details, see the change description of - * change 464782 or the second comment in bug 159623, which fixed the same - * problem for vmblock. - */ - tmpName = compat___getname(); - if (!tmpName) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: could not obtain " - "memory for filename\n")); - result = -ENOMEM; - goto out_error_last; - } - - len = strncpy_from_user(tmpName, shareHost, PATH_MAX); - if (len < 0 || len >= PATH_MAX) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user " - "on host string failed\n")); - result = len < 0 ? len : -ENAMETOOLONG; - goto out_error_last; - } - - hostValid = strcmp(tmpName, ".host") == 0; - if (!hostValid) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: host string is " - "invalid\n")); - result = -EINVAL; - goto out_error_last; - } - - /* - * Perform a simple sanity check on the directory portion: it must begin - * with forward slash. - */ - len = strncpy_from_user(tmpName, shareDir, PATH_MAX); - if (len < 0 || len >= PATH_MAX) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user " - "on dir string failed\n")); - result = len < 0 ? len : -ENAMETOOLONG; - goto out_error_last; - } - - if (*tmpName != '/') { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: dir string is " - "invalid\n")); - result = -EINVAL; - goto out_error_last; - } - - /* - * The SELinux audit subsystem will delay the putname() of a string until - * the end of a system call so that it may be audited at any point. At that - * time, it also unconditionally calls putname() on every string allocated - * by getname(). - * - * This means we can't safely retain strings allocated by getname() beyond - * the syscall boundary. So after getting the string, use kstrdup() to - * duplicate it, and store that (audit-safe) result in the SuperInfo struct. - */ - si->shareName = compat_kstrdup(tmpName, GFP_KERNEL); - if (si->shareName == NULL) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: kstrdup on " - "dir string failed\n")); - result = -ENOMEM; - goto out_error_last; - } - si->shareNameLen = strlen(si->shareName); - -out_error_last: - if (tmpName) { - compat___putname(tmpName); - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - if (result) { - bdi_destroy(&si->bdi); - } -#endif -out_error_si: - if (result) { - kfree(si); - si = ERR_PTR(result); - } - - return si; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsReadSuper -- - * - * The main entry point of the filesystem side of the driver. Called when - * a userland process does a mount(2) of an hgfs filesystem. This makes the - * whole driver transition from its initial state to state 1. Fill the - * content of the uninitialized superblock provided by the kernel. - * - * 'rawData' is a pointer (that can be NULL) to a kernel buffer (whose - * size is <= PAGE_SIZE) that corresponds to the filesystem-specific 'data' - * argument passed to mount(2). - * - * Results: - * zero and initialized superblock on success - * negative value on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsReadSuper(struct super_block *sb, // OUT: Superblock object - void *rawData, // IN: Fs-specific mount data - int flags) // IN: Mount flags -{ - int result = 0; - HgfsSuperInfo *si; - struct dentry *rootDentry = NULL; - uint32 mountInfoVersion; - - ASSERT(sb); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadSuper: entered\n")); - - /* Sanity check the incoming user data. */ - result = HgfsValidateMountInfo(rawData, &mountInfoVersion); - if (result < 0) { - return result; - } - - /* Setup both our superblock and the VFS superblock. */ - si = HgfsInitSuperInfo(rawData, mountInfoVersion); - if (IS_ERR(si)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsReadSuper: superinfo " - "init failed\n")); - return PTR_ERR(si); - } - HGFS_SET_SB_TO_COMMON(sb, si); - 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 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - sb->s_bdi = &si->bdi; -#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 - * allocation routines, but in some, it's up to the filesystem to initialize - * it. Note that we'll initialize it anyway, because the default value is - * MAX_NON_LFS, which caps our filesize at 2^32 bytes. - */ - sb->s_maxbytes = MAX_LFS_FILESIZE; - - /* - * These two operations will make sure that our block size and the bits - * per block match up, no matter what HGFS_BLOCKSIZE may be. Granted, - * HGFS_BLOCKSIZE will always be a power of two, but you never know! - */ - sb->s_blocksize_bits = HgfsComputeBlockBits(HGFS_BLOCKSIZE); - sb->s_blocksize = 1 << sb->s_blocksize_bits; - - /* - * Create the root dentry and its corresponding inode. - */ - result = HgfsInstantiateRoot(sb, &rootDentry); - if (result) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsReadSuper: Could not instantiate " - "root dentry\n")); - goto exit; - } - - sb->s_root = rootDentry; - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadSuper: finished %s\n", si->shareName)); - - exit: - if (result) { - dput(rootDentry); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - bdi_destroy(&si->bdi); - sb->s_bdi = NULL; -#endif - kfree(si->shareName); - kfree(si); - } - return result; -} - - -/* - * HGFS filesystem high-level operations. - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) -/* - *----------------------------------------------------------------------------- - * - * HgfsMount -- - * - * Invokes generic kernel code to mount a deviceless filesystem. - * - * Results: - * Mount's root dentry structure on success - * ERR_PTR()-encoded negative error code on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -struct dentry * -HgfsMount(struct file_system_type *fs_type, // IN: file system type of mount - int flags, // IN: mount flags - const char *dev_name, // IN: device mounting on - void *rawData) // IN: mount arguments -{ - return mount_nodev(fs_type, flags, rawData, HgfsReadSuper); -} -#elif defined VMW_GETSB_2618 -/* - *----------------------------------------------------------------------------- - * - * HgfsGetSb -- - * - * Invokes generic kernel code to prepare superblock for - * deviceless filesystem. - * - * Results: - * 0 on success - * non-zero on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsGetSb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *rawData, - struct vfsmount *mnt) -{ - return get_sb_nodev(fs_type, flags, rawData, HgfsReadSuper, mnt); -} -#else -/* - *----------------------------------------------------------------------------- - * - * HgfsGetSb -- - * - * Invokes generic kernel code to prepare superblock for - * deviceless filesystem. - * - * Results: - * The initialized superblock on success - * NULL on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static struct super_block * -HgfsGetSb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *rawData) -{ - return get_sb_nodev(fs_type, flags, rawData, HgfsReadSuper); -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * HgfsResetOps -- - * - * Reset ops with more than one opcode back to the desired opcode. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsResetOps(void) -{ - hgfsVersionOpen = HGFS_OP_OPEN_V3; - hgfsVersionRead = HGFS_OP_READ_V3; - hgfsVersionWrite = HGFS_OP_WRITE_V3; - hgfsVersionClose = HGFS_OP_CLOSE_V3; - hgfsVersionSearchOpen = HGFS_OP_SEARCH_OPEN_V3; - hgfsVersionSearchRead = HGFS_OP_SEARCH_READ_V3; - hgfsVersionSearchClose = HGFS_OP_SEARCH_CLOSE_V3; - hgfsVersionGetattr = HGFS_OP_GETATTR_V3; - hgfsVersionSetattr = HGFS_OP_SETATTR_V3; - hgfsVersionCreateDir = HGFS_OP_CREATE_DIR_V3; - hgfsVersionDeleteFile = HGFS_OP_DELETE_FILE_V3; - hgfsVersionDeleteDir = HGFS_OP_DELETE_DIR_V3; - hgfsVersionRename = HGFS_OP_RENAME_V3; - hgfsVersionQueryVolumeInfo = HGFS_OP_QUERY_VOLUME_INFO_V3; - hgfsVersionCreateSymlink = HGFS_OP_CREATE_SYMLINK_V3; -} - - -/* - * Public function implementations. - */ - -/* - *----------------------------------------------------------------------------- - * - * HgfsInitFileSystem -- - * - * Initializes the file system and registers it with the kernel. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -Bool -HgfsInitFileSystem(void) -{ - /* Initialize primitives. */ - HgfsResetOps(); - - /* Setup the inode slab allocator. */ - hgfsInodeCache = compat_kmem_cache_create("hgfsInodeCache", - sizeof (HgfsInodeInfo), - 0, - SLAB_HWCACHE_ALIGN, - HgfsInodeCacheCtor); - if (hgfsInodeCache == NULL) { - printk(KERN_WARNING "VMware hgfs: failed to create inode allocator\n"); - return FALSE; - } - - /* Initialize the transport. */ - HgfsTransportInit(); - - /* - * Register the filesystem. This should be the last thing we do - * in init_module. - */ - if (register_filesystem(&hgfsType)) { - printk(KERN_WARNING "VMware hgfs: failed to register filesystem\n"); - kmem_cache_destroy(hgfsInodeCache); - return FALSE; - } - LOG(4, (KERN_DEBUG "VMware hgfs: Module Loaded\n")); - - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsCleanupFileSystem -- - * - * Cleans up file system and unregisters it with the kernel. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -HgfsCleanupFileSystem(void) -{ - Bool success = TRUE; - - /* - * Unregister the filesystem. This should be the first thing we do in - * the module cleanup code. - */ - if (unregister_filesystem(&hgfsType)) { - printk(KERN_WARNING "VMware hgfs: failed to unregister filesystem\n"); - success = FALSE; - } - - /* Transport cleanup. */ - HgfsTransportExit(); - - /* Destroy the inode and request slabs. */ - kmem_cache_destroy(hgfsInodeCache); - - LOG(4, (KERN_DEBUG "VMware hgfs: Module Unloaded\n")); - return success; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.h b/open-vm-tools/modules/linux/vmhgfs/filesystem.h deleted file mode 100644 index cea3d680f..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.h +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * filesystem.h -- - * - * High-level filesystem operations for the filesystem portion of - * the vmhgfs driver. - */ - -#ifndef _HGFS_DRIVER_FILESYSTEM_H_ -#define _HGFS_DRIVER_FILESYSTEM_H_ - -#include "vm_basic_types.h" - -/* Public functions (with respect to the entire module). */ -Bool HgfsInitFileSystem(void); -Bool HgfsCleanupFileSystem(void); - -#endif // _HGFS_DRIVER_FILESYSTEM_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.c b/open-vm-tools/modules/linux/vmhgfs/fsutil.c deleted file mode 100644 index fb439231c..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.c +++ /dev/null @@ -1,2589 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * fsutil.c -- - * - * Functions used in more than one type of filesystem operation will be - * exported from this file. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include - -/* Must come before compat_dcache. */ -#include "compat_fs.h" -#include "compat_dcache.h" -#include "compat_kernel.h" -#include "compat_mm.h" -#include "compat_sched.h" -#include "compat_slab.h" -#include "compat_spinlock.h" - -#include "vm_assert.h" -#include "cpName.h" -#include "cpNameLite.h" -#include "hgfsUtil.h" -#include "module.h" -#include "request.h" -#include "fsutil.h" -#include "hgfsProto.h" -#include "vm_basic_types.h" - -/* - * The get inode descriptor object. - */ -typedef struct HgfsInodeAttrDesc { - uint32 flags; - const HgfsAttrInfo *attr; -} HgfsInodeAttrDesc; - -#define HGFS_INO_DESC_INO_FAKE (1 << 0) -#define HGFS_INO_DESC_INO_COLLISION (1 << 1) - -static void HgfsSetFileType(struct inode *inode, - HgfsAttrInfo const *attr); -static int HgfsUnpackGetattrReply(HgfsReq *req, - HgfsAttrInfo *attr, - char **fileName); -static int HgfsBuildRootPath(char *buffer, - size_t bufferLen, - HgfsSuperInfo *si); -static int HgfsBuildFullPath(char *buffer, - size_t bufferLen, - HgfsSuperInfo *si, - struct dentry *dentry); -static struct inode *HgfsGetInode(struct super_block *sb, - ino_t ino, - HgfsInodeAttrDesc *iattrDesc); -static void HgfsDoReadInode(struct inode *inode); -static int HgfsInitInode(struct inode *inode, - void *opaque); -static int HgfsFindInode(struct inode *inode, - void *opaque); - -/* - * For kernels that are older than 2.6.32 there is no truncate_pagecache call - * so we set an empty macro. - * If we have the call then we check for kernel 3.12 compatibility. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) -#define HGFS_TRUNCATE_PAGE_CACHE(inode, oldSize, newSize) -#elif defined VMW_PAGECACHE_312 || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) -#define HGFS_TRUNCATE_PAGE_CACHE(inode, oldSize, newSize) truncate_pagecache(inode, newSize) -#else -#define HGFS_TRUNCATE_PAGE_CACHE(inode, oldSize, newSize) truncate_pagecache(inode, oldSize, newSize) -#endif - -/* - * Private function implementations. - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) -/* - *---------------------------------------------------------------------------- - * - * set_nlink -- - * - * Set an inode's link count. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------------- - */ - -static inline void -set_nlink(struct inode *inode, unsigned int nlink) -{ - inode->i_nlink = nlink; -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetFileType -- - * - * Get file type from the inode mode. - * - * Results: - * The file type. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static HgfsFileType -HgfsGetFileType(struct inode *inode) // IN: Attrs to use -{ - HgfsFileType type; - - ASSERT(inode != NULL); - - switch (inode->i_mode & S_IFMT) { - case S_IFLNK: - type = HGFS_FILE_TYPE_SYMLINK; - break; - - case S_IFREG: - type = HGFS_FILE_TYPE_REGULAR; - break; - - case S_IFDIR: - type = HGFS_FILE_TYPE_DIRECTORY; - break; - - default: - /* - * XXX Should never happen. Since there aren't any other HGFS supported type. - */ - LOG(4, (KERN_DEBUG LGPFX "%s: UNSUPPORTED inode type %d\n", - __func__, inode->i_mode & S_IFMT)); - type = 0; - break; - } - - LOG(10, (KERN_DEBUG LGPFX "%s: return %d\n", __func__, type)); - return type; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsSetFileType -- - * - * Set file type in inode according to the hgfs attributes. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsSetFileType(struct inode *inode, // IN/OUT: Inode to update - HgfsAttrInfo const *attr) // IN: Attrs to use to update -{ - ASSERT(inode); - ASSERT(attr); - - switch (attr->type) { - case HGFS_FILE_TYPE_DIRECTORY: - inode->i_mode = S_IFDIR; - inode->i_op = &HgfsDirInodeOperations; - inode->i_fop = &HgfsDirFileOperations; - break; - - case HGFS_FILE_TYPE_SYMLINK: - inode->i_mode = S_IFLNK; - inode->i_op = &HgfsLinkInodeOperations; - break; - - case HGFS_FILE_TYPE_REGULAR: - inode->i_mode = S_IFREG; - inode->i_op = &HgfsFileInodeOperations; - inode->i_fop = &HgfsFileFileOperations; - inode->i_data.a_ops = &HgfsAddressSpaceOperations; - break; - - default: - /* - * XXX Should never happen. I'd put NOT_IMPLEMENTED() here - * but if the driver ever goes in the host it's probably not - * a good idea for an attacker to be able to hang the host - * simply by using a bogus file type in a reply. [bac] - */ - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetFileType: UNSUPPORTED " - "inode type\n")); - inode->i_mode = 0; -// NOT_IMPLEMENTED(); - break; - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsUnpackGetattrReply -- - * - * This function abstracts the differences between a GetattrV1 and - * a GetattrV2. The caller provides the packet containing the reply - * and we populate the AttrInfo with version-independent information. - * - * Note that attr->requestType has already been populated so that we - * know whether to expect a V1 or V2 reply. - * - * Results: - * 0 on success, anything else on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ -static int -HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet - HgfsAttrInfo *attr, // IN/OUT: Attributes - char **fileName) // OUT: file name -{ - int result; - char *name = NULL; - uint32 length = 0; - - ASSERT(req); - ASSERT(attr); - - result = HgfsUnpackCommonAttr(req, attr); - if (result != 0) { - return result; - } - - /* GetattrV2+ also wants a symlink target if it exists. */ - if (attr->requestType == HGFS_OP_GETATTR_V3) { - HgfsReplyGetattrV3 *replyV3 = (HgfsReplyGetattrV3 *)(HGFS_REP_PAYLOAD_V3(req)); - name = replyV3->symlinkTarget.name; - length = replyV3->symlinkTarget.length; - - /* Skip the symlinkTarget if it's too long. */ - if (length > HGFS_NAME_BUFFER_SIZET(req->bufferSize, sizeof *replyV3 + sizeof(HgfsReply))) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: symlink " - "target name too long, ignoring\n")); - return -ENAMETOOLONG; - } - } else if (attr->requestType == HGFS_OP_GETATTR_V2) { - HgfsReplyGetattrV2 *replyV2 = (HgfsReplyGetattrV2 *) - (HGFS_REQ_PAYLOAD(req)); - name = replyV2->symlinkTarget.name; - length = replyV2->symlinkTarget.length; - - /* Skip the symlinkTarget if it's too long. */ - if (length > HGFS_NAME_BUFFER_SIZE(req->bufferSize, replyV2)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: symlink " - "target name too long, ignoring\n")); - return -ENAMETOOLONG; - } - } - - if (fileName) { - if (length != 0) { - - *fileName = kmalloc(length + 1, GFP_KERNEL); - if (*fileName == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of " - "memory allocating symlink target name, ignoring\n")); - return -ENOMEM; - } - - /* Copy and convert. From now on, the symlink target is in UTF8. */ - memcpy(*fileName, name, length); - CPNameLite_ConvertFrom(*fileName, length, '/'); - (*fileName)[length] = '\0'; - LOG(4, (KERN_DEBUG "VMware hgfs: %s: symlink name %s\n", - __func__, *fileName)); - } else { - *fileName = NULL; - } - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackCommonattr -- - * - * This function abstracts the HgfsAttr struct behind HgfsAttrInfo. - * Callers can pass one of four replies into it and receive back the - * attributes for those replies. - * - * Callers must populate attr->requestType so that we know whether to - * expect a V1 or V2 Attr struct. - * - * Results: - * Zero on success, non-zero otherwise. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackCommonattr(HgfsReq *req, // IN/OUT: request buffer - HgfsOp opUsed, // IN: Op to be used - HgfsHandle handle, // IN: file handle to use if valid - size_t *reqSize, // OUT: request size - size_t *reqBufferSize, // OUT: request buffer size - char **fileName, // OUT: pointer to request file name - uint32 **fileNameLength, // OUT: pointer to request file name length - HgfsAttrInfo *attr) // OUT: Attrs to update -{ - int result = 0; - - attr->requestType = opUsed; - - switch (opUsed) { - case HGFS_OP_GETATTR_V3: { - HgfsRequest *requestHeader; - HgfsRequestGetattrV3 *requestV3; - - /* Fill out the request packet. */ - requestHeader = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestGetattrV3 *)HGFS_REQ_PAYLOAD_V3(req); - - /* - * When possible, issue a getattr using an existing handle. This will - * give us slightly better performance on a Windows server, and is more - * correct regardless. If we don't find a handle, fall back on getattr - * by name. - */ - requestV3->hints = 0; - if (handle != HGFS_INVALID_HANDLE) { - requestV3->fileName.flags = HGFS_FILE_NAME_USE_FILE_DESC; - requestV3->fileName.fid = handle; - requestV3->fileName.length = 0; - requestV3->fileName.caseType = HGFS_FILE_NAME_DEFAULT_CASE; - *fileName = NULL; - *fileNameLength = NULL; - } else { - *fileName = requestV3->fileName.name; - *fileNameLength = &requestV3->fileName.length; - requestV3->fileName.flags = 0; - requestV3->fileName.fid = HGFS_INVALID_HANDLE; - requestV3->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - } - requestV3->reserved = 0; - *reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - *reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, *reqSize); - break; - } - - case HGFS_OP_GETATTR_V2: { - HgfsRequestGetattrV2 *requestV2; - - requestV2 = (HgfsRequestGetattrV2 *)(HGFS_REQ_PAYLOAD(req)); - requestV2->header.op = opUsed; - requestV2->header.id = req->id; - - /* - * When possible, issue a getattr using an existing handle. This will - * give us slightly better performance on a Windows server, and is more - * correct regardless. If we don't find a handle, fall back on getattr - * by name. - */ - if (handle != HGFS_INVALID_HANDLE) { - requestV2->hints = HGFS_ATTR_HINT_USE_FILE_DESC; - requestV2->file = handle; - *fileName = NULL; - *fileNameLength = NULL; - } else { - requestV2->hints = 0; - *fileName = requestV2->fileName.name; - *fileNameLength = &requestV2->fileName.length; - } - *reqSize = sizeof *requestV2; - *reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2); - break; - } - - case HGFS_OP_GETATTR: { - HgfsRequestGetattr *requestV1; - - requestV1 = (HgfsRequestGetattr *)(HGFS_REQ_PAYLOAD(req)); - requestV1->header.op = opUsed; - requestV1->header.id = req->id; - - *fileName = requestV1->fileName.name; - *fileNameLength = &requestV1->fileName.length; - *reqSize = sizeof *requestV1; - *reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV1); - break; - } - - default: - LOG(4, (KERN_DEBUG "VMware hgfs: %s: unexpected OP type encountered\n", __func__)); - result = -EPROTO; - break; - } - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackGetattrRequestInt -- - * - * Setup the getattr request, depending on the op version. When possible, - * we will issue the getattr using an existing open HGFS handle. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackGetattrRequestInt(HgfsReq *req, // IN/OUT: Request buffer - HgfsOp opUsed, // IN: Op to be used - Bool allowHandleReuse, // IN: Can we use a handle? - HgfsSuperInfo *si, // IN: super block info - struct dentry *dentry, // IN: Optional dentry containing name/handle - HgfsAttrInfo *attr) // OUT: Attrs to update -{ - size_t reqBufferSize; - size_t reqSize; - char *fileName = NULL; - uint32 *fileNameLength = NULL; - HgfsHandle handle = HGFS_INVALID_HANDLE; - int result = 0; - - ASSERT(attr != NULL); - ASSERT(req != NULL); - ASSERT(si != NULL); - - if (allowHandleReuse) { - /* The dentry must be valid if the caller wants to use a file handle. */ - ASSERT(dentry != NULL); - /* Errors are dropped getting the file handle, as we will use the name instead. */ - (void)HgfsGetHandle(dentry->d_inode, 0, &handle); - } - - result = HgfsPackCommonattr(req, - opUsed, - handle, - &reqSize, - &reqBufferSize, - &fileName, - &fileNameLength, - attr); - if (0 > result) { - goto out; - } - - /* Avoid all this extra work when we're doing a getattr by handle. */ - if (fileName != NULL) { - - /* Build full name to send to server. */ - if (HgfsBuildFullPath(fileName, - reqBufferSize, - si, - dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: build path failed\n", __func__)); - result = -EINVAL; - goto out; - } - LOG(6, (KERN_DEBUG "VMware hgfs: %s: getting attrs for \"%s\"\n", - __func__, fileName)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(fileName, - reqBufferSize, - fileName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: CP conversion failed\n", __func__)); - result = -EINVAL; - goto out; - } - - *fileNameLength = result; - } - - req->payloadSize = reqSize + result; - result = 0; - -out: - return result; -} - - -/* - * Public function implementations. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsUnpackCommonAttr -- - * - * This function abstracts the HgfsAttr struct behind HgfsAttrInfo. - * Callers can pass one of four replies into it and receive back the - * attributes for those replies. - * - * Callers must populate attr->requestType so that we know whether to - * expect a V1 or V2 Attr struct. - * - * Results: - * Zero on success, non-zero otherwise. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ -int -HgfsUnpackCommonAttr(HgfsReq *req, // IN: Reply packet - HgfsAttrInfo *attrInfo) // OUT: Attributes -{ - HgfsReplyGetattrV3 *getattrReplyV3; - HgfsReplyGetattrV2 *getattrReplyV2; - HgfsReplyGetattr *getattrReplyV1; - HgfsReplySearchReadV3 *searchReadReplyV3; - HgfsReplySearchReadV2 *searchReadReplyV2; - HgfsReplySearchRead *searchReadReplyV1; - HgfsDirEntry *dirent; - HgfsAttrV2 *attrV2 = NULL; - HgfsAttr *attrV1 = NULL; - - ASSERT(req); - ASSERT(attrInfo); - - switch (attrInfo->requestType) { - case HGFS_OP_GETATTR_V3: - getattrReplyV3 = (HgfsReplyGetattrV3 *)(HGFS_REP_PAYLOAD_V3(req)); - attrV2 = &getattrReplyV3->attr; - break; - case HGFS_OP_GETATTR_V2: - getattrReplyV2 = (HgfsReplyGetattrV2 *)(HGFS_REQ_PAYLOAD(req)); - attrV2 = &getattrReplyV2->attr; - break; - case HGFS_OP_GETATTR: - getattrReplyV1 = (HgfsReplyGetattr *)(HGFS_REQ_PAYLOAD(req)); - attrV1 = &getattrReplyV1->attr; - break; - case HGFS_OP_SEARCH_READ_V3: - searchReadReplyV3 = (HgfsReplySearchReadV3 *)(HGFS_REP_PAYLOAD_V3(req)); - dirent = (HgfsDirEntry *)searchReadReplyV3->payload; - attrV2 = &dirent->attr; - break; - case HGFS_OP_SEARCH_READ_V2: - searchReadReplyV2 = (HgfsReplySearchReadV2 *)(HGFS_REQ_PAYLOAD(req)); - attrV2 = &searchReadReplyV2->attr; - break; - case HGFS_OP_SEARCH_READ: - searchReadReplyV1 = (HgfsReplySearchRead *)(HGFS_REQ_PAYLOAD(req)); - attrV1 = &searchReadReplyV1->attr; - break; - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackCommonAttr: unexpected op " - "in reply packet\n")); - return -EPROTO; - } - - if (attrV2 != NULL) { - attrInfo->mask = 0; - - if (attrV2->mask & HGFS_ATTR_VALID_TYPE) { - attrInfo->type = attrV2->type; - attrInfo->mask |= HGFS_ATTR_VALID_TYPE; - } - if (attrV2->mask & HGFS_ATTR_VALID_SIZE) { - attrInfo->size = attrV2->size; - attrInfo->mask |= HGFS_ATTR_VALID_SIZE; - } - if (attrV2->mask & HGFS_ATTR_VALID_ALLOCATION_SIZE) { - attrInfo->allocSize = attrV2->allocationSize; - attrInfo->mask |= HGFS_ATTR_VALID_ALLOCATION_SIZE; - } - if (attrV2->mask & HGFS_ATTR_VALID_ACCESS_TIME) { - attrInfo->accessTime = attrV2->accessTime; - attrInfo->mask |= HGFS_ATTR_VALID_ACCESS_TIME; - } - if (attrV2->mask & HGFS_ATTR_VALID_WRITE_TIME) { - attrInfo->writeTime = attrV2->writeTime; - attrInfo->mask |= HGFS_ATTR_VALID_WRITE_TIME; - } - if (attrV2->mask & HGFS_ATTR_VALID_CHANGE_TIME) { - attrInfo->attrChangeTime = attrV2->attrChangeTime; - attrInfo->mask |= HGFS_ATTR_VALID_CHANGE_TIME; - } - if (attrV2->mask & HGFS_ATTR_VALID_SPECIAL_PERMS) { - attrInfo->specialPerms = attrV2->specialPerms; - attrInfo->mask |= HGFS_ATTR_VALID_SPECIAL_PERMS; - } - if (attrV2->mask & HGFS_ATTR_VALID_OWNER_PERMS) { - attrInfo->ownerPerms = attrV2->ownerPerms; - attrInfo->mask |= HGFS_ATTR_VALID_OWNER_PERMS; - } - if (attrV2->mask & HGFS_ATTR_VALID_GROUP_PERMS) { - attrInfo->groupPerms = attrV2->groupPerms; - attrInfo->mask |= HGFS_ATTR_VALID_GROUP_PERMS; - } - if (attrV2->mask & HGFS_ATTR_VALID_OTHER_PERMS) { - attrInfo->otherPerms = attrV2->otherPerms; - attrInfo->mask |= HGFS_ATTR_VALID_OTHER_PERMS; - } - if (attrV2->mask & HGFS_ATTR_VALID_USERID) { - attrInfo->userId = attrV2->userId; - attrInfo->mask |= HGFS_ATTR_VALID_USERID; - } - if (attrV2->mask & HGFS_ATTR_VALID_GROUPID) { - attrInfo->groupId = attrV2->groupId; - attrInfo->mask |= HGFS_ATTR_VALID_GROUPID; - } - if (attrV2->mask & (HGFS_ATTR_VALID_FILEID | - HGFS_ATTR_VALID_NON_STATIC_FILEID)) { - attrInfo->hostFileId = attrV2->hostFileId; - attrInfo->mask |= HGFS_ATTR_VALID_FILEID; - } - if (attrV2->mask & HGFS_ATTR_VALID_EFFECTIVE_PERMS) { - attrInfo->effectivePerms = attrV2->effectivePerms; - attrInfo->mask |= HGFS_ATTR_VALID_EFFECTIVE_PERMS; - } - } else if (attrV1 != NULL) { - /* Implicit mask for a Version 1 attr. */ - attrInfo->mask = HGFS_ATTR_VALID_TYPE | - HGFS_ATTR_VALID_SIZE | - HGFS_ATTR_VALID_ACCESS_TIME | - HGFS_ATTR_VALID_WRITE_TIME | - HGFS_ATTR_VALID_CHANGE_TIME | - HGFS_ATTR_VALID_OWNER_PERMS | - HGFS_ATTR_VALID_EFFECTIVE_PERMS; - - attrInfo->type = attrV1->type; - attrInfo->size = attrV1->size; - attrInfo->accessTime = attrV1->accessTime; - attrInfo->writeTime = attrV1->writeTime; - attrInfo->attrChangeTime = attrV1->attrChangeTime; - attrInfo->ownerPerms = attrV1->permissions; - attrInfo->effectivePerms = attrV1->permissions; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsCalcBlockSize -- - * - * Calculate the number of 512 byte blocks used. - * - * Round the size to the next whole block and divide by the block size - * to get the number of 512 byte blocks. - * Note, this is taken from the nfs client and is simply performing: - * (size + 512-1)/ 512) - * - * Results: - * The number of 512 byte blocks for the size. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) -static inline blkcnt_t -HgfsCalcBlockSize(uint64 tsize) -{ - blkcnt_t used = (tsize + 511) >> 9; - return (used > ULONG_MAX) ? ULONG_MAX : used; -} -#else -static inline unsigned long -HgfsCalcBlockSize(uint64 tsize) -{ - loff_t used = (tsize + 511) >> 9; - return (used > ULONG_MAX) ? ULONG_MAX : used; -} -#endif - - -static inline int -hgfs_timespec_compare(const struct timespec *lhs, const struct timespec *rhs) -{ - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_nsec - rhs->tv_nsec; -} - - - -/* - *---------------------------------------------------------------------- - * - * HgfsSetInodeUidGid -- - * - * Set the UID and GID of the inode. - * - * Update an inode's UID and GID to match those of the HgfsAttr returned - * by the server. - * - * Results: - * The number of 512 byte blocks for the size. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsSetInodeUidGid(struct inode *inode, // IN/OUT: Inode - HgfsSuperInfo *si, // IN: New attrs - HgfsAttrInfo const *attr) // IN: New attrs -{ - /* - * Use the stored uid and gid if we were given them at mount-time, or if - * the server didn't give us a uid or gid. - */ - if ((si->mntFlags & HGFS_MNT_SET_UID) != 0 || - (attr->mask & HGFS_ATTR_VALID_USERID) == 0) { - inode->i_uid = si->uid; - } else { - kuid_t attrUid = make_kuid(&init_user_ns, attr->userId); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) - if (uid_valid(attrUid)) { - inode->i_uid = attrUid; - } else { - inode->i_uid = si->uid; - } -#else - inode->i_uid = attrUid; -#endif - LOG(6, (KERN_DEBUG "VMware hgfs: %s: inode uid %u\n", - __func__, from_kuid(&init_user_ns, inode->i_uid))); - } - if ((si->mntFlags & HGFS_MNT_SET_GID) != 0 || - (attr->mask & HGFS_ATTR_VALID_GROUPID) == 0) { - inode->i_gid = si->gid; - } else { - kgid_t attrGid = make_kgid(&init_user_ns, attr->groupId); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) - if (gid_valid(attrGid)) { - inode->i_gid = attrGid; - } else { - inode->i_gid = si->gid; - } -#else - inode->i_gid = attrGid; -#endif - LOG(6, (KERN_DEBUG "VMware hgfs: %s: inode gid %u\n", - __func__, from_kgid(&init_user_ns, inode->i_gid))); - } -} - -/* - *----------------------------------------------------------------------------- - * - * HgfsIsInodeWritable -- - * - * Helper function for verifying if a file is under write access. - * - * Results: - * TRUE if file is writable, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static Bool -HgfsIsInodeWritable(struct inode *inode) // IN: File we're writing to -{ - HgfsInodeInfo *iinfo; - struct list_head *cur; - Bool isWritable = FALSE; - - iinfo = INODE_GET_II_P(inode); - /* - * Iterate over the open handles for this inode, and find if there - * is one that allows the write mode. - * Note, the mode is stored as incremented by one to prevent overload of - * the zero value. - */ - spin_lock(&hgfsBigLock); - list_for_each(cur, &iinfo->files) { - HgfsFileInfo *finfo = list_entry(cur, HgfsFileInfo, list); - - if (0 != (finfo->mode & (HGFS_OPEN_MODE_WRITE_ONLY + 1))) { - isWritable = TRUE; - break; - } - } - spin_unlock(&hgfsBigLock); - - return isWritable; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsIsSafeToChange -- - * - * Helper function for verifying if a file inode size and time fields is safe - * to update. It is deemed safe only if there is not an open writer to the file. - * - * Results: - * TRUE if safe to change inode, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static Bool -HgfsIsSafeToChange(struct inode *inode) // IN: File we're writing to -{ - return !HgfsIsInodeWritable(inode); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsChangeFileAttributes -- - * - * Update an inode's attributes to match those of the HgfsAttr. May - * cause dirty pages to be flushed, and may invalidate cached pages, - * if there was a change in the file size or modification time in - * the server. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsChangeFileAttributes(struct inode *inode, // IN/OUT: Inode - HgfsAttrInfo const *attr) // IN: New attrs -{ - HgfsSuperInfo *si; - HgfsInodeInfo *iinfo; - loff_t fileSize = 0; - Bool fileSizeChanged = FALSE; - Bool needInvalidate = FALSE; - Bool isSafeToChange; - - ASSERT(inode); - ASSERT(inode->i_sb); - ASSERT(attr); - - si = HGFS_SB_TO_COMMON(inode->i_sb); - iinfo = INODE_GET_II_P(inode); - - /* - * We do not want to update the file size from server or invalidate the inode - * for inodes open for write. We need to avoid races with the write page - * extending the file. This also will cause the server to possibly update the - * server side file's mod time too. For those situations we do not want to blindly - * go and invalidate the inode pages thus losing changes in flight and corrupting the - * file. - * We only need to invalidate the inode pages if the file has truly been modified - * on the server side by another server side application, not by our writes. - * If there are no writers it is safe to assume that newer mod time means the file - * changed on the server side underneath us. - */ - isSafeToChange = HgfsIsSafeToChange(inode); - - spin_lock(&inode->i_lock); - - iinfo = INODE_GET_II_P(inode); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsChangeFileAttributes: entered\n")); - HgfsSetFileType(inode, attr); - - /* - * Set the access mode. For hosts that don't give us group or other - * bits (Windows), we use the owner bits in their stead. - */ - inode->i_mode &= ~S_IALLUGO; - if (attr->mask & HGFS_ATTR_VALID_SPECIAL_PERMS) { - inode->i_mode |= (attr->specialPerms << 9); - } - if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS) { - inode->i_mode |= (attr->ownerPerms << 6); - } - if (attr->mask & HGFS_ATTR_VALID_GROUP_PERMS) { - inode->i_mode |= (attr->groupPerms << 3); - } else { - inode->i_mode |= ((inode->i_mode & S_IRWXU) >> 3); - } - if (attr->mask & HGFS_ATTR_VALID_OTHER_PERMS) { - inode->i_mode |= (attr->otherPerms); - } else { - inode->i_mode |= ((inode->i_mode & S_IRWXU) >> 6); - } - - /* Mask the access mode. */ - switch (attr->type) { - case HGFS_FILE_TYPE_REGULAR: - inode->i_mode &= ~si->fmask; - break; - case HGFS_FILE_TYPE_DIRECTORY: - inode->i_mode &= ~si->dmask; - break; - default: - /* Nothing else gets masked. */ - break; - } - - /* - * This field is used to represent the number of hard links. If the file is - * really a file, this is easy; our filesystem doesn't support hard-linking, - * so we just set it to 1. If the field is a directory, the number of links - * represents the number of subdirectories, including '.' and "..". - * - * In either case, what we're doing isn't ideal. We've carefully tracked the - * number of links through calls to HgfsMkdir and HgfsDelete, and now some - * revalidate will make us trample on the number of links. But we have no - * choice: someone on the server may have made our local view of the number - * of links inconsistent (by, say, removing a directory) , and without the - * ability to retrieve nlink via getattr, we have no way of knowing that. - * - * XXX: So in the future, adding nlink to getattr would be nice. At that - * point we may as well just implement hard links anyway. Note that user - * programs seem to have issues with a link count greater than 1 that isn't - * accurate. I experimented with setting nlink to 2 for directories (to - * account for '.' and ".."), and find printed a hard link error. So until - * we have getattr support for nlink, everyone gets 1. - */ - set_nlink(inode, 1); - - HgfsSetInodeUidGid(inode, si, attr); - - inode->i_rdev = 0; /* Device nodes are not supported */ -#if !defined VMW_INODE_2618 - inode->i_blksize = HGFS_BLOCKSIZE; -#endif - - /* - * Invalidate cached pages if we didn't receive the file size, or if it has - * changed on the server, and no writes in flight. - */ - if (attr->mask & HGFS_ATTR_VALID_SIZE) { - fileSize = compat_i_size_read(inode); - LOG(8, (KERN_DEBUG "VMware hgfs: %s: srv size: %"FMT64"u, inode size: %Lu\n", - __func__, attr->size, fileSize)); - if (fileSize != attr->size) { - if (iinfo->numWbPages == 0 && isSafeToChange) { - fileSizeChanged = needInvalidate = TRUE; - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsChangeFileAttributes: new file " - "size: %"FMT64"u, old file size: %Lu\n", attr->size, fileSize)); - compat_i_size_write(inode, attr->size); - } - } - - fileSize = compat_i_size_read(inode); - if ((attr->mask & HGFS_ATTR_VALID_ALLOCATION_SIZE) != 0) { - inode->i_blocks = HgfsCalcBlockSize(attr->allocSize); - } else { - uint64 allocSize = ROUNDUP(fileSize, HGFS_BLOCKSIZE); - inode->i_blocks = HgfsCalcBlockSize(allocSize); - } - LOG(8, (KERN_DEBUG "VMware hgfs: %s: inode: size %Lu, blks %u\n", - __func__, fileSize, (uint32)inode->i_blocks)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsChangeFileAttributes: did not " - "get file size\n")); - } - - if (attr->mask & HGFS_ATTR_VALID_ACCESS_TIME) { - HGFS_SET_TIME(inode->i_atime, attr->accessTime); - } else { - HGFS_SET_TIME(inode->i_atime, HGFS_GET_CURRENT_TIME()); - } - - /* - * Invalidate cached pages if we didn't receive the modification time, or if - * it has changed on the server and we don't have writes in flight and any open - * open writers. - */ - if (attr->mask & HGFS_ATTR_VALID_WRITE_TIME) { - HGFS_DECLARE_TIME(newTime); - HGFS_SET_TIME(newTime, attr->writeTime); - LOG(4, (KERN_DEBUG "VMware hgfs: %s: server mod " - "time: %ld:%lu, inode mod time: %ld:%lu\n", __func__, - HGFS_PRINT_TIME(newTime), HGFS_PRINT_TIME(inode->i_mtime))); - if (hgfs_timespec_compare(&newTime, &inode->i_mtime) > 0 && - iinfo->numWbPages == 0 && - isSafeToChange) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsChangeFileAttributes: new mod " - "time: %ld:%lu, old mod time: %ld:%lu\n", - HGFS_PRINT_TIME(newTime), HGFS_PRINT_TIME(inode->i_mtime))); - needInvalidate = TRUE; - } - HGFS_SET_TIME(inode->i_mtime, attr->writeTime); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsChangeFileAttributes: did not " - "get mod time\n")); - HGFS_SET_TIME(inode->i_mtime, HGFS_GET_CURRENT_TIME()); - } - - /* - * Windows doesn't know about ctime, and might send us something - * bogus; if the ctime is invalid, use the mtime instead. - */ - if (attr->mask & HGFS_ATTR_VALID_CHANGE_TIME) { - if (HGFS_SET_TIME(inode->i_ctime, attr->attrChangeTime)) { - inode->i_ctime = inode->i_mtime; - } - } else { - HGFS_SET_TIME(inode->i_ctime, HGFS_GET_CURRENT_TIME()); - } - - spin_unlock(&inode->i_lock); - - if (fileSizeChanged) { - HGFS_TRUNCATE_PAGE_CACHE(inode, fileSize, attr->size); - } - /* - * Compare old size and write time with new size and write time. If there's - * a difference (or if we didn't get a new size or write time), the file - * must have been written to, and we need to invalidate our cached pages. - */ - if (S_ISREG(inode->i_mode) && needInvalidate) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsChangeFileAttributes: file has " - "changed on the server, invalidating pages.\n")); - compat_filemap_write_and_wait(inode->i_mapping); - if (inode->i_mapping && inode->i_mapping->nrpages != 0) { - invalidate_inode_pages2(inode->i_mapping); - } - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsCanRetryGetattrRequest -- - * - * Checks the getattr request version and downgrades the global getattr - * version if we can. - * - * Results: - * Returns TRUE on success and downgrades the global getattr protocol version, - * or FALSE if no retry is possible. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsCanRetryGetattrRequest(HgfsOp getattrOp) // IN: getattrOp version used -{ - Bool canRetry = FALSE; - - /* Retry with older version(s). Set globally. */ - if (getattrOp == HGFS_OP_GETATTR_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: Version 3 " - "not supported. Falling back to version 2.\n", __func__)); - hgfsVersionGetattr = HGFS_OP_GETATTR_V2; - canRetry = TRUE; - } else if (getattrOp == HGFS_OP_GETATTR_V2) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: Version 2 " - "not supported. Falling back to version 1.\n", __func__)); - hgfsVersionGetattr = HGFS_OP_GETATTR; - canRetry = TRUE; - } - return canRetry; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsSendGetattrRequest -- - * - * Send the getattr request and handle the reply. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsSendGetattrRequest(HgfsReq *req, // IN: getattr request - Bool *doRetry, // OUT: Retry getattr request - Bool *allowHandleReuse, // IN/OUT: handle reuse - HgfsAttrInfo *attr, // OUT: Attr to copy into - char **fileName) // OUT: pointer to allocated file name -{ - int result; - - *doRetry = FALSE; - - result = HgfsSendRequest(req); - if (result == 0) { - HgfsStatus replyStatus = HgfsReplyStatus(req); - - result = HgfsStatusConvertToLinux(replyStatus); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: reply status %d -> %d\n", - __func__, replyStatus, result)); - - /* - * If the getattr succeeded on the server, copy the stats - * into the HgfsAttrInfo, otherwise return an error. - */ - switch (result) { - case 0: - result = HgfsUnpackGetattrReply(req, attr, fileName); - break; - - case -EIO: - /* - * Fix for bug 548177. - * When user deletes a share, we still show that share during directory - * enumeration to minimize user's surprise. Now when we get getattr on - * that share server returns EIO. Linux file manager doesn't like this, - * and it doesn't display any valid shares too. So as a workaround, we - * remap EIO to success and create minimal fake attributes. - */ - LOG(1, (KERN_DEBUG "Hgfs: %s: Server returned EIO on unknown file\n", __func__)); - /* Create fake attributes */ - attr->mask = HGFS_ATTR_VALID_TYPE | HGFS_ATTR_VALID_SIZE; - attr->type = HGFS_FILE_TYPE_DIRECTORY; - attr->size = 0; - result = 0; - break; - - case -EBADF: - /* - * This can happen if we attempted a getattr by handle and the handle - * was closed. Because we have no control over the backdoor, it's - * possible that an attacker closed our handle, in which case the - * driver still thinks the handle is open. So a straight-up - * "goto retry" would cause an infinite loop. Instead, let's retry - * with a getattr by name. - */ - if (*allowHandleReuse) { - *allowHandleReuse = FALSE; - *doRetry = TRUE; - } - - /* - * There's no reason why the server should have sent us this error - * when we haven't used a handle. But to prevent an infinite loop in - * the driver, let's make sure that we don't retry again. - */ - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (HgfsCanRetryGetattrRequest(attr->requestType)) { - *doRetry = TRUE; - } - break; - - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: timed out\n", __func__)); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: protocol error: %d\n", - __func__, result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: unknown error: %d\n", - __func__, result)); - } - - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPrivateGetattrCmn -- - * - * The common getattr request. Send a getattr request to the server - * for the indicated remote name, and if it succeeds copy the - * results of the getattr into the provided HgfsAttrInfo. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPrivateGetattrCmn(HgfsSuperInfo *si, // IN: Super block info - struct dentry *dentry, // IN: Optional dentry containing name/handle - Bool allowHandleReuse, // IN: Use handle instead of name - HgfsAttrInfo *attr, // OUT: Attr to copy into - char **fileName) // OUT: Optional file name -{ - HgfsReq *req; - HgfsOp opUsed; - int result = 0; - Bool doRetry; - - ASSERT(si != NULL); - ASSERT(attr != NULL); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: out of memory " - "while getting new request\n", __func__)); - result = -ENOMEM; - goto out; - } - -retry: - opUsed = hgfsVersionGetattr; - - result = HgfsPackGetattrRequestInt(req, - opUsed, - allowHandleReuse, - si, - dentry, - attr); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: no attrs\n", __func__)); - goto out; - } - - result = HgfsSendGetattrRequest(req, &doRetry, &allowHandleReuse, attr, fileName); - if (0 != result && doRetry) { - goto retry; - } - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPrivateGetattrRoot -- - * - * The getattr for the root. Send a getattr request to the server - * for the indicated remote name, and if it succeeds copy the - * results of the getattr into the provided HgfsAttrInfo. - * - * fileName (of the root) will be set to a newly allocated string. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsPrivateGetattrRoot(struct super_block *sb, // IN: Super block object - HgfsAttrInfo *attr) // OUT: Attr to copy into -{ - HgfsSuperInfo *si; - - ASSERT(sb != NULL); - - si = HGFS_SB_TO_COMMON(sb); - - return HgfsPrivateGetattrCmn(si, NULL, FALSE, attr, NULL); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPrivateGetattr -- - * - * Internal getattr routine. Send a getattr request to the server - * for the indicated remote name, and if it succeeds copy the - * results of the getattr into the provided HgfsAttrInfo. - * - * fileName (if supplied) will be set to a newly allocated string - * if the file is a symlink; it's the caller's duty to free it. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name - HgfsAttrInfo *attr, // OUT: Attr to copy into - char **fileName) // OUT: pointer to allocated file name -{ - HgfsSuperInfo *si; - - ASSERT(dentry); - ASSERT(dentry->d_sb); - - si = HGFS_SB_TO_COMMON(dentry->d_sb); - - return HgfsPrivateGetattrCmn(si, dentry, TRUE, attr, fileName); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsIget -- - * - * Lookup or create an inode with the given attributes and remote filename. - * - * If an inode number of zero is specified, we'll extract an inode number - * either from the attributes, or from calling iunique(). - * - * Results: - * The inode on success - * NULL on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -struct inode * -HgfsIget(struct super_block *sb, // IN: Superblock of this fs - ino_t ino, // IN: Inode number (optional) - HgfsAttrInfo const *attr) // IN: Attributes to create with -{ - HgfsInodeAttrDesc iattrDesc; - HgfsSuperInfo *si; - struct inode *inode; - ino_t hashedId = ino; - - ASSERT(sb); - ASSERT(attr); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsIget: entered\n")); - - si = HGFS_SB_TO_COMMON(sb); - - /* Initialize the descriptor to use for finding an inode. */ - iattrDesc.flags = 0; - iattrDesc.attr = attr; - -retry: - /* No inode number? Use what's in the attributes, or call iunique(). */ - if (hashedId == 0) { - /* - * Try and use the server supplied ID if possible otherwise - * failover to call iunique to generate one. - */ - if ((si->mntFlags & HGFS_MNT_SERVER_INUM) != 0 && - (attr->mask & HGFS_ATTR_VALID_FILEID) != 0) { - hashedId = HgfsUniqueidToIno(attr->hostFileId); - - } else { - iattrDesc.flags |= HGFS_INO_DESC_INO_FAKE; - } - } - - if ((iattrDesc.flags & HGFS_INO_DESC_INO_FAKE) != 0) { - hashedId = iunique(sb, HGFS_RESERVED_INO); - hashedId = HgfsUniqueidToIno(hashedId); - } - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsIget: calling iget on inode number " - "%lu\n", hashedId)); - - /* Now try to find an inode for that number. */ - inode = HgfsGetInode(sb, hashedId, &iattrDesc); - if (inode) { - if ((iattrDesc.flags & HGFS_INO_DESC_INO_COLLISION) != 0) { - LOG(6, (KERN_DEBUG LGPFX "%s: collision using %lu\n", __func__, hashedId)); - iput(inode); - iattrDesc.flags &= ~HGFS_INO_DESC_INO_COLLISION; - iattrDesc.flags |= HGFS_INO_DESC_INO_FAKE; - goto retry; - } - if ((inode->i_state & I_NEW) != 0) { - inode->i_ino = hashedId; - HgfsDoReadInode(inode); - unlock_new_inode(inode); - } - HgfsChangeFileAttributes(inode, attr); - } - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsIget: done\n")); - return inode; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsInstantiateInode -- - * - * Instantiate an inode. - * Look up or create a new inode based on the attributes and inode number - * (if supplied). - * If an inode number of zero may be specified, in which case HgfsIget will - * get one from the server or, barring that, from iunique(). - * - * Results: - * Zero on success, negative error otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsInstantiateInode(struct super_block *sb, // IN: Super block - ino_t ino, // IN: Inode number (optional) - HgfsAttrInfo const *attr, // IN: Attributes to use (optional) - struct inode **inode) // OUT: instantiated inode -{ - int result = 0; - - ASSERT(sb != NULL); - ASSERT(attr != NULL); - ASSERT(inode != NULL); - - LOG(8, (KERN_DEBUG LGPFX "%s: entered\n", __func__)); - - /* - * Get the inode with this inode number and the attrs we got from - * the server. - */ - *inode = HgfsIget(sb, ino, attr); - if (*inode == NULL) { - LOG(4, (KERN_DEBUG LGPFX "%s: error getting inode\n", __func__)); - result = -ENOMEM; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsInstantiateDentry -- - * - * Instantiate a dentry. - * Associate a dentry to a looked up or created inode. - * - * Results: - * Zero on success, negative error otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsInstantiateDentry(struct inode *inode, // IN: inode - Bool rootDentry, // IN: is root dentry or not - struct dentry **dentry) // IN/OUT: dentry to instantiate -{ - int result = 0; - - ASSERT(dentry != NULL); - ASSERT(inode != NULL); - - LOG(8, (KERN_DEBUG LGPFX "%s: instantiating dentry\n", __func__)); - - if (rootDentry) { - /* - * Now the initialization of the inode is complete we can create - * the root dentry which has flags initialized from the inode itself. - */ - *dentry = d_make_root(inode); - if (*dentry == NULL) { - LOG(4, (KERN_WARNING LGPFX "%s: error make root dentry\n", __func__)); - result = -ENOMEM; - goto exit; - } - } - - ASSERT(*dentry != NULL); - - HgfsDentryAgeReset(*dentry); - (*dentry)->d_op = &HgfsDentryOperations; - if (!rootDentry) { - d_instantiate(*dentry, inode); - } - -exit: - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsInstantiateRoot -- - * - * Gets the root dentry for a given super block. - * - * Results: - * zero and a valid root dentry on success - * negative value on failure - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -HgfsInstantiateRoot(struct super_block *sb, // IN: Super block object - struct dentry **rootDentry) // OUT: Root dentry -{ - int result; - struct inode *rootInode = NULL; - struct HgfsAttrInfo rootDentryAttr; - - ASSERT(sb != NULL); - ASSERT(rootDentry != NULL); - - LOG(6, (KERN_DEBUG LGPFX "%s: entered\n", __func__)); - - *rootDentry = NULL; - - LOG(8, (KERN_DEBUG LGPFX "%s: retrieve root attrs\n", __func__)); - result = HgfsPrivateGetattrRoot(sb, &rootDentryAttr); - if (result) { - LOG(4, (KERN_WARNING "VMware hgfs: %s: Could not the root attrs\n", __func__)); - goto exit; - } - - result = HgfsInstantiateInode(sb, HGFS_ROOT_INO, &rootDentryAttr, &rootInode); - if (result) { - LOG(6, (KERN_DEBUG LGPFX "%s: Could not get the root inode\n", __func__)); - goto exit; - } - - result = HgfsInstantiateDentry(rootInode, TRUE, rootDentry); - /* - * 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; - -exit: - if (result) { - iput(rootInode); - dput(*rootDentry); - } - LOG(6, (KERN_DEBUG LGPFX "%s: return %d\n", __func__, result)); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsInstantiate -- - * - * Tie a dentry to a looked up or created inode. Callers may choose to - * supply their own attributes, or may leave attr NULL in which case the - * attributes will be queried from the server. Likewise, an inode number - * of zero may be specified, in which case HgfsIget will get one from the - * server or, barring that, from iunique(). - * - * Results: - * Zero on success, negative error otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -HgfsInstantiate(struct dentry *dentry, // IN: Dentry to use - ino_t ino, // IN: Inode number (optional) - HgfsAttrInfo const *attr) // IN: Attributes to use (optional) -{ - struct inode *inode; - HgfsAttrInfo newAttr; - int result; - - ASSERT(dentry); - - LOG(8, (KERN_DEBUG LGPFX "%s: entered\n", __func__)); - - /* If no specified attributes, get them from the server. */ - if (attr == NULL) { - LOG(8, (KERN_DEBUG LGPFX "%s: issuing getattr\n", __func__)); - result = HgfsPrivateGetattr(dentry, &newAttr, NULL); - if (result) { - goto exit; - } - attr = &newAttr; - } - - /* - * Get the inode with this inode number and the attrs we got from - * the server. - */ - result = HgfsInstantiateInode(dentry->d_sb, ino, attr, &inode); - if (result) { - goto exit; - } - - /* Everything worked out, instantiate the dentry. */ - result = HgfsInstantiateDentry(inode, FALSE, &dentry); - -exit: - LOG(8, (KERN_DEBUG LGPFX "%s: return %d\n", __func__, result)); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBuildFullPath -- - * - * Constructs the full path given the super info and optional dentry. - * This is a wrapper to the functions to build root path, if no dentry - * is supplied, and the general build path routine. - * - * Results: - * If non-negative, the length of the buffer written. - * Otherwise, an error code. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsBuildFullPath(char *buffer, // IN/OUT: Buffer to write into - size_t bufferLen, // IN: Size of buffer - HgfsSuperInfo *si, // IN: Super block info - struct dentry *dentry) // IN: Optional first dentry to walk -{ - int result = 0; - - if (dentry == NULL) { - /* No dentry so we can construct only the root name. */ - result = HgfsBuildRootPath(buffer, - bufferLen, - si); - } else { - result = HgfsBuildPath(buffer, - bufferLen, - dentry); - } - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBuildRootPath -- - * - * Constructs the root path given the super info. - * - * Results: - * If non-negative, the length of the buffer written. - * Otherwise, an error code. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsBuildRootPath(char *buffer, // IN/OUT: Buffer to write into - size_t bufferLen, // IN: Size of buffer - HgfsSuperInfo *si) // IN: First dentry to walk -{ - size_t shortestNameLength; - /* - * Buffer must hold at least the share name (which is already prefixed with - * a forward slash), and nul. - */ - shortestNameLength = si->shareNameLen + 1; - if (bufferLen < shortestNameLength) { - return -ENAMETOOLONG; - } - memcpy(buffer, si->shareName, shortestNameLength); - - /* Short-circuit if we're at the root already. */ - LOG(4, (KERN_DEBUG "VMware hgfs: %s: root path \"%s\"\n", __func__, buffer)); - return shortestNameLength; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsBuildPath -- - * - * Constructs the full path given a dentry by walking the dentry and its - * parents back to the root. Adapted from d_path(), smb_build_path(), and - * build_path_from_dentry() implementations in Linux 2.6.16. - * - * Results: - * If non-negative, the length of the buffer written. - * Otherwise, an error code. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -int -HgfsBuildPath(char *buffer, // IN/OUT: Buffer to write into - size_t bufferLen, // IN: Size of buffer - struct dentry *dentry) // IN: First dentry to walk -{ - int retval; - size_t shortestNameLength; - HgfsSuperInfo *si; - - ASSERT(buffer); - ASSERT(dentry); - ASSERT(dentry->d_sb); - - si = HGFS_SB_TO_COMMON(dentry->d_sb); - - retval = HgfsBuildRootPath(buffer, bufferLen, si); - if (0 > retval) { - return retval; - } - - /* Short-circuit if we're at the root already. */ - if (IS_ROOT(dentry)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsBuildPath: Sending root \"%s\"\n", - buffer)); - return retval; - } - - /* Skip the share name, but overwrite our previous nul. */ - shortestNameLength = retval; - buffer += shortestNameLength - 1; - bufferLen -= shortestNameLength - 1; - retval = 0; - - /* - * Build the path string walking the tree backward from end to ROOT - * and store it in reversed order. - */ - dget(dentry); - compat_lock_dentry(dentry); - while (!IS_ROOT(dentry)) { - struct dentry *parent; - size_t nameLen; - - nameLen = dentry->d_name.len; - bufferLen -= nameLen + 1; - if (bufferLen < 0) { - compat_unlock_dentry(dentry); - dput(dentry); - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsBuildPath: Ran out of space " - "while writing dentry name\n")); - return -ENAMETOOLONG; - } - buffer[bufferLen] = '/'; - memcpy(buffer + bufferLen + 1, dentry->d_name.name, nameLen); - retval += nameLen + 1; - - parent = dentry->d_parent; - dget(parent); - compat_unlock_dentry(dentry); - dput(dentry); - dentry = parent; - compat_lock_dentry(dentry); - } - compat_unlock_dentry(dentry); - dput(dentry); - - if (bufferLen == 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsBuildPath: Ran out of space while " - "writing nul\n")); - return -ENAMETOOLONG; - } - - /* Shift the constructed string down to just past the share name. */ - memmove(buffer, buffer + bufferLen, retval); - buffer[retval] = '\0'; - - /* Don't forget the share name length (which also accounts for the nul). */ - retval += shortestNameLength; - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsBuildPath: Built \"%s\"\n", buffer)); - - return retval; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDentryAgeReset -- - * - * Reset the age of this dentry by setting d_time to now. - * - * XXX: smb_renew_times from smbfs claims it is safe to reset the time of - * all the parent dentries too, but how is that possible? If I stat a file - * using a relative path, only that relative path will be validated. Sure, - * it means that the parents still /exist/, but that doesn't mean their - * attributes are up to date. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -HgfsDentryAgeReset(struct dentry *dentry) // IN: Dentry whose age to reset -{ - ASSERT(dentry); - - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsDentryAgeReset: entered\n")); - dget(dentry); - compat_lock_dentry(dentry); - dentry->d_time = jiffies; - compat_unlock_dentry(dentry); - dput(dentry); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDentryAgeForce -- - * - * Set the dentry's time to 0. This makes the dentry's age "too old" and - * forces subsequent HgfsRevalidates to go to the server for attributes. - * - * Results: - * None. - * - * Side effects: - * Subsequent HgfsRevalidate will not use cached attributes. - * - *----------------------------------------------------------------------------- - */ - -void -HgfsDentryAgeForce(struct dentry *dentry) // IN: Dentry we want to force -{ - ASSERT(dentry); - - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsDentryAgeForce: entered\n")); - dget(dentry); - compat_lock_dentry(dentry); - dentry->d_time = 0; - compat_unlock_dentry(dentry); - dput(dentry); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetOpenMode -- - * - * Based on the flags requested by the process making the open() - * syscall, determine which open mode (access type) to request from - * the server. - * - * Results: - * Returns the correct HgfsOpenMode enumeration to send to the - * server, or -1 on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsGetOpenMode(uint32 flags) // IN: Open flags -{ - uint32 mask = O_RDONLY|O_WRONLY|O_RDWR; - int result = -1; - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: (%u) entered\n", __func__, flags)); - - - /* - * Mask the flags to only look at the access type. - */ - flags &= mask; - - /* Pick the correct HgfsOpenMode. */ - switch (flags) { - - case O_RDONLY: - result = HGFS_OPEN_MODE_READ_ONLY; - break; - - case O_WRONLY: - result = HGFS_OPEN_MODE_WRITE_ONLY; - break; - - case O_RDWR: - result = HGFS_OPEN_MODE_READ_WRITE; - break; - - default: - /* - * This should never happen, but it could if a userlevel program - * is behaving poorly. - */ - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetOpenMode: invalid " - "open flags %o\n", flags)); - result = -1; - break; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: return %d\n", __func__, result)); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetOpenFlags -- - * - * Based on the flags requested by the process making the open() - * syscall, determine which flags to send to the server to open the - * file. - * - * Results: - * Returns the correct HgfsOpenFlags enumeration to send to the - * server, or -1 on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsGetOpenFlags(uint32 flags) // IN: Open flags -{ - uint32 mask = O_CREAT | O_TRUNC | O_EXCL; - int result = -1; - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: (%u) entered\n", __func__, flags)); - - /* - * Mask the flags to only look at O_CREAT, O_EXCL, and O_TRUNC. - */ - - flags &= mask; - - /* O_EXCL has no meaning if O_CREAT is not set. */ - if (!(flags & O_CREAT)) { - flags &= ~O_EXCL; - } - - /* Pick the right HgfsOpenFlags. */ - switch (flags) { - - case 0: - /* Regular open; fails if file nonexistant. */ - result = HGFS_OPEN; - break; - - case O_CREAT: - /* Create file; if it exists already just open it. */ - result = HGFS_OPEN_CREATE; - break; - - case O_TRUNC: - /* Truncate existing file; fails if nonexistant. */ - result = HGFS_OPEN_EMPTY; - break; - - case (O_CREAT | O_EXCL): - /* Create file; fail if it exists already. */ - result = HGFS_OPEN_CREATE_SAFE; - break; - - case (O_CREAT | O_TRUNC): - /* Create file; if it exists already, truncate it. */ - result = HGFS_OPEN_CREATE_EMPTY; - break; - - default: - /* - * This can only happen if all three flags are set, which - * conceptually makes no sense because O_EXCL and O_TRUNC are - * mutually exclusive if O_CREAT is set. - * - * However, the open(2) man page doesn't say you can't set all - * three flags, and certain apps (*cough* Nautilus *cough*) do - * so. To be friendly to those apps, we just silenty drop the - * O_TRUNC flag on the assumption that it's safer to honor - * O_EXCL. - */ - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetOpenFlags: invalid open " - "flags %o. Ignoring the O_TRUNC flag.\n", flags)); - result = HGFS_OPEN_CREATE_SAFE; - break; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: return %d\n", __func__, result)); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsCreateFileInfo -- - * - * Create the HGFS-specific file information struct and store a pointer to - * it in the VFS file pointer. Also, link the file information struct in the - * inode's file list, so that we may find it when all we have is an inode - * (such as in writepage()). - * - * Results: - * Zero if success, non-zero if error. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -int -HgfsCreateFileInfo(struct file *file, // IN: File pointer to attach to - HgfsHandle handle) // IN: Handle returned from server -{ - HgfsFileInfo *fileInfo; - HgfsInodeInfo *inodeInfo; - int mode; - - ASSERT(file); - - inodeInfo = INODE_GET_II_P(file->f_dentry->d_inode); - ASSERT(inodeInfo); - - /* Get the mode of the opened file. */ - mode = HgfsGetOpenMode(file->f_flags); - if (mode < 0) { - return -EINVAL; - } - - /* - * Store the file information for this open() in the file*. This needs - * to be freed on a close(). Note that we trim all flags from the open - * mode and increment it so that it is guaranteed to be non-zero, because - * callers of HgfsGetHandle may pass in zero as the desired mode if they - * don't care about the mode of the opened handle. - * - * XXX: Move this into a slab allocator once HgfsFileInfo is large. One day - * soon, the kernel will allow us to embed the vfs file into our file info, - * like we currently do for inodes. - */ - fileInfo = kmalloc(sizeof *fileInfo, GFP_KERNEL); - if (!fileInfo) { - return -ENOMEM; - } - fileInfo->handle = handle; - fileInfo->mode = HGFS_OPEN_MODE_ACCMODE(mode) + 1; - FILE_SET_FI_P(file, fileInfo); - - /* So that readdir() reissues open request */ - fileInfo->isStale = TRUE; - fileInfo->direntPos = 0; - - /* - * I don't think we need any VFS locks since we're only touching the HGFS - * specific state. But we should still acquire our own lock. - * - * XXX: Better granularity on locks, etc. - */ - spin_lock(&hgfsBigLock); - list_add_tail(&fileInfo->list, &inodeInfo->files); - spin_unlock(&hgfsBigLock); - - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsReleaseFileInfo -- - * - * Release HGFS-specific file information struct created in - * HgfsCreateFileInfo. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -void -HgfsReleaseFileInfo(struct file *file) // IN: File pointer to detach from -{ - HgfsFileInfo *fileInfo; - ASSERT(file); - - fileInfo = FILE_GET_FI_P(file); - ASSERT(fileInfo); - - spin_lock(&hgfsBigLock); - list_del_init(&fileInfo->list); - spin_unlock(&hgfsBigLock); - - kfree(fileInfo); - FILE_SET_FI_P(file, NULL); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsGetHandle -- - * - * Retrieve an existing HGFS handle for this inode, assuming one exists. - * The handle retrieved satisfies the mode desired by the client. - * - * The desired mode does not correspond directly to HgfsOpenMode. Callers - * should either increment the desired HgfsOpenMode, or, if any mode will - * do, pass zero instead. This is in line with the Linux kernel's behavior - * (see do_filp_open() and open_namei() for details). - * - * Results: - * Zero on success, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -HgfsGetHandle(struct inode *inode, // IN: Inode to search for handles - HgfsOpenMode mode, // IN: Mode to satisfy - HgfsHandle *handle) // OUT: Retrieved HGFS handle -{ - HgfsInodeInfo *iinfo; - struct list_head *cur; - Bool found = FALSE; - - ASSERT(handle); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetHandle: desired mode %u\n", mode)); - - /* - * We may have been called from a dentry without an associated inode. - * HgfsReadSuper is one such caller. No inode means no open files, so - * return an error. - */ - if (inode == NULL) { - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsGetHandle: NULL input\n")); - return -EINVAL; - } - iinfo = INODE_GET_II_P(inode); - - /* - * Unfortunately, we can't reuse handles belonging to directories. These - * handles were created by a SearchOpen request, but the server itself - * backed them with an artificial list of dentries populated via scandir. So - * it can't actually use the handles for Getattr or Setattr requests, only - * for subsequent SearchRead or SearchClose requests. - */ - if (S_ISDIR(inode->i_mode)) { - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsGetHandle: Called on directory\n")); - return -EINVAL; - } - - /* - * Iterate over the open handles for this inode, and find one that allows - * the given mode. A desired mode of zero means "any mode will do". - * Otherwise return an error; - */ - spin_lock(&hgfsBigLock); - list_for_each(cur, &iinfo->files) { - HgfsFileInfo *finfo = list_entry(cur, HgfsFileInfo, list); - - if (mode == 0 || finfo->mode & mode) { - *handle = finfo->handle; - found = TRUE; - break; - } - } - spin_unlock(&hgfsBigLock); - - if (found) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetHandle: Returning handle %d\n", - *handle)); - return 0; - } else { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetHandle: Could not find matching " - "handle\n")); - return -ENOENT; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsStatusConvertToLinux -- - * - * Convert a cross-platform HGFS status code to its Linux-kernel specific - * counterpart. - * - * Rather than encapsulate the status codes within an array indexed by the - * various HGFS status codes, we explicitly enumerate them in a switch - * statement, saving the reader some time when matching HGFS status codes - * against Linux status codes. - * - * Results: - * Zero if the converted status code represents success, negative error - * otherwise. Unknown status codes are converted to the more generic - * "protocol error" status code to maintain forwards compatibility. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -HgfsStatusConvertToLinux(HgfsStatus hgfsStatus) // IN: Status code to convert -{ - switch (hgfsStatus) { - case HGFS_STATUS_SUCCESS: - return 0; - - case HGFS_STATUS_NO_SUCH_FILE_OR_DIR: - case HGFS_STATUS_INVALID_NAME: - return -ENOENT; - - case HGFS_STATUS_INVALID_HANDLE: - return -EBADF; - - case HGFS_STATUS_OPERATION_NOT_PERMITTED: - return -EPERM; - - case HGFS_STATUS_FILE_EXISTS: - return -EEXIST; - - case HGFS_STATUS_NOT_DIRECTORY: - return -ENOTDIR; - - case HGFS_STATUS_DIR_NOT_EMPTY: - return -ENOTEMPTY; - - case HGFS_STATUS_PROTOCOL_ERROR: - return -EPROTO; - - case HGFS_STATUS_ACCESS_DENIED: - case HGFS_STATUS_SHARING_VIOLATION: - return -EACCES; - - case HGFS_STATUS_NO_SPACE: - return -ENOSPC; - - case HGFS_STATUS_OPERATION_NOT_SUPPORTED: - return -EOPNOTSUPP; - - case HGFS_STATUS_NAME_TOO_LONG: - return -ENAMETOOLONG; - - case HGFS_STATUS_GENERIC_ERROR: - return -EIO; - - case HGFS_STATUS_NOT_SAME_DEVICE: - return -EXDEV; - - default: - LOG(10, (KERN_DEBUG "VMware hgfs: HgfsStatusConvertToLinux: unknown " - "error: %u\n", hgfsStatus)); - return -EIO; - } -} - - -/* - *---------------------------------------------------------------------------- - * - * HgfsSetUidGid -- - * - * Sets the uid and gid of the host file represented by the provided - * dentry. - * - * Note that this function assumes it is being called for a file that has - * been created on the host with the correct gid if the sgid bit is set for - * the parent directory. That is, we treat the presence of the sgid bit in - * the parent direcory's mode as an indication not to set the gid manually - * ourselves here. If we did, we would clobber the gid that the host file - * system chose for us automatically when the file was created. - * - * Also note that the sgid bit itself would have been propagated to the new - * file by the host file system as well. - * - * Results: - * None. - * - * Side effects: - * The host file's uid and gid are modified if the hgfs server has - * permission to do so. - * - *---------------------------------------------------------------------------- - */ - -void -HgfsSetUidGid(struct inode *parent, // IN: parent inode - struct dentry *dentry, // IN: dentry of file to update - kuid_t uid, // IN: uid to set - kgid_t gid) // IN: gid to set -{ - struct iattr setUidGid; - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: entered \n", __func__)); - - setUidGid.ia_valid = ATTR_UID; - setUidGid.ia_uid = uid; - - /* - * Only set the gid if the host file system wouldn't have for us. See the - * comment in the function header. - */ - if (!parent || !(parent->i_mode & S_ISGID)) { - setUidGid.ia_valid |= ATTR_GID; - setUidGid.ia_gid = gid; - } - - /* - * After the setattr, we desperately want a revalidate so we can - * get the true attributes from the server. However, the setattr - * may have done that for us. To prevent a spurious revalidate, - * reset the dentry's time before the setattr. That way, if setattr - * ends up revalidating the dentry, the subsequent call to - * revalidate will do nothing. - */ - HgfsDentryAgeForce(dentry); - HgfsSetattr(dentry, &setUidGid); - HgfsRevalidate(dentry); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: returns\n", __func__)); -} - - -/* - *---------------------------------------------------------------------------- - * - * HgfsGetInode -- - * - * This function replaces iget() and should be called instead of it. - * HgfsGetInode() obtains an inode and, if it is a new one, initializes - * it calling HgfsDoReadInode(). - * - * Results: - * A new inode object on success, NULL on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static struct inode * -HgfsGetInode(struct super_block *sb, // IN: file system superblock object - ino_t ino, // IN: inode number to assign to new inode - HgfsInodeAttrDesc *iattrDesc) // IN: Attributes to create with -{ - return iget5_locked(sb, ino, HgfsFindInode, HgfsInitInode, iattrDesc); -} - - -/* - *---------------------------------------------------------------------------- - * - * HgfsFindInode -- - * - * This function is a callback used for comparisons between inodes. - * - * Results: - * 1 on success, 0 on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -HgfsFindInode(struct inode *inode, // IN: compared inode - void *opaque) // IN: attribute data -{ - HgfsInodeAttrDesc *iattrDesc = opaque; - HgfsInodeInfo *iinfo = INODE_GET_II_P(inode); - int result = 1; - - ASSERT(iattrDesc != NULL); - - if (iinfo->hostFileId != iattrDesc->attr->hostFileId) { - /* Don't match inode with different unique Ids. */ - result = 0; - - } else if (iinfo->isFakeInodeNumber || - iattrDesc->attr->type == HGFS_FILE_TYPE_DIRECTORY) { - iattrDesc->flags |= HGFS_INO_DESC_INO_COLLISION; - /* Deal with a collision and retry again. */ - result = 1; - - } else if (iattrDesc->attr->type != HgfsGetFileType(inode)) { - /* Don't match inodes of different types. */ - result = 0; - - } else if (is_bad_inode(inode)) { - result = 0; - } - - return result; -} - - -/* - *---------------------------------------------------------------------------- - * - * HgfsInitInode -- - * - * This function is a callback used to initialize a new struct inode. - * - * Results: - * Zero on success always. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -HgfsInitInode(struct inode *inode, // IN: inode to init - void *opaque) // IN: attributes to init with -{ - HgfsInodeAttrDesc *iattrDesc = opaque; - HgfsInodeInfo *iinfo = INODE_GET_II_P(inode); - - ASSERT(iattrDesc != NULL); - - if ((iattrDesc->attr->mask & HGFS_ATTR_VALID_FILEID) != 0) { - iinfo->hostFileId = iattrDesc->attr->hostFileId; - } - - iinfo->isFakeInodeNumber = (iattrDesc->flags & HGFS_INO_DESC_INO_FAKE) != 0; - return 0; -} - - - -/* - *---------------------------------------------------------------------------- - * - * HgfsDoReadInode -- - * - * A filesystem wide function that is called to initialize a new inode. - * This is called from two different places depending on the kernel version. - * In older kernels that provide the iget() interface, this function is - * called by the kernel as part of inode initialization (from - * HgfsDoReadInode). In newer kernels that call iget_locked(), this - * function is called by filesystem code to initialize the new inode. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -HgfsDoReadInode(struct inode *inode) // IN: Inode to initialize -{ - HgfsInodeInfo *iinfo = INODE_GET_II_P(inode); - - /* - * If the vfs inode is not embedded within the HgfsInodeInfo, then we - * haven't yet allocated the HgfsInodeInfo. Do so now. - * - * XXX: We could allocate with GFP_ATOMIC. But instead, we'll do a standard - * allocation and mark the inode "bad" if the allocation fails. This'll - * make all subsequent operations on the inode fail, which is what we want. - */ - INODE_SET_II_P(inode, iinfo); - INIT_LIST_HEAD(&iinfo->files); - iinfo->createdAndUnopened = FALSE; - iinfo->numWbPages = 0; - INIT_LIST_HEAD(&iinfo->listWbPages); - -} diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.h b/open-vm-tools/modules/linux/vmhgfs/fsutil.h deleted file mode 100644 index 054a98df9..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.h +++ /dev/null @@ -1,141 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * fsutil.h -- - * - * Functions used in more than one type of filesystem operation will be - * exported from this file. - */ - -#ifndef _HGFS_DRIVER_FSUTIL_H_ -#define _HGFS_DRIVER_FSUTIL_H_ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include "compat_fs.h" - -#include "module.h" /* For kuid_t kgid_t types. */ -#include "inode.h" -#include "request.h" -#include "vm_basic_types.h" -#include "hgfsProto.h" - -/* - * Struct used to pass around attributes that Linux cares about. - * These aren't just the attributes seen in HgfsAttr[V2]; we add a filename - * pointer for convenience (used by SearchRead and Getattr). - */ -typedef struct HgfsAttrInfo { - HgfsOp requestType; - HgfsAttrValid mask; - HgfsFileType type; /* File type */ - uint64 allocSize; /* Disk allocation size (in bytes) */ - uint64 size; /* File size (in bytes) */ - uint64 accessTime; /* Time of last access */ - uint64 writeTime; /* Time of last write */ - uint64 attrChangeTime; /* Time file attributes were last changed */ - HgfsPermissions specialPerms; /* Special permissions bits */ - HgfsPermissions ownerPerms; /* Owner permissions bits */ - HgfsPermissions groupPerms; /* Group permissions bits */ - HgfsPermissions otherPerms; /* Other permissions bits */ - HgfsPermissions effectivePerms; /* Permissions in effect for the user on the - host. */ - uint32 userId; /* UID */ - uint32 groupId; /* GID */ - uint64 hostFileId; /* Inode number */ -} HgfsAttrInfo; - - -/* - * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down - * so that it will fit. - * Note, this is taken from CIFS so we apply the same algorithm. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) -/* - * We use hash_64 to convert the value to 31 bits, and - * then add 1, to ensure that we don't end up with a 0 as the value. - */ -#if BITS_PER_LONG == 64 -static inline ino_t -HgfsUniqueidToIno(uint64 fileid) -{ - return (ino_t)fileid; -} -#else -#include - -static inline ino_t -HgfsUniqueidToIno(uint64 fileid) -{ - return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; -} -#endif - -#else -static inline ino_t -HgfsUniqueidToIno(uint64 fileid) -{ - ino_t ino = (ino_t) fileid; - if (sizeof(ino_t) < sizeof(uint64)) { - ino ^= fileid >> (sizeof(uint64)-sizeof(ino_t)) * 8; - } - return ino; -} -#endif - -/* Public functions (with respect to the entire module). */ -int HgfsUnpackCommonAttr(HgfsReq *req, - HgfsAttrInfo *attr); -void HgfsChangeFileAttributes(struct inode *inode, - HgfsAttrInfo const *attr); -int HgfsPrivateGetattr(struct dentry *dentry, - HgfsAttrInfo *attr, - char **fileName); -struct inode *HgfsIget(struct super_block *sb, - ino_t ino, - HgfsAttrInfo const *attr); -int HgfsInstantiateRoot(struct super_block *sb, - struct dentry **rootDentry); -int HgfsInstantiate(struct dentry *dentry, - ino_t ino, - HgfsAttrInfo const *attr); -int HgfsBuildPath(char *buffer, - size_t bufferLen, - struct dentry *dentry); -void HgfsDentryAgeReset(struct dentry *dentry); -void HgfsDentryAgeForce(struct dentry *dentry); -int HgfsGetOpenMode(uint32 flags); -int HgfsGetOpenFlags(uint32 flags); -int HgfsCreateFileInfo(struct file *file, - HgfsHandle handle); -void HgfsReleaseFileInfo(struct file *file); -int HgfsGetHandle(struct inode *inode, - HgfsOpenMode mode, - HgfsHandle *handle); -int HgfsStatusConvertToLinux(HgfsStatus hgfsStatus); -void HgfsSetUidGid(struct inode *parent, - struct dentry *dentry, - kuid_t uid, - kgid_t gid); - - -#endif // _HGFS_DRIVER_FSUTIL_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/inode.c b/open-vm-tools/modules/linux/vmhgfs/inode.c deleted file mode 100644 index c6110e044..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/inode.c +++ /dev/null @@ -1,2305 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * inode.c -- - * - * Inode operations for the filesystem portion of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -#include -#endif -#include -#include // for current_fs_time - -#include "compat_cred.h" -#include "compat_dcache.h" -#include "compat_fs.h" -#include "compat_kernel.h" -#include "compat_mm.h" -#include "compat_page-flags.h" -#include "compat_spinlock.h" -#include "compat_version.h" - -#include "cpName.h" -#include "cpNameLite.h" -#include "hgfsProto.h" -#include "hgfsUtil.h" -#include "inode.h" -#include "module.h" -#include "request.h" -#include "fsutil.h" -#include "vm_assert.h" - - -#if defined VMW_DCOUNT_311 || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) -/* - * Linux Kernel versions that are version 3.11 version and newer or are compatible - * by having the d_count function replacement backported. - */ -#define hgfs_d_count(dentry) d_count(dentry) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) -/* - * Kernel versions that are not 3.11 version compatible or are just older will - * use the d_count field. - */ -#define hgfs_d_count(dentry) dentry->d_count -#else -#define hgfs_d_count(dentry) atomic_read(&dentry->d_count) -#endif - -#if defined VMW_DALIAS_319 || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) -/* - * Linux Kernel versions that are version 3.19 and newer or are compatible - * by having the d_alias field moved into a union backported. - */ -#define hgfs_d_alias() d_u.d_alias -#else -/* - * Kernel versions that are not 3.19 version compatible or are just older will - * use the d_alias field directly. - */ -#define hgfs_d_alias() d_alias -#endif - -/* Private functions. */ -static int HgfsDelete(struct inode *dir, - struct dentry *dentry, - HgfsOp op); -static int HgfsPackSetattrRequest(struct iattr *iattr, - struct dentry *dentry, - Bool allowHandleReuse, - HgfsOp opUsed, - HgfsReq *req, - Bool *changed); -static int HgfsPackCreateDirRequest(struct dentry *dentry, - compat_umode_t mode, - HgfsOp opUsed, - HgfsReq *req); -static int HgfsTruncatePages(struct inode *inode, - loff_t newSize); -static int HgfsPackSymlinkCreateRequest(struct dentry *dentry, - const char *symname, - HgfsOp opUsed, - HgfsReq *req); - -/* HGFS inode operations. */ -static int HgfsCreate(struct inode *dir, - struct dentry *dentry, - compat_umode_t mode, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - bool excl -#else - struct nameidata *nd -#endif -); -static struct dentry *HgfsLookup(struct inode *dir, - struct dentry *dentry, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - unsigned int flags -#else - struct nameidata *nd -#endif -); -static int HgfsMkdir(struct inode *dir, - struct dentry *dentry, - compat_umode_t mode); -static int HgfsRmdir(struct inode *dir, - struct dentry *dentry); -static int HgfsUnlink(struct inode *dir, - struct dentry *dentry); -static int HgfsRename(struct inode *oldDir, - struct dentry *oldDentry, - struct inode *newDir, - struct dentry *newDentry); -static int HgfsSymlink(struct inode *dir, - struct dentry *dentry, - const char *symname); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -static int HgfsPermission(struct inode *inode, - int mask, - struct nameidata *nameidata); -#elif defined(IPERM_FLAG_RCU) -static int HgfsPermission(struct inode *inode, - int mask, - unsigned int flags); -#else -static int HgfsPermission(struct inode *inode, - int mask); -#endif -static int HgfsGetattr(struct vfsmount *mnt, - struct dentry *dentry, - struct kstat *stat); - -#define HGFS_CREATE_DIR_MASK (HGFS_CREATE_DIR_VALID_FILE_NAME | \ - HGFS_CREATE_DIR_VALID_SPECIAL_PERMS | \ - HGFS_CREATE_DIR_VALID_OWNER_PERMS | \ - HGFS_CREATE_DIR_VALID_GROUP_PERMS | \ - HGFS_CREATE_DIR_VALID_OTHER_PERMS) - -/* HGFS inode operations structure for directories. */ -struct inode_operations HgfsDirInodeOperations = { - /* Optional */ - .create = HgfsCreate, - - /* Optional */ - .mkdir = HgfsMkdir, - - .lookup = HgfsLookup, - .rmdir = HgfsRmdir, - .unlink = HgfsUnlink, - .rename = HgfsRename, - .symlink = HgfsSymlink, - .permission = HgfsPermission, - .setattr = HgfsSetattr, - - /* Optional */ - .getattr = HgfsGetattr, -}; - -/* HGFS inode operations structure for files. */ -struct inode_operations HgfsFileInodeOperations = { - .permission = HgfsPermission, - .setattr = HgfsSetattr, - - /* Optional */ - .getattr = HgfsGetattr, -}; - -/* - * Private functions implementations. - */ - - -/* - *---------------------------------------------------------------------- - * - * HgfsClearReadOnly -- - * - * Try to remove the file/dir read only attribute. - * - * Note when running on Windows servers the entry may have the read-only - * flag set and prevent a rename or delete operation from occuring. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsClearReadOnly(struct dentry *dentry) // IN: file/dir to remove read only -{ - struct iattr enableWrite; - - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsClearReadOnly: removing read-only\n")); - enableWrite.ia_mode = (dentry->d_inode->i_mode | S_IWUSR); - enableWrite.ia_valid = ATTR_MODE; - return HgfsSetattr(dentry, &enableWrite); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsDelete -- - * - * Handle both unlink and rmdir requests. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsDelete(struct inode *dir, // IN: Parent dir of file/dir to delete - struct dentry *dentry, // IN: Dentry of file/dir to delete - HgfsOp op) // IN: Opcode for file type (file or dir) -{ - HgfsReq *req = NULL; - int result = 0; - Bool secondAttempt = FALSE; - HgfsStatus replyStatus; - char *fileName = NULL; - uint32 *fileNameLength; - uint32 reqSize; - HgfsOp opUsed; - - ASSERT(dir); - ASSERT(dir->i_sb); - ASSERT(dentry); - ASSERT(dentry->d_inode); - - if (!dir || !dentry) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: NULL input\n")); - result = -EFAULT; - goto out; - } - - if ((op != HGFS_OP_DELETE_FILE) && - (op != HGFS_OP_DELETE_DIR)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: Invalid opcode\n")); - result = -EINVAL; - goto out; - } - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - if (op == HGFS_OP_DELETE_FILE) { - opUsed = hgfsVersionDeleteFile; - } else { - opUsed = hgfsVersionDeleteDir; - } - - if (opUsed == HGFS_OP_DELETE_FILE_V3 || - opUsed == HGFS_OP_DELETE_DIR_V3) { - HgfsRequestDeleteV3 *request; - HgfsRequest *header; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestDeleteV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->hints = 0; - fileName = request->fileName.name; - fileNameLength = &request->fileName.length; - request->fileName.fid = HGFS_INVALID_HANDLE; - request->fileName.flags = 0; - request->fileName.caseType = HGFS_FILE_NAME_DEFAULT_CASE; - request->reserved = 0; - reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - } else { - HgfsRequestDelete *request; - - request = (HgfsRequestDelete *)(HGFS_REQ_PAYLOAD(req)); - /* Fill out the request packet. */ - request->header.id = req->id; - request->header.op = opUsed; - fileName = request->fileName.name; - fileNameLength = &request->fileName.length; - reqSize = sizeof *request; - } - - /* Build full name to send to server. */ - if (HgfsBuildPath(fileName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize), - dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: build path failed\n")); - result = -EINVAL; - goto out; - } - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: deleting \"%s\", opUsed %u\n", - fileName, opUsed)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(fileName, - HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize), - fileName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: CP conversion failed\n")); - result = -EINVAL; - goto out; - } - - *fileNameLength = result; - req->payloadSize = reqSize + result; - - result = HgfsSendRequest(req); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDelete: got reply\n")); - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - /* - * Since we deleted the file, decrement its hard link count. As - * we don't support hard links, this has the effect of making the - * link count 0, which means that when the last reference to the - * inode is dropped, the inode will be freed instead of moved to - * the unused list. - * - * Also update the mtime/ctime of the parent directory, and the - * ctime of the deleted file. - */ - compat_drop_nlink(dentry->d_inode); - dentry->d_inode->i_ctime = dir->i_ctime = dir->i_mtime = - CURRENT_TIME; - break; - - case -EACCES: - case -EPERM: - /* - * It's possible that we're talking to a Windows server with - * a file marked read-only. Let's try again, after removing - * the read-only bit from the file. - * - * XXX: I think old servers will send -EPERM here. Is this entirely - * safe? - */ - if (!secondAttempt) { - secondAttempt = TRUE; - result = HgfsClearReadOnly(dentry); - if (result == 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: file is no " - "longer read-only, retrying delete\n")); - goto retry; - } - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: failed to remove " - "read-only property\n")); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: second attempt at " - "delete failed\n")); - } - break; - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_DELETE_DIR_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionDeleteDir = HGFS_OP_DELETE_DIR; - goto retry; - } else if (opUsed == HGFS_OP_DELETE_FILE_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionDeleteFile = HGFS_OP_DELETE_FILE; - goto retry; - } - - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: server " - "returned error: %d\n", result)); - break; - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackSetattrRequest -- - * - * Setup the Setattr request, depending on the op version. When possible, - * we will issue the setattr request using an existing open HGFS handle. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * On success, the changed argument is set indicating whether the - * attributes have actually changed. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from - struct dentry *dentry, // IN: File to set attributes of - Bool allowHandleReuse, // IN: Can we use a handle? - HgfsOp opUsed, // IN: Op to be used - HgfsReq *req, // IN/OUT: Packet to write into - Bool *changed) // OUT: Have the attrs changed? -{ - HgfsAttrV2 *attrV2; - HgfsAttr *attr; - HgfsAttrHint *hints; - HgfsAttrChanges *update; - HgfsHandle handle; - char *fileName = NULL; - uint32 *fileNameLength = NULL; - unsigned int valid; - size_t reqBufferSize; - size_t reqSize; - int result = 0; - uid_t attrUid = -1; - gid_t attrGid = -1; - - ASSERT(iattr); - ASSERT(dentry); - ASSERT(req); - ASSERT(changed); - - valid = iattr->ia_valid; - - if (valid & ATTR_UID) { - attrUid = from_kuid(&init_user_ns, iattr->ia_uid); - } - - if (valid & ATTR_GID) { - attrGid = from_kgid(&init_user_ns, iattr->ia_gid); - } - - switch (opUsed) { - case HGFS_OP_SETATTR_V3: { - HgfsRequest *requestHeader; - HgfsRequestSetattrV3 *requestV3; - - requestHeader = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestSetattrV3 *)HGFS_REQ_PAYLOAD_V3(req); - attrV2 = &requestV3->attr; - hints = &requestV3->hints; - - /* - * Clear attributes, mask, and hints before touching them. - * We can't rely on GetNewRequest() to zero our structures, so - * make sure to zero them all here. - */ - memset(attrV2, 0, sizeof *attrV2); - memset(hints, 0, sizeof *hints); - - /* - * When possible, issue a setattr using an existing handle. This will - * give us slightly better performance on a Windows server, and is more - * correct regardless. If we don't find a handle, fall back on setattr - * by name. - * - * Changing the size (via truncate) requires write permissions. Changing - * the times also requires write permissions on Windows, so we require it - * here too. Otherwise, any handle will do. - */ - if (allowHandleReuse && HgfsGetHandle(dentry->d_inode, - (valid & ATTR_SIZE) || - (valid & ATTR_ATIME) || - (valid & ATTR_MTIME) ? - HGFS_OPEN_MODE_WRITE_ONLY + 1 : 0, - &handle) == 0) { - requestV3->fileName.fid = handle; - requestV3->fileName.flags = HGFS_FILE_NAME_USE_FILE_DESC; - requestV3->fileName.caseType = HGFS_FILE_NAME_DEFAULT_CASE; - requestV3->fileName.length = 0; - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackSetattrRequest: setting " - "attributes of handle %u\n", handle)); - } else { - fileName = requestV3->fileName.name; - fileNameLength = &requestV3->fileName.length; - requestV3->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - requestV3->fileName.fid = HGFS_INVALID_HANDLE; - requestV3->fileName.flags = 0; - } - requestV3->reserved = 0; - reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize); - - /* - * We only support changing these attributes: - * - all mode bits (i.e. all permissions) - * - uid/gid - * - size - * - access/write times - */ - - if (valid & ATTR_MODE) { - attrV2->mask |= HGFS_ATTR_VALID_SPECIAL_PERMS | - HGFS_ATTR_VALID_OWNER_PERMS | HGFS_ATTR_VALID_GROUP_PERMS | - HGFS_ATTR_VALID_OTHER_PERMS; - attrV2->specialPerms = ((iattr->ia_mode & - (S_ISUID | S_ISGID | S_ISVTX)) >> 9); - attrV2->ownerPerms = ((iattr->ia_mode & S_IRWXU) >> 6); - attrV2->groupPerms = ((iattr->ia_mode & S_IRWXG) >> 3); - attrV2->otherPerms = (iattr->ia_mode & S_IRWXO); - *changed = TRUE; - } - - if (valid & ATTR_UID) { - attrV2->mask |= HGFS_ATTR_VALID_USERID; - attrV2->userId = attrUid; - *changed = TRUE; - } - - if (valid & ATTR_GID) { - attrV2->mask |= HGFS_ATTR_VALID_GROUPID; - attrV2->groupId = attrGid; - *changed = TRUE; - } - - if (valid & ATTR_SIZE) { - attrV2->mask |= HGFS_ATTR_VALID_SIZE; - attrV2->size = iattr->ia_size; - *changed = TRUE; - } - - if (valid & ATTR_ATIME) { - attrV2->mask |= HGFS_ATTR_VALID_ACCESS_TIME; - attrV2->accessTime = HGFS_GET_TIME(iattr->ia_atime); - if (valid & ATTR_ATIME_SET) { - *hints |= HGFS_ATTR_HINT_SET_ACCESS_TIME; - } - *changed = TRUE; - } - - if (valid & ATTR_MTIME) { - attrV2->mask |= HGFS_ATTR_VALID_WRITE_TIME; - attrV2->writeTime = HGFS_GET_TIME(iattr->ia_mtime); - if (valid & ATTR_MTIME_SET) { - *hints |= HGFS_ATTR_HINT_SET_WRITE_TIME; - } - *changed = TRUE; - } - break; - } - - case HGFS_OP_SETATTR_V2: { - HgfsRequestSetattrV2 *requestV2; - - requestV2 = (HgfsRequestSetattrV2 *)(HGFS_REQ_PAYLOAD(req)); - requestV2->header.op = opUsed; - requestV2->header.id = req->id; - - attrV2 = &requestV2->attr; - hints = &requestV2->hints; - - /* - * Clear attributes, mask, and hints before touching them. - * We can't rely on GetNewRequest() to zero our structures, so - * make sure to zero them all here. - */ - memset(attrV2, 0, sizeof *attrV2); - memset(hints, 0, sizeof *hints); - - /* - * When possible, issue a setattr using an existing handle. This will - * give us slightly better performance on a Windows server, and is more - * correct regardless. If we don't find a handle, fall back on setattr - * by name. - * - * Changing the size (via truncate) requires write permissions. Changing - * the times also requires write permissions on Windows, so we require it - * here too. Otherwise, any handle will do. - */ - if (allowHandleReuse && HgfsGetHandle(dentry->d_inode, - (valid & ATTR_SIZE) || - (valid & ATTR_ATIME) || - (valid & ATTR_MTIME) ? - HGFS_OPEN_MODE_WRITE_ONLY + 1 : 0, - &handle) == 0) { - *hints = HGFS_ATTR_HINT_USE_FILE_DESC; - requestV2->file = handle; - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackSetattrRequest: setting " - "attributes of handle %u\n", handle)); - } else { - fileName = requestV2->fileName.name; - fileNameLength = &requestV2->fileName.length; - } - reqSize = sizeof *requestV2; - reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2); - - /* - * We only support changing these attributes: - * - all mode bits (i.e. all permissions) - * - uid/gid - * - size - * - access/write times - */ - - if (valid & ATTR_MODE) { - attrV2->mask |= HGFS_ATTR_VALID_SPECIAL_PERMS | - HGFS_ATTR_VALID_OWNER_PERMS | HGFS_ATTR_VALID_GROUP_PERMS | - HGFS_ATTR_VALID_OTHER_PERMS; - attrV2->specialPerms = ((iattr->ia_mode & - (S_ISUID | S_ISGID | S_ISVTX)) >> 9); - attrV2->ownerPerms = ((iattr->ia_mode & S_IRWXU) >> 6); - attrV2->groupPerms = ((iattr->ia_mode & S_IRWXG) >> 3); - attrV2->otherPerms = (iattr->ia_mode & S_IRWXO); - *changed = TRUE; - } - - if (valid & ATTR_UID) { - attrV2->mask |= HGFS_ATTR_VALID_USERID; - attrV2->userId = attrUid; - *changed = TRUE; - } - - if (valid & ATTR_GID) { - attrV2->mask |= HGFS_ATTR_VALID_GROUPID; - attrV2->groupId = attrGid; - *changed = TRUE; - } - - if (valid & ATTR_SIZE) { - attrV2->mask |= HGFS_ATTR_VALID_SIZE; - attrV2->size = iattr->ia_size; - *changed = TRUE; - } - - if (valid & ATTR_ATIME) { - attrV2->mask |= HGFS_ATTR_VALID_ACCESS_TIME; - attrV2->accessTime = HGFS_GET_TIME(iattr->ia_atime); - if (valid & ATTR_ATIME_SET) { - *hints |= HGFS_ATTR_HINT_SET_ACCESS_TIME; - } - *changed = TRUE; - } - - if (valid & ATTR_MTIME) { - attrV2->mask |= HGFS_ATTR_VALID_WRITE_TIME; - attrV2->writeTime = HGFS_GET_TIME(iattr->ia_mtime); - if (valid & ATTR_MTIME_SET) { - *hints |= HGFS_ATTR_HINT_SET_WRITE_TIME; - } - *changed = TRUE; - } - break; - } - - case HGFS_OP_SETATTR: { - HgfsRequestSetattr *request; - - request = (HgfsRequestSetattr *)(HGFS_REQ_PAYLOAD(req)); - request->header.op = opUsed; - request->header.id = req->id; - - attr = &request->attr; - update = &request->update; - - /* We'll use these later. */ - fileName = request->fileName.name; - fileNameLength = &request->fileName.length; - reqSize = sizeof *request; - reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, request); - - - /* - * Clear attributes before touching them. - * We can't rely on GetNewRequest() to zero our structures, so - * make sure to zero them all here. - */ - memset(attr, 0, sizeof *attr); - memset(update, 0, sizeof *update); - - /* - * We only support changing these attributes: - * - owner mode bits (i.e. owner permissions) - * - size - * - access/write times - */ - - if (valid & ATTR_MODE) { - *update |= HGFS_ATTR_PERMISSIONS; - attr->permissions = ((iattr->ia_mode & S_IRWXU) >> 6); - *changed = TRUE; - } - - if (valid & ATTR_SIZE) { - *update |= HGFS_ATTR_SIZE; - attr->size = iattr->ia_size; - *changed = TRUE; - } - - if (valid & ATTR_ATIME) { - *update |= HGFS_ATTR_ACCESS_TIME | - ((valid & ATTR_ATIME_SET) ? HGFS_ATTR_ACCESS_TIME_SET : 0); - attr->accessTime = HGFS_GET_TIME(iattr->ia_atime); - *changed = TRUE; - } - - if (valid & ATTR_MTIME) { - *update |= HGFS_ATTR_WRITE_TIME | - ((valid & ATTR_MTIME_SET) ? HGFS_ATTR_WRITE_TIME_SET : 0); - attr->writeTime = HGFS_GET_TIME(iattr->ia_mtime); - *changed = TRUE; - } - break; - } - - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSetattrRequest: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - /* Avoid all this extra work when we're doing a setattr by handle. */ - if (fileName != NULL) { - - /* Build full name to send to server. */ - if (HgfsBuildPath(fileName, reqBufferSize, dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSetattrRequest: build path " - "failed\n")); - return -EINVAL; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackSetattrRequest: setting " - "attributes of \"%s\"\n", fileName)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(fileName, - reqBufferSize, - fileName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSetattrRequest: CP " - "conversion failed\n")); - return -EINVAL; - } - - *fileNameLength = result; - } - req->payloadSize = reqSize + result; - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackCreateDirRequest -- - * - * Setup the CreateDir request, depending on the op version. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackCreateDirRequest(struct dentry *dentry, // IN: Directory to create - compat_umode_t mode, // IN: Mode to assign dir - HgfsOp opUsed, // IN: Op to be used. - HgfsReq *req) // IN/OUT: Packet to write into -{ - char *fileName = NULL; - uint32 *fileNameLength; - size_t requestSize; - int result; - - ASSERT(dentry); - ASSERT(req); - - switch (opUsed) { - case HGFS_OP_CREATE_DIR_V3: { - HgfsRequest *requestHeader; - HgfsRequestCreateDirV3 *requestV3; - - requestHeader = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestCreateDirV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - - /* We'll use these later. */ - fileName = requestV3->fileName.name; - fileNameLength = &requestV3->fileName.length; - requestV3->fileName.flags = 0; - requestV3->fileName.fid = HGFS_INVALID_HANDLE; - requestV3->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - - requestSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - - requestV3->mask = HGFS_CREATE_DIR_MASK; - - /* Set permissions. */ - requestV3->specialPerms = (mode & (S_ISUID | S_ISGID | S_ISVTX)) >> 9; - requestV3->ownerPerms = (mode & S_IRWXU) >> 6; - requestV3->groupPerms = (mode & S_IRWXG) >> 3; - requestV3->otherPerms = (mode & S_IRWXO); - requestV3->fileAttr = 0; - break; - } - case HGFS_OP_CREATE_DIR_V2: { - HgfsRequestCreateDirV2 *requestV2; - - requestV2 = (HgfsRequestCreateDirV2 *)(HGFS_REQ_PAYLOAD(req)); - requestV2->header.op = opUsed; - requestV2->header.id = req->id; - - /* We'll use these later. */ - fileName = requestV2->fileName.name; - fileNameLength = &requestV2->fileName.length; - requestSize = sizeof *requestV2; - - requestV2->mask = HGFS_CREATE_DIR_MASK; - - /* Set permissions. */ - requestV2->specialPerms = (mode & (S_ISUID | S_ISGID | S_ISVTX)) >> 9; - requestV2->ownerPerms = (mode & S_IRWXU) >> 6; - requestV2->groupPerms = (mode & S_IRWXG) >> 3; - requestV2->otherPerms = (mode & S_IRWXO); - break; - } - case HGFS_OP_CREATE_DIR: { - HgfsRequestCreateDir *request; - - request = (HgfsRequestCreateDir *)(HGFS_REQ_PAYLOAD(req)); - - /* We'll use these later. */ - fileName = request->fileName.name; - fileNameLength = &request->fileName.length; - requestSize = sizeof *request; - requestSize = sizeof *request; - - /* Set permissions. */ - request->permissions = (mode & S_IRWXU) >> 6; - break; - } - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - /* Build full name to send to server. */ - if (HgfsBuildPath(fileName, - req->bufferSize - (requestSize - 1), - dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: build path " - "failed\n")); - return -EINVAL; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: create dir " - "\"%s\", perms %o\n", fileName, mode)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(fileName, - req->bufferSize - (requestSize - 1), - fileName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: CP " - "conversion failed\n")); - return -EINVAL; - } - - *fileNameLength = result; - req->payloadSize = requestSize + result; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTruncatePages -- - * - * Following a truncate operation on the server, we must update the - * page cache's view of the file by truncating some pages. This is a - * two step procedure. First we call vmtruncate() to truncate all - * whole pages. Then we get the boundary page from the page cache - * ourselves, compute where the truncation began, and memset() the - * rest of the page to zero. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsTruncatePages(struct inode *inode, // IN: Inode whose page to truncate - loff_t newSize) // IN: New size of the file -{ - int result; - pgoff_t pageIndex = newSize >> PAGE_CACHE_SHIFT; - unsigned pageOffset = newSize & (PAGE_CACHE_SIZE - 1); - struct page *page; - char *buffer; - - ASSERT(inode); - - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsTruncatePages: entered\n")); - - /* - * In 3.8.0, vmtruncate was removed and replaced by calling the check - * size and set directly. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) - result = vmtruncate(inode, newSize); -#else - result = inode_newsize_ok(inode, newSize); - if (0 == result) { - truncate_setsize(inode, newSize); - } -#endif - if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsTruncatePages: vmtruncate failed " - "with error code %d\n", result)); - return result; - } - - /* - * This is a bit complicated, so it merits an explanation. grab_cache_page() - * will give us back the page with the specified index, after having locked - * and incremented its reference count. We must first map it into memory so - * we can modify it. After we're done modifying the page, we flush its data - * from the data cache, unmap it, release our reference, and unlock it. - */ - page = grab_cache_page(inode->i_mapping, pageIndex); - if (page == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsTruncatePages: could not get page " - "with index %lu from page cache\n", pageIndex)); - return -ENOMEM; - } - buffer = kmap(page); - memset(buffer + pageOffset, 0, PAGE_CACHE_SIZE - pageOffset); - flush_dcache_page(page); - kunmap(page); - page_cache_release(page); - compat_unlock_page(page); - return 0; -} - - -/* - * HGFS inode operations. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsCreate -- - * - * Create inode for a new file. Called directly by vfs_create, - * which is called by open_namei (both in fs/namei.c), as a result - * of someone doing a creat(2) or an open(2) with O_CREAT. - * - * This gets called BEFORE f_op->open is called, so the file on the - * remote end has not been created yet when we get here. So, we - * just cheat and create a reasonable looking inode and instantiate - * it. When this returns, our open routine will get called, which - * will create the actual file on the server. If that fails for - * some reason, dentry_open (which calls f_op->open) will cleanup - * things and fput the dentry. - * - * XXX: Now that we do care about having valid inode numbers, it is - * unfortunate but necessary that we "cheat" here. The problem is that - * without the "intent" field from the nameidata struct (which we don't - * get prior to 2.5.75), we have no way of knowing whether the file was - * opened with O_EXCL or O_TRUNC. Knowing about O_TRUNC isn't crucial - * because we can always create the file now and truncate it later, in - * HgfsOpen. But without knowing about O_EXCL, we can't "fail if the file - * exists on the server", which is the desired behavior for O_EXCL. The - * source code for NFSv3 in 2.4.2 describes this shortcoming. The only - * solution, barring massive architectural differences between the 2.4 and - * 2.6 HGFS drivers, is to ignore O_EXCL, but we've supported it up until - * now... - * - * Results: - * Returns zero on success, negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsCreate(struct inode *dir, // IN: Parent dir to create in - struct dentry *dentry, // IN: Dentry containing name to create - compat_umode_t mode, // IN: Mode of file to be created -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - bool excl // IN: O_EXCL -#else - struct nameidata *nd // IN: Intent, vfsmount, ... -#endif - ) -{ - HgfsAttrInfo attr; - int result; - - ASSERT(dir); - ASSERT(dentry); - - /* - * We can call HgfsBuildPath and make the full path to this new entry, - * but why bother if it's only for logging. - */ - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsCreate: new entry \"%s\"\n", - dentry->d_name.name)); - - /* Create appropriate attrs for this file. */ - attr.type = HGFS_FILE_TYPE_REGULAR; - attr.size = 0; /* just to be explicit */ - attr.specialPerms = ((mode & (S_ISUID | S_ISGID | S_ISVTX)) >> 9); - attr.ownerPerms = (mode & S_IRWXU) >> 6; - attr.groupPerms = (mode & S_IRWXG) >> 3; - attr.otherPerms = mode & S_IRWXO; - attr.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; - - result = HgfsInstantiate(dentry, 0, &attr); - - /* - * Mark the inode as recently created but not yet opened so that if we do - * fail to create the actual file in HgfsOpen, we know to force a - * revalidate so that the next operation on this inode will fail. - */ - if (result == 0) { - HgfsInodeInfo *iinfo = INODE_GET_II_P(dentry->d_inode); - iinfo->createdAndUnopened = TRUE; - } - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsLookup -- - * - * Lookup a file in a directory. - * - * We do a getattr to see if the file exists on the server, and if - * so we create a new inode and fill in the fields appropriately by - * calling HgfsIget with the results of the getattr, and then - * call d_add with the new dentry. - * - * For the curious, the way lookup in linux works (see fs/namei.c) - * is roughly as follows: first a d_lookup is done to see if there - * is an appropriate entry in the dcache already. If there is, it - * is revalidated by calling d_op->d_revalidate, which calls our - * HgfsDentryRevalidate (see above). If there is no dentry in the - * cache or if the dentry is no longer valid, then namei calls - * i_op->lookup, which calls HgfsLookup. - * - * Results: - * Returns NULL on success, negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static struct dentry * -HgfsLookup(struct inode *dir, // IN: Inode of parent directory - struct dentry *dentry, // IN: Dentry containing name to look up -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) - unsigned int flags -#else - struct nameidata *nd // IN: Intent, vfsmount, ... -#endif - ) -{ - HgfsAttrInfo attr; - struct inode *inode; - int error = 0; - - ASSERT(dir); - ASSERT(dentry); - - if (!dir || !dentry) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsLookup: NULL input\n")); - error = -EFAULT; - goto error; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsLookup: dir ino %lu, i_dev %u\n", - dir->i_ino, dir->i_sb->s_dev)); - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsLookup: entry name is \"%s\"\n", - dentry->d_name.name)); - - /* Do a getattr on the file to see if it exists on the server. */ - inode = NULL; - error = HgfsPrivateGetattr(dentry, &attr, NULL); - if (!error) { - /* File exists on the server. */ - - /* - * Get the inode with this inode number and the attrs we got from - * the server. - */ - inode = HgfsIget(dir->i_sb, 0, &attr); - if (!inode) { - error = -ENOMEM; - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsLookup: out of memory getting " - "inode\n")); - goto error; - } - } else if (error != -ENOENT) { - /* - * Either the file doesn't exist or there was a more serious - * error; if it's the former, it's okay, we just do nothing. - */ - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsLookup: error other " - "than ENOENT: %d\n", error)); - goto error; - } - - /* - * Set the dentry's time to NOW, set its operations pointer, add it - * and the new (possibly NULL) inode to the dcache. - */ - HgfsDentryAgeReset(dentry); - dentry->d_op = &HgfsDentryOperations; - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsLookup: adding new entry\n")); - d_add(dentry, inode); - - return NULL; - -error: - return ERR_PTR(error); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsMkdir -- - * - * Handle a mkdir request - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsMkdir(struct inode *dir, // IN: Inode of parent directory - struct dentry *dentry, // IN: Dentry with name to be created - compat_umode_t mode) // IN: Mode of dir to be created -{ - HgfsReq *req; - HgfsStatus replyStatus; - HgfsOp opUsed; - int result = 0; - - ASSERT(dir); - ASSERT(dir->i_sb); - ASSERT(dentry); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionCreateDir; - result = HgfsPackCreateDirRequest(dentry, mode, opUsed, req); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: error packing request\n")); - goto out; - } - - /* - * Send the request and process the reply. Since HgfsReplyCreateDirV2 and - * HgfsReplyCreateDir are identical, we need no special logic here. - */ - result = HgfsSendRequest(req); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsMkdir: got reply\n")); - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsMkdir: directory created " - "successfully, instantiating dentry\n")); - result = HgfsInstantiate(dentry, 0, NULL); - if (result == 0) { - /* - * Attempt to set host directory's uid/gid to that of the - * current user. As with the open(.., O_CREAT) case, this is - * only expected to work when the hgfs server is running on - * a Linux machine and as root, but we might as well give it - * a go. - */ - HgfsSetUidGid(dir, dentry, current_fsuid(), current_fsgid()); - } - - /* - * XXX: When we support hard links, this is a good place to - * increment link count of parent dir. - */ - break; - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_CREATE_DIR_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: Version 3 not " - "supported. Falling back to version 2.\n")); - hgfsVersionCreateDir = HGFS_OP_CREATE_DIR_V2; - goto retry; - } else if (opUsed == HGFS_OP_CREATE_DIR_V2) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: Version 2 not " - "supported. Falling back to version 1.\n")); - hgfsVersionCreateDir = HGFS_OP_CREATE_DIR; - goto retry; - } - - /* Fallthrough. */ - default: - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsMkdir: directory was not " - "created, error %d\n", result)); - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsMkdir: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsRmdir -- - * - * Handle an rmdir request. Just calls HgfsDelete with the - * correct opcode. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsRmdir(struct inode *dir, // IN: Parent dir of dir to remove - struct dentry *dentry) // IN: Dentry of dir to remove -{ - int result; - - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsRmdir: was called\n")); - - /* - * XXX: CIFS also sets the size of the deleted directory to 0. Why? I don't - * know...why not? - * - * XXX: When we support hardlinks, we should decrement the link count of - * the parent directory. - */ - result = HgfsDelete(dir, dentry, HGFS_OP_DELETE_DIR); - if (!result) { - compat_i_size_write(dentry->d_inode, 0); - } - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsUnlink -- - * - * Handle an unlink request. Just calls HgfsDelete with the - * correct opcode. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsUnlink(struct inode *dir, // IN: Parent dir of file to unlink - struct dentry *dentry) // IN: Dentry of file to unlink -{ - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsUnlink: was called\n")); - - return HgfsDelete(dir, dentry, HGFS_OP_DELETE_FILE); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsRename -- - * - * Handle rename requests. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsRename(struct inode *oldDir, // IN: Inode of original directory - struct dentry *oldDentry, // IN: Dentry of file to rename - struct inode *newDir, // IN: Inode of new directory - struct dentry *newDentry) // IN: Dentry containing new name -{ - HgfsReq *req = NULL; - char *oldName; - char *newName; - Bool secondAttempt=FALSE; - uint32 *oldNameLength; - uint32 *newNameLength; - int result = 0; - uint32 reqSize; - HgfsOp opUsed; - HgfsStatus replyStatus; - - ASSERT(oldDir); - ASSERT(oldDir->i_sb); - ASSERT(oldDentry); - ASSERT(newDir); - ASSERT(newDentry); - - if (!oldDir || !oldDentry || !newDir || !newDentry) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: NULL input\n")); - result = -EFAULT; - goto out; - } - - if (oldDentry->d_inode && newDentry->d_inode) { - HgfsInodeInfo *oldIinfo; - HgfsInodeInfo *newIinfo; - /* - * Don't do rename if the source and target are identical (from the - * viewpoint of the host). It is possible that multiple guest inodes - * point to the same host inode under the case that both one folder - * and its subfolder are mapped as hgfs sharese. Please also see the - * comments at fsutil.c/HgfsIget. - */ - oldIinfo = INODE_GET_II_P(oldDentry->d_inode); - newIinfo = INODE_GET_II_P(newDentry->d_inode); - if (oldIinfo->hostFileId !=0 && newIinfo->hostFileId != 0 && - oldIinfo->hostFileId == newIinfo->hostFileId) { - LOG(4, ("VMware hgfs: %s: source and target are the same file.\n", - __func__)); - result = -EEXIST; - goto out; - } - } - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - -retry: - opUsed = hgfsVersionRename; - if (opUsed == HGFS_OP_RENAME_V3) { - HgfsRequestRenameV3 *request = (HgfsRequestRenameV3 *)HGFS_REQ_PAYLOAD_V3(req); - HgfsRequest *header = (HgfsRequest *)HGFS_REQ_PAYLOAD(req); - - header->op = opUsed; - header->id = req->id; - - oldName = request->oldName.name; - oldNameLength = &request->oldName.length; - request->hints = 0; - request->oldName.flags = 0; - request->oldName.fid = HGFS_INVALID_HANDLE; - request->oldName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - request->reserved = 0; - reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - } else { - HgfsRequestRename *request = (HgfsRequestRename *)HGFS_REQ_PAYLOAD(req); - - request->header.op = opUsed; - oldName = request->oldName.name; - oldNameLength = &request->oldName.length; - reqSize = sizeof *request; - } - - /* Build full old name to send to server. */ - if (HgfsBuildPath(oldName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize), - oldDentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: build old path failed\n")); - result = -EINVAL; - goto out; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRename: Old name: \"%s\"\n", - oldName)); - - /* Convert old name to CP format. */ - result = CPName_ConvertTo(oldName, - HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize), - oldName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: oldName CP " - "conversion failed\n")); - result = -EINVAL; - goto out; - } - - *oldNameLength = result; - reqSize += result; - - /* - * Build full new name to send to server. - * Note the different buffer length. This is because HgfsRequestRename - * contains two filenames, and once we place the first into the packet we - * must account for it when determining the amount of buffer available for - * the second. - */ - if (opUsed == HGFS_OP_RENAME_V3) { - HgfsRequestRenameV3 *request = (HgfsRequestRenameV3 *)HGFS_REQ_PAYLOAD_V3(req); - HgfsFileNameV3 *newNameP; - newNameP = (HgfsFileNameV3 *)((char *)&request->oldName + - sizeof request->oldName + result); - newName = newNameP->name; - newNameLength = &newNameP->length; - newNameP->flags = 0; - newNameP->fid = HGFS_INVALID_HANDLE; - newNameP->caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - } else { - HgfsRequestRename *request = (HgfsRequestRename *)HGFS_REQ_PAYLOAD(req); - HgfsFileName *newNameP; - newNameP = (HgfsFileName *)((char *)&request->oldName + - sizeof request->oldName + result); - newName = newNameP->name; - newNameLength = &newNameP->length; - } - - if (HgfsBuildPath(newName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize) - result, - newDentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: build new path failed\n")); - result = -EINVAL; - goto out; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRename: New name: \"%s\"\n", - newName)); - - /* Convert new name to CP format. */ - result = CPName_ConvertTo(newName, - HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize) - result, - newName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: newName CP " - "conversion failed\n")); - result = -EINVAL; - goto out; - } - - *newNameLength = result; - reqSize += result; - req->payloadSize = reqSize; - - result = HgfsSendRequest(req); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRename: got reply\n")); - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - if (result == -EPROTO) { - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_RENAME_V3) { - hgfsVersionRename = HGFS_OP_RENAME; - goto retry; - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: server " - "returned error: %d\n", result)); - goto out; - } - } else if ((-EACCES == result) || (-EPERM == result)) { - /* - * It's possible that we're talking to a Windows server with - * a file marked read-only. Let's try again, after removing - * the read-only bit from the file. - * - * XXX: I think old servers will send -EPERM here. Is this entirely - * safe? - * We can receive EACCES or EPERM if we don't have the correct - * permission on the source file. So lets not assume that we have - * a target and only clear the target if there is one. - */ - if (!secondAttempt && newDentry->d_inode != NULL) { - secondAttempt = TRUE; - LOG(4, (KERN_DEBUG "VMware hgfs: %s:clear target RO mode %8x\n", - __func__, newDentry->d_inode->i_mode)); - result = HgfsClearReadOnly(newDentry); - if (result == 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: file is no " - "longer read-only, retrying rename\n")); - goto retry; - } - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: failed to remove " - "read-only property\n")); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: second attempt or " - "no target failed\n")); - } - } else if (0 != result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: failed with result %d\n", result)); - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: unknown error: " - "%d\n", result)); - } - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) - if (result == 0) { - /* - * We force revalidate to go get the file info as soon as needed. - * We only add this fix, borrowed from CIFS, for newer versions - * of the kernel which have the current_fs_time function. - * For details see bug 1613734 but here is a short summary. - * This addresses issues in editors such as gedit which use - * rename when saving the updated contents of a file. - * If we don't force the revalidation here, then the dentry - * will randomly age over some time which will then pick up the - * file's new timestamps from the server at that time. - * This delay will cause the editor to think the file has been modified - * underneath it and prompt the user if they want to reload the file. - */ - HgfsDentryAgeForce(oldDentry); - HgfsDentryAgeForce(newDentry); - oldDir->i_ctime = oldDir->i_mtime = newDir->i_ctime = - newDir->i_mtime = current_fs_time(oldDir->i_sb); - } -#endif // LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackSymlinkCreateRequest -- - * - * Setup the create symlink request, depending on the op version. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackSymlinkCreateRequest(struct dentry *dentry, // IN: File pointer for this open - const char *symname, // IN: Target name - HgfsOp opUsed, // IN: Op to be used - HgfsReq *req) // IN/OUT: Packet to write into -{ - HgfsRequestSymlinkCreateV3 *requestV3 = NULL; - HgfsRequestSymlinkCreate *request = NULL; - char *symlinkName; - uint32 *symlinkNameLength; - char *targetName; - uint32 *targetNameLength; - size_t targetNameBytes; - - size_t requestSize; - int result; - - ASSERT(dentry); - ASSERT(symname); - ASSERT(req); - - switch (opUsed) { - case HGFS_OP_CREATE_SYMLINK_V3: { - HgfsRequest *requestHeader; - - requestHeader = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestSymlinkCreateV3 *)HGFS_REQ_PAYLOAD_V3(req); - - /* We'll use these later. */ - symlinkName = requestV3->symlinkName.name; - symlinkNameLength = &requestV3->symlinkName.length; - requestV3->symlinkName.flags = 0; - requestV3->symlinkName.fid = HGFS_INVALID_HANDLE; - requestV3->symlinkName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - requestV3->reserved = 0; - requestSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - break; - } - case HGFS_OP_CREATE_SYMLINK: { - - request = (HgfsRequestSymlinkCreate *)(HGFS_REQ_PAYLOAD(req)); - request->header.op = opUsed; - request->header.id = req->id; - - /* We'll use these later. */ - symlinkName = request->symlinkName.name; - symlinkNameLength = &request->symlinkName.length; - requestSize = sizeof *request; - break; - } - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - if (HgfsBuildPath(symlinkName, req->bufferSize - (requestSize - 1), - dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: build symlink path " - "failed\n")); - return -EINVAL; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: Symlink name: \"%s\"\n", - symlinkName)); - - /* Convert symlink name to CP format. */ - result = CPName_ConvertTo(symlinkName, - req->bufferSize - (requestSize - 1), - symlinkName); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: symlinkName CP " - "conversion failed\n")); - return -EINVAL; - } - - *symlinkNameLength = result; - req->payloadSize = requestSize + result; - - /* - * Note the different buffer length. This is because HgfsRequestSymlink - * contains two filenames, and once we place the first into the packet we - * must account for it when determining the amount of buffer available for - * the second. - * - * Also note that targetNameBytes accounts for the NUL character. Once - * we've converted it to CP name, it won't be NUL-terminated and the length - * of the string in the packet itself won't account for it. - */ - if (opUsed == HGFS_OP_CREATE_SYMLINK_V3) { - HgfsFileNameV3 *fileNameP; - fileNameP = (HgfsFileNameV3 *)((char *)&requestV3->symlinkName + - sizeof requestV3->symlinkName + result); - targetName = fileNameP->name; - targetNameLength = &fileNameP->length; - fileNameP->flags = 0; - fileNameP->fid = HGFS_INVALID_HANDLE; - fileNameP->caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - } else { - HgfsFileName *fileNameP; - fileNameP = (HgfsFileName *)((char *)&request->symlinkName + - sizeof request->symlinkName + result); - targetName = fileNameP->name; - targetNameLength = &fileNameP->length; - } - targetNameBytes = strlen(symname) + 1; - - /* Copy target name into request packet. */ - if (targetNameBytes > req->bufferSize - (requestSize - 1)) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: target name is too " - "big\n")); - return -EINVAL; - } - memcpy(targetName, symname, targetNameBytes); - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: target name: \"%s\"\n", - targetName)); - - /* Convert target name to CPName-lite format. */ - CPNameLite_ConvertTo(targetName, targetNameBytes - 1, '/'); - - *targetNameLength = targetNameBytes - 1; - req->payloadSize += targetNameBytes - 1; - - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsSymlink -- - * - * Handle a symlink request - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsSymlink(struct inode *dir, // IN: Inode of parent directory - struct dentry *dentry, // IN: Dentry of new symlink file - const char *symname) // IN: Target name -{ - HgfsReq *req; - int result = 0; - HgfsOp opUsed; - HgfsStatus replyStatus; - - ASSERT(dir); - ASSERT(dir->i_sb); - ASSERT(dentry); - ASSERT(symname); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSymlink: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionCreateSymlink; - result = HgfsPackSymlinkCreateRequest(dentry, symname, opUsed, req); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSymlink: error packing request\n")); - goto out; - } - - result = HgfsSendRequest(req); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsSymlink: got reply\n")); - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsSymlink: symlink created " - "successfully, instantiating dentry\n")); - result = HgfsInstantiate(dentry, 0, NULL); - } else if (result == -EPROTO) { - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_CREATE_SYMLINK_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSymlink: Version 3 " - "not supported. Falling back to version 2.\n")); - hgfsVersionCreateSymlink = HGFS_OP_CREATE_SYMLINK; - goto retry; - } else { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsSymlink: symlink was not " - "created, error %d\n", result)); - } - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSymlink: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSymlink: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSymlink: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - - return result; -} - - -/* - *---------------------------------------------------------------------------- - * - * HgfsAccessInt -- - * - * Check to ensure the user has the specified type of access to the file. - * - * Results: - * Returns 0 if access is allowed and a non-zero error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -HgfsAccessInt(struct dentry *dentry, // IN: dentry to check access for - int mask) // IN: access mode requested. -{ - - HgfsAttrInfo attr; - int ret; - - if (!dentry) { - return 0; - } - ret = HgfsPrivateGetattr(dentry, &attr, NULL); - if (ret == 0) { - uint32 effectivePermissions; - - if (attr.mask & HGFS_ATTR_VALID_EFFECTIVE_PERMS) { - effectivePermissions = attr.effectivePerms; - } else { - /* - * If the server did not return actual effective permissions then - * need to calculate ourselves. However we should avoid unnecessary - * denial of access so perform optimistic permissions calculation. - * It is safe since host enforces necessary restrictions regardless of - * the client's decisions. - */ - effectivePermissions = - attr.ownerPerms | attr.groupPerms | attr.otherPerms; - } - - if ((effectivePermissions & mask) != mask) { - ret = -EACCES; - } - LOG(8, ("VMware Hgfs: %s: effectivePermissions: %d, ret: %d\n", - __func__, effectivePermissions, ret)); - } else { - LOG(4, ("VMware Hgfs: %s: HgfsPrivateGetattr failed.\n", __func__)); - } - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPermission -- - * - * Check for access rights on Hgfs. Called from VFS layer for each - * file access. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) -static int -HgfsPermission(struct inode *inode, - int mask) -{ - LOG(8, ("VMware hgfs: %s: inode->mode: %8x mask: %8x\n", __func__, - inode->i_mode, mask)); - /* - * For sys_access, we go to the host for permission checking; - * otherwise return 0. - */ - if (mask & MAY_ACCESS) { /* For sys_access. */ - struct dentry *dentry; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) - struct hlist_node *p; -#endif - - if (mask & MAY_NOT_BLOCK) - return -ECHILD; - - /* Find a dentry with valid d_count. Refer bug 587879. */ - hlist_for_each_entry(dentry, -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) - p, -#endif - &inode->i_dentry, - hgfs_d_alias()) { - int dcount = hgfs_d_count(dentry); - if (dcount) { - LOG(4, ("Found %s %d \n", dentry->d_name.name, dcount)); - return HgfsAccessInt(dentry, mask & (MAY_READ | MAY_WRITE | MAY_EXEC)); - } - } - ASSERT(FALSE); - } - return 0; -} -#else -static int -HgfsPermission(struct inode *inode, - int mask -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - , struct nameidata *nd -#elif defined(IPERM_FLAG_RCU) - , unsigned int flags -#endif - ) -{ - LOG(8, ("VMware hgfs: %s: inode->mode: %8x mask: %8x\n", __func__, - inode->i_mode, mask)); - /* - * For sys_access, we go to the host for permission checking; - * otherwise return 0. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - if (nd != NULL && (nd->flags & LOOKUP_ACCESS)) { /* For sys_access. */ -#else - if (mask & MAY_ACCESS) { /* For sys_access. */ -#endif - struct list_head *pos; - - /* - * In 2.6.38 path walk is done in 2 distinct modes: rcu-walk and - * ref-walk. Ref-walk is the classic one; rcu is lockless and is - * not allowed to sleep. We insist on using ref-walk since our - * transports may sleep. In 3.1 IPERM_FLAG_RCU was replaced with - * MAY_NOT_BLOCK. - */ -#if defined(MAY_NOT_BLOCK) - if (mask & MAY_NOT_BLOCK) - return -ECHILD; -#elif defined(IPERM_FLAG_RCU) - if (flags & IPERM_FLAG_RCU) - return -ECHILD; -#endif - - /* Find a dentry with valid d_count. Refer bug 587879. */ - list_for_each(pos, &inode->i_dentry) { - int dcount; - struct dentry *dentry = list_entry(pos, struct dentry, hgfs_d_alias()); - dcount = hgfs_d_count(dentry); - if (dcount) { - LOG(4, ("Found %s %d \n", (dentry)->d_name.name, dcount)); - return HgfsAccessInt(dentry, mask & (MAY_READ | MAY_WRITE | MAY_EXEC)); - } - } - ASSERT(FALSE); - } - return 0; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * HgfsGetattr -- - * - * Hgfs superblock 'getattr' method. - * - * Results: - * 0 on success - * error < 0 on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsGetattr(struct vfsmount *mnt, // Unused - struct dentry *dentry, // IN - struct kstat *stat) // OUT -{ - int err; - - // XXX ASSERT(mnt); ? --hpreg - ASSERT(dentry); - ASSERT(stat); - - err = HgfsRevalidate(dentry); - if (err) { - return err; - } - - /* Convert stats from the VFS inode format to the kernel format --hpreg */ - generic_fillattr(dentry->d_inode, stat); - // XXX Should we set stat->blocks and stat->blksize? --hpreg - - return 0; -} - -/* - * Public function implementations. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsSetattr -- - * - * Handle a setattr request. Call HgfsSetattrCopy to determine - * which fields need updating and convert them to the HgfsAttr - * format, then send the request to the server. - * - * Results: - * Returns zero on success, or a negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsSetattr(struct dentry *dentry, // IN: File to set attributes of - struct iattr *iattr) // IN: Attributes to set -{ - HgfsReq *req; - HgfsStatus replyStatus; - int result = 0; - Bool changed = FALSE; - Bool allowHandleReuse = TRUE; - HgfsOp opUsed; - - ASSERT(dentry); - ASSERT(dentry->d_inode); - ASSERT(dentry->d_sb); - ASSERT(iattr); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - /* Fill out the request packet. */ - opUsed = hgfsVersionSetattr; - result = HgfsPackSetattrRequest(iattr, dentry, allowHandleReuse, - opUsed, req, &changed); - if (result != 0 || !changed) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: no attrs changed\n")); - goto out; - } - - /* - * Flush all dirty pages prior to sending the request if we're going to - * modify the file size or change the last write time. - */ - if (iattr->ia_valid & ATTR_SIZE || iattr->ia_valid & ATTR_MTIME) { - ASSERT(dentry->d_inode->i_mapping); - compat_filemap_write_and_wait(dentry->d_inode->i_mapping); - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - /* - * If we modified the file size, we must truncate our pages from the - * page cache. - */ - if (iattr->ia_valid & ATTR_SIZE) { - result = HgfsTruncatePages(dentry->d_inode, iattr->ia_size); - } - - /* Fallthrough to revalidate. */ - case -EPERM: - /* - * Now that the server's attributes are updated, let's update our - * local view of them. Unfortunately, we can't trust iattr, because - * the server may have chosen to ignore certain attributes that we - * asked it to set. For example, a Windows server will have ignored - * the mode nearly entirely. Therefore, rather than calling - * inode_setattr() to update the inode with the contents of iattr, - * just force a revalidate. - * - * XXX: Note that EPERM gets similar treatment, as the server may - * have updated some of the attributes and still sent us an error. - */ - HgfsDentryAgeForce(dentry); - HgfsRevalidate(dentry); - break; - - case -EBADF: - /* - * This can happen if we attempted a setattr by handle and the handle - * was closed. Because we have no control over the backdoor, it's - * possible that an attacker closed our handle, in which case the - * driver still thinks the handle is open. So a straight-up - * "goto retry" would cause an infinite loop. Instead, let's retry - * with a setattr by name. - */ - if (allowHandleReuse) { - allowHandleReuse = FALSE; - goto retry; - } - - /* - * There's no reason why the server should have sent us this error - * when we haven't used a handle. But to prevent an infinite loop in - * the driver, let's make sure that we don't retry again. - */ - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_SETATTR_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: Version 3 " - "not supported. Falling back to version 2.\n")); - hgfsVersionSetattr = HGFS_OP_SETATTR_V2; - goto retry; - } else if (opUsed == HGFS_OP_SETATTR_V2) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: Version 2 " - "not supported. Falling back to version 1.\n")); - hgfsVersionSetattr = HGFS_OP_SETATTR; - goto retry; - } - - /* Fallthrough. */ - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsSetattr: unknown error: " - "%d\n", result)); - } - -out: - HgfsFreeRequest(req); - return result; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsRevalidate -- - * - * Called when the kernel wants to check that an inode is still - * valid. Called with the dentry that points to the inode we're - * interested in. - * - * We call HgfsPrivateGetattr with the inode's remote name, and if - * it succeeds we update the inode's attributes and return zero - * (success). Otherwise, we return an error. - * - * Results: - * Returns zero if inode is valid, negative error if not. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsRevalidate(struct dentry *dentry) // IN: Dentry to revalidate -{ - int error = 0; - HgfsSuperInfo *si; - unsigned long age; - HgfsInodeInfo *iinfo; - - ASSERT(dentry); - si = HGFS_SB_TO_COMMON(dentry->d_sb); - - if (!dentry->d_inode) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: null input\n")); - return -EINVAL; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: name %s, " - "inum %lu\n", dentry->d_name.name, dentry->d_inode->i_ino)); - - age = jiffies - dentry->d_time; - iinfo = INODE_GET_II_P(dentry->d_inode); - - if (age > si->ttl || iinfo->hostFileId == 0) { - HgfsAttrInfo attr; - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: dentry is too old, " - "getting new attributes\n")); - /* - * Sync unwritten file data so the file size on the server will - * be current with our view of the file. - */ - compat_filemap_write_and_wait(dentry->d_inode->i_mapping); - error = HgfsPrivateGetattr(dentry, &attr, NULL); - if (!error) { - /* - * If server provides file ID, we need to check whether it has changed - * since last revalidation. There might be a case that at server side - * the same file name has been used for other file during the period. - */ - if (attr.mask & HGFS_ATTR_VALID_FILEID) { - if (iinfo->hostFileId == 0) { - /* hostFileId was invalidated, so update it here */ - iinfo->hostFileId = attr.hostFileId; - } else if (iinfo->hostFileId != attr.hostFileId) { - LOG(4, ("VMware hgfs: %s: host file id mismatch. Expected " - "%"FMT64"u, got %"FMT64"u.\n", __func__, - iinfo->hostFileId, attr.hostFileId)); - return -EINVAL; - } - } - /* Update inode's attributes and reset the age. */ - HgfsChangeFileAttributes(dentry->d_inode, &attr); - HgfsDentryAgeReset(dentry); - } - } else { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: using cached dentry " - "attributes\n")); - } - - return error; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/inode.h b/open-vm-tools/modules/linux/vmhgfs/inode.h deleted file mode 100644 index 4d6f36d49..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/inode.h +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * inode.h -- - * - * Inode operations for the filesystem portion of the vmhgfs driver. - */ - -#ifndef _HGFS_DRIVER_INODE_H_ -#define _HGFS_DRIVER_INODE_H_ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include "compat_fs.h" - -/* Public functions (with respect to the entire module). */ -int HgfsSetattr(struct dentry *dentry, - struct iattr *iattr); -int HgfsRevalidate(struct dentry *dentry); - -#endif // _HGFS_DRIVER_INODE_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/link.c b/open-vm-tools/modules/linux/vmhgfs/link.c deleted file mode 100644 index c7b00eb86..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/link.c +++ /dev/null @@ -1,278 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * link.c -- - * - * Symlink-specific inode operations for the filesystem portion of the - * vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include "compat_fs.h" -#include "compat_namei.h" - -#include "module.h" -#include "hgfsProto.h" -#include "fsutil.h" -#include "vm_assert.h" - -/* HGFS symlink operations. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) -static const char *HgfsFollowlink(struct dentry *dentry, - void **cookie); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -static void *HgfsFollowlink(struct dentry *dentry, - struct nameidata *nd); -#else -static int HgfsFollowlink(struct dentry *dentry, - struct nameidata *nd); -#endif -static int HgfsReadlink(struct dentry *dentry, - char __user *buffer, - int buflen); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) -static void HgfsPutlink(struct inode *unused, - void *cookie); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -static void HgfsPutlink(struct dentry *dentry, - struct nameidata *nd, - void *cookie); -#else -static void HgfsPutlink(struct dentry *dentry, - struct nameidata *nd); -#endif - -/* HGFS inode operations structure for symlinks. */ -struct inode_operations HgfsLinkInodeOperations = { - .follow_link = HgfsFollowlink, - .readlink = HgfsReadlink, - .put_link = HgfsPutlink, -}; - -/* - * HGFS symlink operations. - */ - -/* - *---------------------------------------------------------------------- - * - * HgfsFollowlink -- - * - * Modeled after nfs_follow_link from a 2.4 kernel so it'll work - * across all kernel revisions we care about. - * - * Results: - * Returns zero on success, negative error on failure. - * - * On new kernels: The error is returned as void *. - * On older kernels: The error is returned as is. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) -static const char * -HgfsFollowlink(struct dentry *dentry, - void **cookie) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -static void * -HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link - struct nameidata *nd) // OUT: Contains target dentry -#else -static int -HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link - struct nameidata *nd) // OUT: Contains target dentry -#endif -{ - HgfsAttrInfo attr; - char *fileName = NULL; - int error; - - ASSERT(dentry); -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) - ASSERT(nd); -#endif - - if (!dentry) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: null input\n")); - error = -EINVAL; - goto out; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling HgfsPrivateGetattr %s\n", - __func__, dentry->d_name.name)); - error = HgfsPrivateGetattr(dentry, &attr, &fileName); - LOG(6, (KERN_DEBUG "VMware hgfs: %s: HgfsPrivateGetattr %s ret %d\n", - __func__, dentry->d_name.name, error)); - if (!error) { - - /* Let's make sure we got called on a symlink. */ - if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called " - "on something that wasn't a symlink\n")); - error = -EINVAL; - kfree(fileName); - } else { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling nd_set_link %s\n", - __func__, fileName)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) - *cookie = fileName; -#else - nd_set_link(nd, fileName); -#endif - } - } - -out: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) - if (!error) { - return *cookie; - } else { - return ERR_PTR(error); - } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) - return ERR_PTR(error); -#else - return error; -#endif -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) -#define HGFS_DO_READLINK(dentry,buffer,buflen,fileName) \ - readlink_copy(buffer, buflen, fileName) -#else -#define HGFS_DO_READLINK(dentry,buffer,buflen,fileName) \ - vfs_readlink(dentry, buffer, buflen, fileName) -#endif - -/* - *---------------------------------------------------------------------- - * - * HgfsReadlink -- - * - * Modeled after nfs_read_link from a 2.4 kernel so it'll work - * across all kernel revisions we care about. - * - * Results: - * Returns zero on success, negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsReadlink(struct dentry *dentry, // IN: Dentry containing link - char __user *buffer, // OUT: User buffer to copy link into - int buflen) // IN: Length of user buffer - -{ - HgfsAttrInfo attr; - char *fileName = NULL; - int error; - - ASSERT(dentry); - ASSERT(buffer); - - if (!dentry) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsReadlink: null input\n")); - return -EINVAL; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling HgfsPrivateGetattr %s\n", - __func__, dentry->d_name.name)); - error = HgfsPrivateGetattr(dentry, &attr, &fileName); - if (!error) { - - /* Let's make sure we got called on a symlink. */ - if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: got called " - "on something that wasn't a symlink\n")); - error = -EINVAL; - } else { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling vfs_readlink %s\n", - __func__, fileName)); - error = HGFS_DO_READLINK(dentry, buffer, buflen, fileName); - LOG(6, (KERN_DEBUG "VMware hgfs: %s: vfs_readlink %s ret %dn", - __func__, fileName, error)); - } - kfree(fileName); - } - return error; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPutlink -- - * - * Modeled after page_put_link from a 2.6.9 kernel so it'll work - * across all kernel revisions we care about. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) -static void -HgfsPutlink(struct inode *unused, - void *cookie) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -static void -HgfsPutlink(struct dentry *dentry, // dentry - struct nameidata *nd, // lookup name information - void *cookie) // cookie -#else -static void -HgfsPutlink(struct dentry *dentry, // dentry - struct nameidata *nd) // lookup name information -#endif -{ - char *fileName = NULL; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) - fileName = cookie; - LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n", - __func__, fileName)); -#else - LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n", - __func__, dentry->d_name.name)); - fileName = nd_get_link(nd); -#endif - if (!IS_ERR(fileName)) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: putting %s\n", - __func__, fileName)); - kfree(fileName); -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) - nd_set_link(nd, NULL); -#endif - } -} diff --git a/open-vm-tools/modules/linux/vmhgfs/module.c b/open-vm-tools/modules/linux/vmhgfs/module.c deleted file mode 100644 index dfee1869e..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/module.c +++ /dev/null @@ -1,109 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * module.c -- - * - * Module-specific components of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include "compat_module.h" - -#include "filesystem.h" -#include "module.h" -#include "vmhgfs_version.h" - -#ifdef VMX86_DEVEL -/* - * Logging is available only in devel build. - */ - -int LOGLEVEL_THRESHOLD = 4; -module_param(LOGLEVEL_THRESHOLD, int, 0444); -MODULE_PARM_DESC(LOGLEVEL_THRESHOLD, "Set verbosity (0 means no log, 10 means very verbose, 4 is default)"); -#endif - -/* Module information. */ -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Host/Guest File System"); -MODULE_VERSION(VMHGFS_DRIVER_VERSION_STRING); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("vmware_vmhgfs"); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); - - -/* - *---------------------------------------------------------------------- - * - * init_module -- - * - * linux module entry point. Called by /sbin/insmod command. - * Sets up internal state and registers the hgfs filesystem - * with the kernel. - * - * Results: - * Returns 0 on success, an error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -init_module(void) -{ - return HgfsInitFileSystem() ? 0 : -EBUSY; -} - - -/* - *---------------------------------------------------------------------- - * - * cleanup_module -- - * - * Called by /sbin/rmmod. Unregisters filesystem with kernel, - * cleans up internal state, and unloads module. - * - * Note: for true kernel 2.4 compliance, this should be - * "module_exit". - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -cleanup_module(void) -{ - HgfsCleanupFileSystem(); -} diff --git a/open-vm-tools/modules/linux/vmhgfs/module.h b/open-vm-tools/modules/linux/vmhgfs/module.h deleted file mode 100644 index 528a2e056..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/module.h +++ /dev/null @@ -1,251 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * module.h -- - * - * Global module definitions for the entire vmhgfs driver. - */ - -#ifndef _HGFS_DRIVER_MODULE_H_ -#define _HGFS_DRIVER_MODULE_H_ - -/* Must come before any kernel header file. */ -#include "driver-config.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) -#include -#endif -#include -#include "compat_fs.h" -#include "compat_semaphore.h" -#include "compat_slab.h" -#include "compat_spinlock.h" -#include "compat_version.h" - -#include "rpcout.h" -#include "hgfsProto.h" - -#ifndef __user -#define __user -#endif - -/* Logging stuff. */ -#define LGPFX "VMware hgfs: " - -#ifdef VMX86_DEVEL -extern int LOGLEVEL_THRESHOLD; -#define LOG(level, args) ((void) (LOGLEVEL_THRESHOLD >= (level) ? (printk args) : 0)) -#else -#define LOG(level, args) -#endif - -/* Blocksize to be set in superblock. (XXX how is this used?) */ -#define HGFS_BLOCKSIZE 1024 - -/* The amount of time we'll wait for the backdoor to process our request. */ -#define HGFS_REQUEST_TIMEOUT (30 * HZ) - -/* - * Inode number of the root inode. We set this to be non-zero because, - * according to glibc source, when the returned inode number in a dirent - * is zero, that entry has been deleted. This is presumably when you've done - * an opendir, the file is deleted, and then you do a readdir. The point is - * that if the root inode is zero, aliases to it (such as '.' and "..") won't - * appear in a directory listing. - */ -#define HGFS_ROOT_INO 1 - -/* Leave HGFS_ROOT_INO and below out of inode number generation. */ -#define HGFS_RESERVED_INO HGFS_ROOT_INO + 1 - -/* - * Macros for accessing members that are private to this code in - * sb/inode/file structs. - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) -typedef uid_t kuid_t; -typedef gid_t kgid_t; -#define from_kuid(_ns, _kuid) (_kuid) -#define from_kgid(_ns, _kgid) (_kgid) -#define make_kuid(_ns, _uid) (_uid) -#define make_kgid(_ns, _gid) (_gid) -#endif - -/* - * Since the f_dentry disappeared we do this locally. - * It is used quite extensively and only one other driver - * is affected by this so it is done locally and not - * as part of the common compat_fs.h includes. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) -#ifndef f_dentry -#define f_dentry f_path.dentry -#endif -#endif - -#define HGFS_SET_SB_TO_COMMON(sb, common) do { (sb)->s_fs_info = (common); } while (0) -#define HGFS_SB_TO_COMMON(sb) ((HgfsSuperInfo *)(sb)->s_fs_info) - -#define INODE_GET_II_P(_inode) container_of(_inode, HgfsInodeInfo, inode) - -#if defined VMW_INODE_2618 -#define INODE_SET_II_P(inode, info) do { (inode)->i_private = (info); } while (0) -#else -#define INODE_SET_II_P(inode, info) do { (inode)->u.generic_ip = (info); } while (0) -#endif - -#define HGFS_DECLARE_TIME(unixtm) struct timespec unixtm -#define HGFS_EQUAL_TIME(unixtm1, unixtm2) timespec_equal(&unixtm1, &unixtm2) -#define HGFS_SET_TIME(unixtm,nttime) HgfsConvertFromNtTimeNsec(&unixtm, nttime) -#define HGFS_GET_TIME(unixtm) HgfsConvertTimeSpecToNtTime(&unixtm) -#define HGFS_GET_CURRENT_TIME() ({ \ - struct timespec ct = CURRENT_TIME; \ - HGFS_GET_TIME(ct); \ - }) - -/* - * Beware! This macro returns list of two elements. Do not add braces around. - */ -#define HGFS_PRINT_TIME(unixtm) unixtm.tv_sec, unixtm.tv_nsec - -/* - * For files opened in our actual Host/Guest filesystem, the - * file->private_data field is used for storing the HgfsFileInfo of the - * opened file. This macro is for accessing the file information from the - * file *. - */ -#define FILE_SET_FI_P(file, info) do { (file)->private_data = info; } while (0) -#define FILE_GET_FI_P(file) ((HgfsFileInfo *)(file)->private_data) - -#define HGFS_MNT_SET_UID (1 << 0) /* Was the UID specified at mount-time? */ -#define HGFS_MNT_SET_GID (1 << 1) /* Was the GID specified at mount-time? */ -#define HGFS_MNT_SERVER_INUM (1 << 2) /* Use inode numbers from the server? */ - -/* Data kept in each superblock in sb->u. */ -typedef struct HgfsSuperInfo { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - struct backing_dev_info bdi; /* Kernel VFS uses it to check whether our backend - need to writeback dirty pages among other things. */ -#endif - kuid_t uid; /* UID of user who mounted this fs. */ - kgid_t gid; /* GID of user who mounted this fs. */ - mode_t fmask; /* File permission mask. */ - mode_t dmask; /* Directory permission mask. */ - uint32 ttl; /* Maximum dentry age (in ticks). */ - char *shareName; /* Mounted share name. */ - size_t shareNameLen; /* To avoid repeated strlen() calls. */ - uint32 mntFlags; /* HGFS mount flags */ -} HgfsSuperInfo; - -/* - * HGFS specific per-inode data. - */ -typedef struct HgfsInodeInfo { - /* Embedded inode. */ - struct inode inode; - - /* Inode number given by the host. */ - uint64 hostFileId; - - /* Was the inode number for this inode generated via iunique()? */ - Bool isFakeInodeNumber; - - /* Is this a fake inode created in HgfsCreate that has yet to be opened? */ - Bool createdAndUnopened; - - /* - * The number of write back pages to the file which is tracked so any - * concurrent file validations such as reads will not invalidate the cache. - */ - unsigned long numWbPages; - struct list_head listWbPages; - - /* List of open files for this inode. */ - struct list_head files; -} HgfsInodeInfo; - -/* - * HGFS specific per-file data. - */ -typedef struct HgfsFileInfo { - - /* Links to place this object on the inode's list of open files. */ - struct list_head list; - - /* Handle to be sent to the server. Needed for writepage(). */ - HgfsHandle handle; - - /* - * Mode with which handle was opened. When we reuse a handle, we need to - * choose one with appropriate permissions. - */ - HgfsOpenMode mode; - - /* - * Do we need to reopen a directory ? Note that this is only used - * for directories. - */ - Bool isStale; - - /* Directory read position for tracking. */ - loff_t direntPos; - -} HgfsFileInfo; - - -/* - * Global synchronization primitives. - */ - -/* - * We use hgfsBigLock to protect certain global structures that are locked for - * a very short amount of time. - */ -extern spinlock_t hgfsBigLock; - -/* Hgfs filesystem structs. */ -extern struct super_operations HgfsSuperOperations; -extern struct dentry_operations HgfsDentryOperations; -extern struct inode_operations HgfsFileInodeOperations; -extern struct inode_operations HgfsDirInodeOperations; -extern struct inode_operations HgfsLinkInodeOperations; -extern struct file_operations HgfsFileFileOperations; -extern struct file_operations HgfsDirFileOperations; -extern struct address_space_operations HgfsAddressSpaceOperations; - -/* Other global state. */ -extern compat_kmem_cache *hgfsInodeCache; - -extern HgfsOp hgfsVersionOpen; -extern HgfsOp hgfsVersionRead; -extern HgfsOp hgfsVersionWrite; -extern HgfsOp hgfsVersionClose; -extern HgfsOp hgfsVersionSearchOpen; -extern HgfsOp hgfsVersionSearchRead; -extern HgfsOp hgfsVersionSearchClose; -extern HgfsOp hgfsVersionGetattr; -extern HgfsOp hgfsVersionSetattr; -extern HgfsOp hgfsVersionCreateDir; -extern HgfsOp hgfsVersionDeleteFile; -extern HgfsOp hgfsVersionDeleteDir; -extern HgfsOp hgfsVersionRename; -extern HgfsOp hgfsVersionQueryVolumeInfo; -extern HgfsOp hgfsVersionCreateSymlink; - -#endif // _HGFS_DRIVER_MODULE_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/page.c b/open-vm-tools/modules/linux/vmhgfs/page.c deleted file mode 100644 index 0f5f7d39c..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/page.c +++ /dev/null @@ -1,2236 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * page.c -- - * - * Address space operations for the filesystem portion of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include - -#include "compat_mm.h" -#include "compat_page-flags.h" -#include "compat_fs.h" -#include "compat_kernel.h" -#include "compat_pagemap.h" -#include "compat_highmem.h" -#include - -#include "cpName.h" -#include "hgfsProto.h" -#include "module.h" -#include "request.h" -#include "hgfsUtil.h" -#include "fsutil.h" -#include "inode.h" -#include "vm_assert.h" -#include "vm_basic_types.h" -#include "vm_basic_defs.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) -#define HGFS_SM_MB_BEFORE smp_mb__before_atomic -#define HGFS_SM_MB_AFTER smp_mb__after_atomic -#else -/* - * Fedora 21 backported some of the atomic primitives so - * we test if they are defined and use them otherwise fallback - * to the older variants. - */ -#ifdef smp_mb__before_atomic -#define HGFS_SM_MB_BEFORE smp_mb__before_atomic -#else -#define HGFS_SM_MB_BEFORE smp_mb__before_clear_bit -#endif -#ifdef smp_mb__after_atomic -#define HGFS_SM_MB_AFTER smp_mb__after_atomic -#else -#define HGFS_SM_MB_AFTER smp_mb__after_clear_bit -#endif -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) -#define HGFS_PAGE_FILE_INDEX(page) page_file_index(page) -#else -#define HGFS_PAGE_FILE_INDEX(page) ((page)->index) -#endif - -/* Private functions. */ -static int HgfsDoWrite(HgfsHandle handle, - HgfsDataPacket dataPacket[], - uint32 numEntries, - loff_t offset); -static int HgfsDoRead(HgfsHandle handle, - HgfsDataPacket dataPacket[], - uint32 numEntries, - loff_t offset); -static int HgfsDoReadpage(HgfsHandle handle, - struct page *page, - unsigned pageFrom, - unsigned pageTo); -static int HgfsDoWritepage(HgfsHandle handle, - struct page *page, - unsigned pageFrom, - unsigned pageTo); -static int HgfsDoWriteBegin(struct file *file, - struct page *page, - unsigned pageFrom, - unsigned pageTo, - Bool canRetry, - Bool *doRetry); -static int HgfsDoWriteEnd(struct file *file, - struct page *page, - unsigned pageFrom, - unsigned pageTo, - loff_t writeTo, - unsigned copied); -static void HgfsDoExtendFile(struct inode *inode, - loff_t writeTo); - -/* HGFS address space operations. */ -static int HgfsReadpage(struct file *file, - struct page *page); -static int HgfsWritepage(struct page *page, - struct writeback_control *wbc); - -/* - * Write aop interface has changed in 2.6.28. Specifically, - * the page locking semantics and requirement to handle - * short writes. We already handle short writes, so no major - * changes needed. write_begin is expected to return a locked - * page and write_end is expected to unlock the page and drop - * the reference before returning. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) -static int HgfsWriteBegin(struct file *file, - struct address_space *mapping, - loff_t pos, - unsigned len, - unsigned flags, - struct page **page, - void **clientData); -static int HgfsWriteEnd(struct file *file, - struct address_space *mapping, - loff_t pos, - unsigned len, - unsigned copied, - struct page *page, - void *clientData); -#else -static int HgfsPrepareWrite(struct file *file, - struct page *page, - unsigned pageFrom, - unsigned pageTo); -static int HgfsCommitWrite(struct file *file, - struct page *page, - unsigned pageFrom, - unsigned pageTo); -#endif - -/* HGFS address space operations structure. */ -struct address_space_operations HgfsAddressSpaceOperations = { - .readpage = HgfsReadpage, - .writepage = HgfsWritepage, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) - .write_begin = HgfsWriteBegin, - .write_end = HgfsWriteEnd, -#else - .prepare_write = HgfsPrepareWrite, - .commit_write = HgfsCommitWrite, -#endif - .set_page_dirty = __set_page_dirty_nobuffers, -}; - -enum { - PG_BUSY = 0, -}; - -typedef struct HgfsWbPage { - struct list_head wb_list; /* Defines state of page: */ - struct page *wb_page; /* page to read in/write out */ - pgoff_t wb_index; /* Offset >> PAGE_CACHE_SHIFT */ - struct kref wb_kref; /* reference count */ - unsigned long wb_flags; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13) - wait_queue_head_t wb_queue; -#endif -} HgfsWbPage; - -static void HgfsInodePageWbAdd(struct inode *inode, - struct page *page); -static void HgfsInodePageWbRemove(struct inode *inode, - struct page *page); -static Bool HgfsInodePageWbFind(struct inode *inode, - struct page *page); -static void HgfsWbRequestDestroy(HgfsWbPage *req); -static Bool HgfsCheckReadModifyWrite(struct file *file, - struct page *page, - unsigned int pageFrom, - unsigned int pageTo); - - -/* - * Private functions. - */ - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoRead -- - * - * Do one read request. Called by HgfsReadpage, possibly multiple times - * if the size of the read is too big to be handled by one server request. - * - * We send a "Read" request to the server with the given handle. - * - * It is assumed that this function is never called with a larger read than - * what can be sent in one request. - * - * HgfsDataPacket is an array of pages into which data will be read. - * - * Results: - * Returns the number of bytes read on success, or an error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -HgfsDoRead(HgfsHandle handle, // IN: Handle for this file - HgfsDataPacket dataPacket[], // IN/OUT: Data description - uint32 numEntries, // IN: Number of entries in dataPacket - loff_t offset) // IN: Offset at which to read -{ - HgfsReq *req; - HgfsOp opUsed; - int result = 0; - uint32 actualSize = 0; - char *payload = NULL; - HgfsStatus replyStatus; - char *buf; - uint32 count; - ASSERT(numEntries == 1); - - count = dataPacket[0].len; - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionRead; - if (opUsed == HGFS_OP_READ_FAST_V4) { - HgfsRequest *header; - HgfsRequestReadV3 *request; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestReadV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->file = handle; - request->offset = offset; - request->requiredSize = count; - request->reserved = 0; - req->dataPacket = kmalloc(numEntries * sizeof req->dataPacket[0], - GFP_KERNEL); - if (!req->dataPacket) { - LOG(4, (KERN_WARNING "%s: Failed to allocate mem\n", __func__)); - result = -ENOMEM; - goto out; - } - memcpy(req->dataPacket, dataPacket, numEntries * sizeof req->dataPacket[0]); - req->numEntries = numEntries; - - LOG(4, (KERN_WARNING "VMware hgfs: Fast Read V4\n")); - } else if (opUsed == HGFS_OP_READ_V3) { - HgfsRequest *header; - HgfsRequestReadV3 *request; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestReadV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->file = handle; - request->offset = offset; - request->requiredSize = MIN(req->bufferSize - sizeof *request - - sizeof *header, count); - request->reserved = 0; - req->dataPacket = NULL; - req->numEntries = 0; - req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - } else { - HgfsRequestRead *request; - - request = (HgfsRequestRead *)(HGFS_REQ_PAYLOAD(req)); - request->header.id = req->id; - request->header.op = opUsed; - request->file = handle; - request->offset = offset; - request->requiredSize = MIN(req->bufferSize - sizeof *request, count); - req->dataPacket = NULL; - req->numEntries = 0; - req->payloadSize = sizeof *request; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - switch (result) { - case 0: - if (opUsed == HGFS_OP_READ_FAST_V4) { - actualSize = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize; - } else if (opUsed == HGFS_OP_READ_V3) { - actualSize = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize; - payload = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->payload; - } else { - actualSize = ((HgfsReplyRead *)HGFS_REQ_PAYLOAD(req))->actualSize; - payload = ((HgfsReplyRead *)HGFS_REQ_PAYLOAD(req))->payload; - } - - /* Sanity check on read size. */ - if (actualSize > count) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: read too big!\n")); - result = -EPROTO; - goto out; - } - - result = actualSize; - if (actualSize == 0) { - /* We got no bytes. */ - LOG(6, (KERN_WARNING "VMware hgfs: HgfsDoRead: server returned " - "zero\n")); - goto out; - } - - /* Return result. */ - if (opUsed == HGFS_OP_READ_V3 || opUsed == HGFS_OP_READ) { - buf = kmap(dataPacket[0].page) + dataPacket[0].offset; - ASSERT(buf); - memcpy(buf, payload, actualSize); - LOG(6, (KERN_WARNING "VMware hgfs: HgfsDoRead: copied %u\n", - actualSize)); - kunmap(dataPacket[0].page); - } - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - switch (opUsed) { - case HGFS_OP_READ_FAST_V4: - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: Fast Read V4 not " - "supported. Falling back to V3 Read.\n")); - if (req->dataPacket) { - kfree(req->dataPacket); - req->dataPacket = NULL; - } - hgfsVersionRead = HGFS_OP_READ_V3; - goto retry; - - case HGFS_OP_READ_V3: - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionRead = HGFS_OP_READ; - goto retry; - - default: - break; - } - break; - - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoRead: unknown error: " - "%d\n", result)); - } - -out: - if (req->dataPacket) { - kfree(req->dataPacket); - } - HgfsFreeRequest(req); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoWrite -- - * - * Do one write request. Called by HgfsDoWritepage, possibly multiple - * times if the size of the write is too big to be handled by one server - * request. - * - * We send a "Write" request to the server with the given handle. - * - * It is assumed that this function is never called with a larger write - * than what can be sent in one request. - * - * HgfsDataPacket is an array of pages from which data will be written - * to file. - * - * Results: - * Returns the number of bytes written on success, or an error on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file - HgfsDataPacket dataPacket[], // IN: Data description - uint32 numEntries, // IN: Number of entries in dataPacket - loff_t offset) // IN: Offset to begin writing at -{ - HgfsReq *req; - int result = 0; - HgfsOp opUsed; - uint32 requiredSize = 0; - uint32 actualSize = 0; - char *payload = NULL; - uint32 reqSize; - HgfsStatus replyStatus; - char *buf; - uint32 count; - ASSERT(numEntries == 1); - - count = dataPacket[0].len; - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionWrite; - if (opUsed == HGFS_OP_WRITE_FAST_V4) { - HgfsRequest *header; - HgfsRequestWriteV3 *request; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestWriteV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->file = handle; - request->flags = 0; - request->offset = offset; - request->requiredSize = count; - request->reserved = 0; - payload = request->payload; - requiredSize = request->requiredSize; - - req->dataPacket = kmalloc(numEntries * sizeof req->dataPacket[0], - GFP_KERNEL); - if (!req->dataPacket) { - LOG(4, (KERN_WARNING "%s: Failed to allocate mem\n", __func__)); - result = -ENOMEM; - goto out; - } - memcpy(req->dataPacket, dataPacket, numEntries * sizeof req->dataPacket[0]); - req->numEntries = numEntries; - reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - req->payloadSize = reqSize; - LOG(4, (KERN_WARNING "VMware hgfs: Fast Write V4\n")); - } else if (opUsed == HGFS_OP_WRITE_V3) { - HgfsRequest *header; - HgfsRequestWriteV3 *request; - - header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - header->id = req->id; - header->op = opUsed; - - request = (HgfsRequestWriteV3 *)(HGFS_REQ_PAYLOAD_V3(req)); - request->file = handle; - request->flags = 0; - request->offset = offset; - request->requiredSize = MIN(req->bufferSize - sizeof *header - - sizeof *request, count); - LOG(4, (KERN_WARNING "VMware hgfs: Using write V3\n")); - request->reserved = 0; - payload = request->payload; - requiredSize = request->requiredSize; - reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); - req->dataPacket = NULL; - req->numEntries = 0; - buf = kmap(dataPacket[0].page) + dataPacket[0].offset; - memcpy(payload, buf, requiredSize); - kunmap(dataPacket[0].page); - - req->payloadSize = reqSize + requiredSize - 1; - } else { - HgfsRequestWrite *request; - - request = (HgfsRequestWrite *)(HGFS_REQ_PAYLOAD(req)); - request->header.id = req->id; - request->header.op = opUsed; - request->file = handle; - request->flags = 0; - request->offset = offset; - request->requiredSize = MIN(req->bufferSize - sizeof *request, count); - payload = request->payload; - requiredSize = request->requiredSize; - reqSize = sizeof *request; - req->dataPacket = NULL; - req->numEntries = 0; - buf = kmap(dataPacket[0].page) + dataPacket[0].offset; - memcpy(payload, buf, requiredSize); - kunmap(dataPacket[0].page); - - req->payloadSize = reqSize + requiredSize - 1; - } - - /* Send the request and process the reply. */ - result = HgfsSendRequest(req); - if (result == 0) { - /* Get the reply. */ - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: res %u\n", result)); - switch (result) { - case 0: - if (opUsed == HGFS_OP_WRITE_V3 || opUsed == HGFS_OP_WRITE_FAST_V4) { - actualSize = ((HgfsReplyWriteV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize; - } else { - actualSize = ((HgfsReplyWrite *)HGFS_REQ_PAYLOAD(req))->actualSize; - } - - /* Return result. */ - LOG(6, (KERN_WARNING "VMware hgfs: HgfsDoWrite: wrote %u bytes\n", - actualSize)); - result = actualSize; - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - switch (opUsed) { - case HGFS_OP_WRITE_FAST_V4: - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: Fast Write V4 not " - "supported. Falling back to V3 write.\n")); - if (req->dataPacket) { - kfree(req->dataPacket); - req->dataPacket = NULL; - } - hgfsVersionWrite = HGFS_OP_WRITE_V3; - goto retry; - - case HGFS_OP_WRITE_V3: - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionWrite = HGFS_OP_WRITE; - goto retry; - - default: - break; - } - break; - - default: - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: server " - "returned error: %d\n", result)); - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: server " - "returned error: %d\n", result)); - } else { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoWrite: unknown error: " - "%d\n", result)); - } - -out: - if (req->dataPacket) { - kfree(req->dataPacket); - } - HgfsFreeRequest(req); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoReadpage -- - * - * Reads in a single page, using the specified handle and page offsets. - * At the time of writing, HGFS_IO_MAX == PAGE_CACHE_SIZE, so we could - * avoid the do {} while() and just read the page as is, but in case the - * above assumption is ever broken, it's nice that this will continue to - * "just work". - * - * Results: - * Zero on success, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsDoReadpage(HgfsHandle handle, // IN: Handle to use for reading - struct page *page, // IN/OUT: Page to read into - unsigned pageFrom, // IN: Where to start reading to - unsigned pageTo) // IN: Where to stop reading -{ - int result = 0; - loff_t curOffset = ((loff_t)HGFS_PAGE_FILE_INDEX(page) << PAGE_CACHE_SHIFT) + pageFrom; - size_t nextCount, remainingCount = pageTo - pageFrom; - HgfsDataPacket dataPacket[1]; - - LOG(6, (KERN_WARNING "VMware hgfs: HgfsDoReadpage: read %Zu bytes from fh %u " - "at offset %Lu\n", remainingCount, handle, curOffset)); - - /* - * Call HgfsDoRead repeatedly until either - * - HgfsDoRead returns an error, or - * - HgfsDoRead returns 0 (end of file), or - * - We have read the requested number of bytes. - */ - do { - nextCount = (remainingCount > HGFS_IO_MAX) ? - HGFS_IO_MAX : remainingCount; - dataPacket[0].page = page; - dataPacket[0].offset = pageFrom; - dataPacket[0].len = nextCount; - result = HgfsDoRead(handle, dataPacket, 1, curOffset); - if (result < 0) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsDoReadpage: read error %d\n", - result)); - goto out; - } - remainingCount -= result; - curOffset += result; - pageFrom += result; - } while ((result > 0) && (remainingCount > 0)); - - /* - * It's possible that despite being asked to read a full page, there is less - * than a page in the file from this offset, so we should zero the rest of - * the page's memory. - */ - if (remainingCount) { - char *buffer = kmap(page) + pageTo; - LOG(6, (KERN_DEBUG "VMware hgfs: %s: zeroing last %Zu bytes\n", - __func__, remainingCount)); - memset(buffer - remainingCount, 0, remainingCount); - kunmap(page); - } - - /* - * We read a full page (or all of the page that actually belongs to the - * file), so mark it up to date. Also, flush the old page data from the data - * cache. - */ - flush_dcache_page(page); - SetPageUptodate(page); - result = 0; - - out: - compat_unlock_page(page); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoWritepageInt -- - * - * Writes out a single page, using the specified handle and page offsets. - * At the time of writing, HGFS_IO_MAX == PAGE_CACHE_SIZE, so we could - * avoid the do {} while() and just write the page as is, but in case the - * above assumption is ever broken, it's nice that this will continue to - * "just work". - * - * Results: - * Number of bytes copied on success, negative error on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsDoWritepageInt(HgfsHandle handle, // IN: Handle to use for writing - struct page *page, // IN: Page containing data to write - unsigned pageFrom, // IN: Beginning page offset - unsigned pageTo) // IN: Ending page offset -{ - int result = 0; - loff_t curOffset = ((loff_t)HGFS_PAGE_FILE_INDEX(page) << PAGE_CACHE_SHIFT) + pageFrom; - size_t nextCount; - size_t remainingCount = pageTo - pageFrom; - struct inode *inode; - HgfsDataPacket dataPacket[1]; - - ASSERT(page->mapping); - ASSERT(page->mapping->host); - inode = page->mapping->host; - - LOG(4, (KERN_WARNING "VMware hgfs: %s: start writes at %Lu\n", - __func__, curOffset)); - /* - * Call HgfsDoWrite repeatedly until either - * - HgfsDoWrite returns an error, or - * - HgfsDoWrite returns 0 (XXX this probably rarely happens), or - * - We have written the requested number of bytes. - */ - do { - nextCount = (remainingCount > HGFS_IO_MAX) ? - HGFS_IO_MAX : remainingCount; - dataPacket[0].page = page; - dataPacket[0].offset = pageFrom; - dataPacket[0].len = nextCount; - result = HgfsDoWrite(handle, dataPacket, 1, curOffset); - if (result < 0) { - LOG(4, (KERN_WARNING "VMware hgfs: %s: write error %d\n", - __func__, result)); - goto exit; - } - remainingCount -= result; - curOffset += result; - pageFrom += result; - - /* Update the inode's size now rather than waiting for a revalidate. */ - HgfsDoExtendFile(inode, curOffset); - } while ((result > 0) && (remainingCount > 0)); - -exit: - if (result >= 0) { - result = pageTo - pageFrom - remainingCount; - } - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoWritepage -- - * - * Writes out a single page, using the specified handle and page offsets. - * At the time of writing, HGFS_IO_MAX == PAGE_CACHE_SIZE, so we could - * avoid the do {} while() and just write the page as is, but in case the - * above assumption is ever broken, it's nice that this will continue to - * "just work". - * - * A quick note about appending to files. Before HGFS used the page cache, - * an HgfsWrite examined a file's f_flags and added HGFS_WRITE_APPEND to - * the write packet if the file was opened with O_APPEND. This causes the - * server to reopen the fd with O_APPEND so that writes will append to the - * end. - * - * In the page cache world, this won't work because we may have arrived at - * this function via writepage(), which doesn't give us a particular file - * and thus we don't know if we should be appending or not. In fact, the - * generic write path employed by the page cache handles files with O_APPEND - * set by moving the file offset to the result of i_size_read(). So we - * shouldn't ever need to set HGFS_WRITE_APPEND, as now we will handle all - * write appends, instead of telling the server to do it for us. - * - * Results: - * Zero on success, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsDoWritepage(HgfsHandle handle, // IN: Handle to use for writing - struct page *page, // IN: Page containing data to write - unsigned pageFrom, // IN: Beginning page offset - unsigned pageTo) // IN: Ending page offset -{ - int result = 0; - - LOG(4, (KERN_WARNING "VMware hgfs: %s: start writes at %u to %u\n", - __func__, pageFrom, pageTo)); - - result = HgfsDoWritepageInt(handle, page, pageFrom, pageTo); - if (result < 0) { - goto exit; - } - - HgfsInodePageWbRemove(page->mapping->host, page); - - result = 0; - SetPageUptodate(page); - -exit: - LOG(4, (KERN_WARNING "VMware hgfs: %s: return %d\n", __func__, result)); - return result; -} - - -/* - * HGFS address space operations. - */ - -/* - *----------------------------------------------------------------------------- - * - * HgfsReadpage -- - * - * Read a page from an open file. Like HgfsWritepage, there are some - * complicated locking rules governing this function. The page arrives from - * the VFS locked, and we must unlock it before exiting. In addition, we - * must acquire a reference to the page before mapping it, and we must - * flush the page's data from the data cache (not to be confused with - * dcache i.e. the dentry cache). - * - * Results: - * Zero on success, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsReadpage(struct file *file, // IN: File to read from - struct page *page) // IN/OUT: Page to write to -{ - int result = 0; - HgfsHandle handle; - - ASSERT(file); - ASSERT(file->f_dentry); - ASSERT(file->f_dentry->d_inode); - ASSERT(page); - - handle = FILE_GET_FI_P(file)->handle; - LOG(6, (KERN_WARNING "VMware hgfs: %s: reading from handle %u\n", - __func__, handle)); - - page_cache_get(page); - result = HgfsDoReadpage(handle, page, 0, PAGE_CACHE_SIZE); - page_cache_release(page); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsWritepage -- - * - * The "spontaneous" way to write a page, called when the kernel is under - * memory pressure or is asked to sync a memory mapped file. Because - * writepage() can be called from so many different places, we don't get a - * filp with which to write, and we have to be very careful about races and - * locking. - * - * Results: - * Zero on success, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsWritepage(struct page *page, // IN: Page to write from - struct writeback_control *wbc) // IN: Ignored -{ - struct inode *inode; - HgfsHandle handle; - int result; - pgoff_t lastPageIndex; - pgoff_t pageIndex; - loff_t currentFileSize; - unsigned to = PAGE_CACHE_SIZE; - - ASSERT(page); - ASSERT(page->mapping); - ASSERT(page->mapping->host); - inode = page->mapping->host; - - /* We need a writable file handle. */ - result = HgfsGetHandle(inode, - HGFS_OPEN_MODE_WRITE_ONLY + 1, - &handle); - if (result) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsWritepage: could not get writable " - "file handle\n")); - goto exit; - } - - /* - * We were given an entire page to write. In most cases this means "start - * writing from the beginning of the page (byte 0) to the very end (byte - * PAGE_CACHE_SIZE). But what if this is the last page of the file? Then - * we don't want to write a full PAGE_CACHE_SIZE bytes, but just however - * many bytes may remain in the page. - * - * XXX: Other filesystems check the page index to make sure that the page - * we're being asked to write is within the size of the file. I guess - * that's because writepage() can race with truncate(), and if we find - * ourselves here after a truncate(), we can drop the write. - */ - currentFileSize = compat_i_size_read(inode); - lastPageIndex = currentFileSize >> PAGE_CACHE_SHIFT; - pageIndex = HGFS_PAGE_FILE_INDEX(page); - LOG(4, (KERN_WARNING "VMware hgfs: %s: file size lpi %lu pi %lu\n", - __func__, lastPageIndex, pageIndex)); - if (pageIndex > lastPageIndex) { - goto exit; - } else if (pageIndex == lastPageIndex) { - to = currentFileSize & (PAGE_CACHE_SIZE - 1); - if (to == 0) { - goto exit; - } - } - - /* - * This part is fairly intricate, so it deserves some explanation. We're - * really interested in calling HgfsDoWritepage with our page and - * handle, without having to then worry about locks or references. See - * Documentation/filesystems/Locking in the kernel to see what rules we - * must obey. - * - * Firstly, we acquire a reference to the page via page_cache_get() and call - * compat_set_page_writeback(). The latter does a number of things: it sets - * the writeback bit on the page, and if it wasn't already set, it sets the - * writeback bit in the radix tree. Then, if the page isn't dirty, it clears - * the dirty bit in the radix tree. The end result is that the radix tree's - * notion of dirty and writeback is fully synced with the page itself. - * - * Secondly, we write the page itself. - * - * Thirdly, we end writeback of the page via compat_end_page_writeback(), - * and release our reference on the page. - * - * Finally, we unlock the page, waking up its waiters and making it - * available to anyone else. Note that this step must be performed - * regardless of whether we wrote anything, as the VFS locked the page for - * us. - */ - page_cache_get(page); - compat_set_page_writeback(page); - result = HgfsDoWritepage(handle, page, 0, to); - compat_end_page_writeback(page); - page_cache_release(page); - - exit: - compat_unlock_page(page); - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoWriteBegin -- - * - * Helper function for HgfsWriteBegin / HgfsPrepareWrite. - * - * Initialize the page if the file is to be appended. - * - * Results: - * Zero on success, always. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsDoWriteBegin(struct file *file, // IN: File to be written - struct page *page, // IN: Page to be written - unsigned pageFrom, // IN: Starting page offset - unsigned pageTo, // IN: Ending page offset - Bool canRetry, // IN: can we retry write - Bool *doRetry) // OUT: set to retry if necessary -{ - ASSERT(page); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: off %Lu: %u to %u\n", __func__, - (loff_t)HGFS_PAGE_FILE_INDEX(page) << PAGE_CACHE_SHIFT, pageFrom, pageTo)); - - if (canRetry && HgfsCheckReadModifyWrite(file, page, pageFrom, pageTo)) { - HgfsHandle readHandle; - int result; - result = HgfsGetHandle(page->mapping->host, - HGFS_OPEN_MODE_READ_ONLY + 1, - &readHandle); - if (result == 0) { - /* - * We have a partial page write and thus require non-written part if the page - * is to contain valid data. - * A read of the page of the valid file data will set the page up to date. - * If it fails the page will not be set up to date and the write end will write - * the data out immediately (synchronously effectively). - */ - result = HgfsDoReadpage(readHandle, page, 0, PAGE_CACHE_SIZE); - *doRetry = TRUE; - } - LOG(6, (KERN_DEBUG "VMware hgfs: %s: HgfsReadpage result %d\n", __func__, result)); - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: returns 0\n", __func__)); - return 0; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) -/* - *----------------------------------------------------------------------------- - * - * HgfsPrepareWrite -- - * - * Called by the generic write path to set up a write request for a page. - * We're expected to do any pre-allocation and housekeeping prior to - * receiving the write. - * - * Results: - * On success zero, always. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsPrepareWrite(struct file *file, // IN: File to be written - struct page *page, // IN: Page to prepare - unsigned pageFrom, // IN: Beginning page offset - unsigned pageTo) // IN: Ending page offset -{ - Bool dummyCanRetry = FALSE; - return HgfsDoWriteBegin(file, page, pageFrom, pageTo, FALSE, &dummyCanRetry); -} - -#else - - -/* - *----------------------------------------------------------------------------- - * - * HgfsWriteBegin -- - * - * Called by the generic write path to set up a write request for a page. - * We're expected to do any pre-allocation and housekeeping prior to - * receiving the write. - * - * This function is expected to return a locked page. - * - * Results: - * Zero on success, non-zero error otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsWriteBegin(struct file *file, // IN: File to be written - struct address_space *mapping, // IN: Mapping - loff_t pos, // IN: File position - unsigned len, // IN: Bytes to be written - unsigned flags, // IN: Write flags - struct page **pagePtr, // OUT: Locked page - void **clientData) // OUT: Opaque to pass to write_end, unused -{ - pgoff_t index = pos >> PAGE_CACHE_SHIFT; - unsigned pageFrom = pos & (PAGE_CACHE_SIZE - 1); - unsigned pageTo = pageFrom + len; - struct page *page; - int result; - Bool canRetry = TRUE; - Bool doRetry; - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%s/%s(%ld), %u@%lld)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - mapping->host->i_ino, len, (long long) pos)); - - do { - doRetry = FALSE; - page = compat_grab_cache_page_write_begin(mapping, index, flags); - if (page == NULL) { - result = -ENOMEM; - goto exit; - } - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: file size %Lu @ %Lu page %u to %u\n", __func__, - (loff_t)compat_i_size_read(page->mapping->host), - (loff_t)HGFS_PAGE_FILE_INDEX(page) << PAGE_CACHE_SHIFT, - pageFrom, pageTo)); - - result = HgfsDoWriteBegin(file, page, pageFrom, pageTo, canRetry, &doRetry); - ASSERT(result == 0); - canRetry = FALSE; - if (doRetry) { - page_cache_release(page); - } - } while (doRetry); - -exit: - *pagePtr = page; - LOG(6, (KERN_DEBUG "VMware hgfs: %s: return %d\n", __func__, result)); - return result; -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoExtendFile -- - * - * Helper function for extending a file size. - * - * This function updates the inode->i_size, under the inode lock. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsDoExtendFile(struct inode *inode, // IN: File we're writing to - loff_t writeTo) // IN: Offset we're written to -{ - loff_t currentFileSize; - - spin_lock(&inode->i_lock); - currentFileSize = compat_i_size_read(inode); - - if (writeTo > currentFileSize) { - compat_i_size_write(inode, writeTo); - } - spin_unlock(&inode->i_lock); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsZeroUserSegments -- - * - * Wrapper function for setting a page's segments. - * - * This function updates the inode->i_size, under the inode lock. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsZeroUserSegments(struct page *page, // IN: Page we're writing to - unsigned int start1, // IN: segment 1 start - unsigned int end1, // IN: segment 1 end - unsigned int start2, // IN: segment 2 start - unsigned int end2) // IN: segment 2 end -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) - zero_user_segments(page, start1, end1, start2, end2); -#else - void *kaddr = compat_kmap_atomic(page); - if (end1 > start1) { - memset(kaddr + start1, 0, end1 - start1); - } - if (end2 > start2) { - memset(kaddr + start2, 0, end2 - start2); - } - compat_kunmap_atomic(kaddr); - flush_dcache_page(page); -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsZeroUserSegments -- - * - * Wrapper function for zeroing a page's segments. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsZeroUserSegment(struct page *page, // IN: Page we're writing to - unsigned int start, // IN: segment 1 start - unsigned int end) // IN: segment 1 end -{ - HgfsZeroUserSegments(page, start, end, 0, 0); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsGetPageLength -- - * - * Helper function for finding the extent of valid file data in a page. - * - * Results: - * The page valid data length. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static unsigned int -HgfsGetPageLength(struct page *page) // IN: Page we're writing to -{ - loff_t currentFileSize; - unsigned int pageLength = 0; - - currentFileSize = compat_i_size_read(page->mapping->host); - if (currentFileSize > 0) { - pgoff_t pageIndex = HGFS_PAGE_FILE_INDEX(page); - pgoff_t fileSizeIndex = (currentFileSize - 1) >> PAGE_CACHE_SHIFT; - - if (pageIndex < fileSizeIndex) { - pageLength = PAGE_CACHE_SIZE; - } else if (pageIndex == fileSizeIndex) { - pageLength = ((currentFileSize - 1) & ~PAGE_CACHE_MASK) + 1; - } - } - - return pageLength; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDoWriteEnd -- - * - * Helper function for HgfsWriteEnd. - * - * This function updates the inode->i_size, conditionally marks the page - * updated and carries out the actual write in case of partial page writes. - * - * Results: - * Zero on succes, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsDoWriteEnd(struct file *file, // IN: File we're writing to - struct page *page, // IN: Page we're writing from - unsigned pageFrom, // IN: Starting page offset - unsigned pageTo, // IN: Ending page offset - loff_t writeTo, // IN: File position to write to - unsigned copied) // IN: Number of bytes copied to the page -{ - struct inode *inode; - - ASSERT(file); - ASSERT(page); - inode = page->mapping->host; - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%s/%s(%ld), from %u to %u@%lld => %u)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - page->mapping->host->i_ino, pageFrom, pageTo, (long long) writeTo, copied)); - - /* - * Zero any uninitialised parts of the page, and then mark the page - * as up to date if it turns out that we're extending the file. - */ - if (!PageUptodate(page)) { - unsigned int pageLength = HgfsGetPageLength(page); - - if (pageLength == 0) { - /* No file valid data in this page. Zero unwritten segments only. */ - HgfsZeroUserSegments(page, 0, pageFrom, pageTo, PAGE_CACHE_SIZE); - SetPageUptodate(page); - } else if (pageTo >= pageLength) { - /* Some file valid data in this page. Zero unwritten segments only. */ - HgfsZeroUserSegment(page, pageTo, PAGE_CACHE_SIZE); - if (pageTo == 0) { - /* Overwritten all file valid data in this page. So the page is uptodate. */ - SetPageUptodate(page); - } - } else { - /* Overwriting part of the valid file data. */ - HgfsZeroUserSegment(page, pageLength, PAGE_CACHE_SIZE); - } - } - - - if (!PageUptodate(page)) { - HgfsHandle handle = FILE_GET_FI_P(file)->handle; - int result; - - /* Do a synchronous write since we have a partial page write of data. */ - result = HgfsDoWritepageInt(handle, page, pageFrom, pageTo); - if (result == 0) { - LOG(6, (KERN_WARNING "VMware hgfs: %s: sync write return %d\n", __func__, result)); - } - } else { - /* Page to write contains all valid data. */ - set_page_dirty(page); - /* - * Track the pages being written. - */ - HgfsInodePageWbAdd(inode, page); - } - - HgfsDoExtendFile(inode, writeTo); - - LOG(6, (KERN_WARNING "VMware hgfs: %s: return 0\n", __func__)); - return 0; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) -/* - *----------------------------------------------------------------------------- - * - * HgfsCommitWrite -- - * - * This function is the more common write path for HGFS, called from - * generic_file_buffered_write. It is much simpler for us than - * HgfsWritepage above: the caller has obtained a reference to the page - * and will unlock it when we're done. And we don't need to worry about - * properly marking the writeback bit, either. See mm/filemap.c in the - * kernel for details about how we are called. - * - * Results: - * Zero on succes, non-zero on error. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsCommitWrite(struct file *file, // IN: File to write - struct page *page, // IN: Page to write from - unsigned pageFrom, // IN: Starting page offset - unsigned pageTo) // IN: Ending page offset -{ - loff_t offset; - loff_t writeTo; - unsigned copied; - - ASSERT(page); - ASSERT(file); - - offset = (loff_t)HGFS_PAGE_FILE_INDEX(page) << PAGE_CACHE_SHIFT; - writeTo = offset + pageTo; - copied = pageTo - pageFrom; - - return HgfsDoWriteEnd(file, page, pageFrom, pageTo, writeTo, copied); -} - -#else - - -/* - *----------------------------------------------------------------------------- - * - * HgfsWriteEnd -- - * - * This function is the more common write path for HGFS, called from - * generic_file_buffered_write. It is much simpler for us than - * HgfsWritepage above: write_begin has obtained a reference to the page - * and we will unlock it when we're done. And we don't need to worry about - * properly marking the writeback bit, either. See mm/filemap.c in the - * kernel for details about how we are called. - * - * This function should unlock the page and reduce the refcount. - * - * Results: - * Number of bytes written or negative error - * - * Side effects: - * Unlocks the page and drops the reference. - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsWriteEnd(struct file *file, // IN: File to write - struct address_space *mapping, // IN: Mapping - loff_t pos, // IN: File position - unsigned len, // IN: len passed from write_begin - unsigned copied, // IN: Number of actually copied bytes - struct page *page, // IN: Page to write from - void *clientData) // IN: From write_begin, unused. -{ - unsigned pageFrom = pos & (PAGE_CACHE_SIZE - 1); - unsigned pageTo = pageFrom + len; - loff_t writeTo = pos + copied; - int ret; - - ASSERT(file); - ASSERT(mapping); - ASSERT(page); - - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%s/%s(%ld), %u@%lld,=>%u)\n", - __func__, file->f_dentry->d_parent->d_name.name, - file->f_dentry->d_name.name, - mapping->host->i_ino, len, (long long) pos, copied)); - - if (copied < len) { - HgfsZeroUserSegment(page, pageFrom + copied, pageFrom + len); - } - - ret = HgfsDoWriteEnd(file, page, pageFrom, pageTo, writeTo, copied); - if (ret == 0) { - ret = copied; - } - - compat_unlock_page(page); - page_cache_release(page); - LOG(6, (KERN_WARNING "VMware hgfs: %s: return %d\n", __func__, ret)); - return ret; -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbPageAlloc -- - * - * Allocates a write-back page object. - * - * Results: - * The write-back page object - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static inline HgfsWbPage * -HgfsWbPageAlloc(void) -{ - return kmalloc(sizeof (HgfsWbPage), GFP_KERNEL); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbPageAlloc -- - * - * Frees a write-back page object. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - - -static inline void -HgfsWbPageFree(HgfsWbPage *page) // IN: request of page data to write -{ - ASSERT(page); - kfree(page); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestFree -- - * - * Frees the resources for a write-back page request. - * Calls the request destroy and then frees the object memory. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsWbRequestFree(struct kref *kref) // IN: ref field request of page data to write -{ - HgfsWbPage *req = container_of(kref, HgfsWbPage, wb_kref); - - /* Release write back request page and free it. */ - HgfsWbRequestDestroy(req); - HgfsWbPageFree(req); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestGet -- - * - * Reference the write-back page request. - * Calls the request destroy and then frees the object memory. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsWbRequestGet(HgfsWbPage *req) // IN: request of page data to write -{ - kref_get(&req->wb_kref); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestPut -- - * - * Remove a reference the write-back page request. - * Calls the request free to tear down the object memory if it was the - * final one. - * - * Results: - * None - * - * Side effects: - * Destroys the request if last one. - * - *---------------------------------------------------------------------- - */ - -void -HgfsWbRequestPut(HgfsWbPage *req) // IN: request of page data to write -{ - kref_put(&req->wb_kref, HgfsWbRequestFree); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestWaitUninterruptible -- - * - * Sleep function while waiting for requests to complete. - * - * Results: - * Always zero. - * - * Side effects: -* None - * - *---------------------------------------------------------------------- - */ - -#if !defined VMW_WAITONBIT_317 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) -static int -HgfsWbRequestWaitUninterruptible(void *word) // IN:unused -{ - io_schedule(); - return 0; -} -#endif - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestWait -- - * - * Wait for a write-back page request to complete. - * Interruptible by fatal signals only. - * The user is responsible for holding a count on the request. - * - * Results: - * Returned value will be zero if the bit was cleared, - * non-zero if the process received a signal and the mode - * permitted wakeup on that signal. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - - -int -HgfsWbRequestWait(HgfsWbPage *req) // IN: request of page data to write -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) - return wait_on_bit_io(&req->wb_flags, - PG_BUSY, - TASK_UNINTERRUPTIBLE); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) - return wait_on_bit(&req->wb_flags, - PG_BUSY, -#if !defined VMW_WAITONBIT_317 && LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) - HgfsWbRequestWaitUninterruptible, -#endif - TASK_UNINTERRUPTIBLE); -#else - wait_event(req->wb_queue, - !test_bit(PG_BUSY, &req->wb_flags)); - return 0; -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestLock -- - * - * Lock the write-back page request. - * - * Results: - * Non-zero if the lock was not already locked - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static inline int -HgfsWbRequestLock(HgfsWbPage *req) // IN: request of page data to write -{ - return !test_and_set_bit(PG_BUSY, &req->wb_flags); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestUnlock -- - * - * Unlock the write-back page request. - * Wakes up any waiting threads on the lock. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsWbRequestUnlock(HgfsWbPage *req) // IN: request of page data to write -{ - if (!test_bit(PG_BUSY,&req->wb_flags)) { - LOG(6, (KERN_WARNING "VMware Hgfs: %s: Invalid unlock attempted\n", __func__)); - return; - } - HGFS_SM_MB_BEFORE(); - clear_bit(PG_BUSY, &req->wb_flags); - HGFS_SM_MB_AFTER(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) - wake_up_bit(&req->wb_flags, PG_BUSY); -#else - wake_up(&req->wb_queue); -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestUnlockAndPut -- - * - * Unlock the write-back page request and removes a reference. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsWbRequestUnlockAndPut(HgfsWbPage *req) // IN: request of page data to write -{ - HgfsWbRequestUnlock(req); - HgfsWbRequestPut(req); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestListAdd -- - * - * Add the write-back page request into the list. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static inline void -HgfsWbRequestListAdd(HgfsWbPage *req, // IN: request of page data to write - struct list_head *head) // IN: list of requests -{ - list_add_tail(&req->wb_list, head); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestListRemove -- - * - * Remove the write-back page request from the list. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static inline void -HgfsWbRequestListRemove(HgfsWbPage *req) // IN: request of page data to write -{ - if (!list_empty(&req->wb_list)) { - list_del_init(&req->wb_list); - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestCreate -- - * - * Create the write-back page request. - * - * Results: - * The new write-back page request. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsWbPage * -HgfsWbRequestCreate(struct page *page) // IN: page of data to write -{ - HgfsWbPage *wbReq; - /* try to allocate the request struct */ - wbReq = HgfsWbPageAlloc(); - if (wbReq == NULL) { - wbReq = ERR_PTR(-ENOMEM); - goto exit; - } - - /* - * Initialize the request struct. Initially, we assume a - * long write-back delay. This will be adjusted in - * update_nfs_request below if the region is not locked. - */ - wbReq->wb_flags = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13) - init_waitqueue_head(&wbReq->wb_queue); -#endif - INIT_LIST_HEAD(&wbReq->wb_list); - wbReq->wb_page = page; - wbReq->wb_index = HGFS_PAGE_FILE_INDEX(page); - page_cache_get(page); - kref_init(&wbReq->wb_kref); - -exit: - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %p)\n", - __func__, wbReq, page)); - return wbReq; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsWbRequestDestroy -- - * - * Destroys by freeing up all resources allocated to the request. - * Release page associated with a write-back request after it has completed. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsWbRequestDestroy(HgfsWbPage *req) // IN: write page request -{ - struct page *page = req->wb_page; - - LOG(6, (KERN_WARNING"VMware hgfs: %s: (%p, %p)\n", - __func__, req, req->wb_page)); - - if (page != NULL) { - page_cache_release(page); - req->wb_page = NULL; - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodeFindWbRequest -- - * - * Finds if there is a write-back page request on this inode and returns it. - * - * Results: - * NULL or the write-back request for the page. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static HgfsWbPage * -HgfsInodeFindWbRequest(struct inode *inode, // IN: inode of file to write to - struct page *page) // IN: page of data to write -{ - HgfsInodeInfo *iinfo; - HgfsWbPage *req = NULL; - HgfsWbPage *cur; - - iinfo = INODE_GET_II_P(inode); - - /* Linearly search the write back list for the correct req */ - list_for_each_entry(cur, &iinfo->listWbPages, wb_list) { - if (cur->wb_page == page) { - req = cur; - break; - } - } - - if (req != NULL) { - HgfsWbRequestGet(req); - } - - return req; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodeFindExistingWbRequest -- - * - * Finds if there is a write-back page request on this inode and returns - * locked. - * If the request is busy (locked) then it drops the lock and waits for it - * be not locked and searches the list again. - * - * Results: - * NULL or the write-back request for the page. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static HgfsWbPage * -HgfsInodeFindExistingWbRequest(struct inode *inode, // IN: inode of file to write to - struct page *page) // IN: page of data to write -{ - HgfsWbPage *req; - int error; - - spin_lock(&inode->i_lock); - - for (;;) { - req = HgfsInodeFindWbRequest(inode, page); - if (req == NULL) { - goto out_exit; - } - - /* - * Try and lock the request if not already locked. - * If we find it is already locked, busy, then we drop - * the reference and wait to try again. Otherwise, - * once newly locked we break out and return to the caller. - */ - if (HgfsWbRequestLock(req)) { - break; - } - - /* The request was in use, so wait and then retry */ - spin_unlock(&inode->i_lock); - error = HgfsWbRequestWait(req); - HgfsWbRequestPut(req); - if (error != 0) { - goto out_nolock; - } - - spin_lock(&inode->i_lock); - } - -out_exit: - spin_unlock(&inode->i_lock); - return req; - -out_nolock: - return ERR_PTR(error); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodeAddWbRequest -- - * - * Add a write-back page request to an inode. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsInodeAddWbRequest(struct inode *inode, // IN: inode of file to write to - HgfsWbPage *req) // IN: page write request -{ - HgfsInodeInfo *iinfo = INODE_GET_II_P(inode); - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %p, %lu)\n", - __func__, inode, req->wb_page, iinfo->numWbPages)); - - /* Lock the request! */ - HgfsWbRequestLock(req); - - HgfsWbRequestListAdd(req, &iinfo->listWbPages); - iinfo->numWbPages++; - HgfsWbRequestGet(req); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodeRemoveWbRequest -- - * - * Remove a write-back page request from an inode. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsInodeRemoveWbRequest(struct inode *inode, // IN: inode of file written to - HgfsWbPage *req) // IN: page write request -{ - HgfsInodeInfo *iinfo = INODE_GET_II_P(inode); - - LOG(6, (KERN_CRIT "VMware hgfs: %s: (%p, %p, %lu)\n", - __func__, inode, req->wb_page, iinfo->numWbPages)); - - iinfo->numWbPages--; - HgfsWbRequestListRemove(req); - HgfsWbRequestPut(req); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodePageWbAdd -- - * - * Add a write-back page request to an inode. - * If the page is already exists in the list for this inode nothing is - * done, otherwise a new object is created for the page and added to the - * inode list. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsInodePageWbAdd(struct inode *inode, // IN: inode of file to write to - struct page *page) // IN: page of data to write -{ - HgfsWbPage *req; - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %p)\n", - __func__, inode, page)); - - req = HgfsInodeFindExistingWbRequest(inode, page); - if (req != NULL) { - goto exit; - } - - /* - * We didn't find an existing write back request for that page so - * we create one. - */ - req = HgfsWbRequestCreate(page); - if (IS_ERR(req)) { - goto exit; - } - - spin_lock(&inode->i_lock); - /* - * Add the new write request for the page into our inode list to track. - */ - HgfsInodeAddWbRequest(inode, req); - spin_unlock(&inode->i_lock); - -exit: - if (!IS_ERR(req)) { - HgfsWbRequestUnlockAndPut(req); - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodePageWbRemove -- - * - * Remove a write-back page request from an inode. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsInodePageWbRemove(struct inode *inode, // IN: inode of file written to - struct page *page) // IN: page of data written -{ - HgfsWbPage *req; - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %p)\n", - __func__, inode, page)); - - req = HgfsInodeFindExistingWbRequest(inode, page); - if (req == NULL) { - goto exit; - } - spin_lock(&inode->i_lock); - /* - * Add the new write request for the page into our inode list to track. - */ - HgfsInodeRemoveWbRequest(inode, req); - HgfsWbRequestUnlockAndPut(req); - spin_unlock(&inode->i_lock); - -exit: - return; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsInodePageWbFind -- - * - * Find a write-back page request from an inode. - * - * Results: - * TRUE if found an existing write for the page, FALSE otherwise. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsInodePageWbFind(struct inode *inode, // IN: inode of file written to - struct page *page) // IN: page of data written -{ - HgfsWbPage *req; - Bool found = TRUE; - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %p)\n", - __func__, inode, page)); - - req = HgfsInodeFindExistingWbRequest(inode, page); - if (req == NULL) { - found = FALSE; - goto exit; - } - spin_lock(&inode->i_lock); - /* - * Remove the write request lock and reference we just grabbed. - */ - HgfsWbRequestUnlockAndPut(req); - spin_unlock(&inode->i_lock); - -exit: - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %p) return %d\n", - __func__, inode, page, found)); - return found; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsCheckReadModifyWrite -- - * - * Check if we can read the page from the server to get the valid data - * for a page that we are in process of partially modifying and then - * writing. - * - * We maybe required to read the page first if the file is open for - * reading in addition to writing, the page is not marked as uptodate, - * it is not dirty or waiting to be committed, indicating that it was - * previously allocated and then modified, that there were valid bytes - * of data in that range of the file, and that the new data won't completely - * replace the old data in that range of the file. - * - * Results: - * TRUE if we need to read valid data and can do so for the page, - * FALSE otherwise. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsCheckReadModifyWrite(struct file *file, // IN: File to be written - struct page *page, // IN: page of data written - unsigned int pageFrom, // IN: position - unsigned int pageTo) // IN: len -{ - unsigned int pageLength = HgfsGetPageLength(page); - struct inode *inode = page->mapping->host; - Bool readPage = FALSE; - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %u, %u)\n", - __func__, page, pageFrom, pageTo)); - - if ((file->f_mode & FMODE_READ) && // opened for read? - !HgfsInodePageWbFind(inode, page) && // I/O request already ? - !PageUptodate(page) && // Up to date? - pageLength > 0 && // valid bytes of file? - (pageTo < pageLength || pageFrom != 0)) { // replace all valid bytes? - readPage = TRUE; - } - - LOG(6, (KERN_WARNING "VMware hgfs: %s: (%p, %u, %u) return %d\n", - __func__, page, pageFrom, pageTo, readPage)); - return readPage; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/request.c b/open-vm-tools/modules/linux/vmhgfs/request.c deleted file mode 100644 index 0667cb8c8..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/request.c +++ /dev/null @@ -1,350 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * request.c -- - * - * Functions dealing with the creation, deletion, and sending of HGFS - * requests are defined here. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include -#include "compat_kernel.h" -#include "compat_sched.h" -#include "compat_semaphore.h" -#include "compat_slab.h" -#include "compat_spinlock.h" - -#include "module.h" -#include "request.h" -#include "transport.h" -#include "fsutil.h" -#include "vm_assert.h" - -/* - *---------------------------------------------------------------------- - * - * HgfsRequestInit -- - * - * Initializes new request structure. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsRequestInit(HgfsReq *req, // IN: request to initialize - int requestId) // IN: ID assigned to the request -{ - ASSERT(req); - - kref_init(&req->kref); - INIT_LIST_HEAD(&req->list); - init_waitqueue_head(&req->queue); - req->id = requestId; - req->payloadSize = 0; - req->state = HGFS_REQ_STATE_ALLOCATED; - req->numEntries = 0; -} - -/* - *---------------------------------------------------------------------- - * - * HgfsGetNewRequest -- - * - * Allocates and initializes new request structure. - * - * Results: - * On success the new struct is returned with all fields - * initialized. Returns NULL on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsReq * -HgfsGetNewRequest(void) -{ - static atomic_t hgfsIdCounter = ATOMIC_INIT(0); - HgfsReq *req; - - req = HgfsTransportAllocateRequest(HGFS_PACKET_MAX); - if (req == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: can't allocate memory\n", __func__)); - return NULL; - } - - HgfsRequestInit(req, atomic_inc_return(&hgfsIdCounter) - 1); - - return req; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsCopyRequest -- - * - * Allocates and initializes new request structure and copies - * existing request into it. - * - * Results: - * On success the new struct is returned with all fields - * initialized. Returns NULL on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsReq * -HgfsCopyRequest(HgfsReq *req) // IN: request to be copied -{ - HgfsReq *newReq; - - ASSERT(req); - - newReq = HgfsTransportAllocateRequest(req->bufferSize); - if (newReq == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: %s: can't allocate memory\n", __func__)); - return NULL; - } - - HgfsRequestInit(newReq, req->id); - - memcpy(newReq->dataPacket, req->dataPacket, - req->numEntries * sizeof (req->dataPacket[0])); - - newReq->numEntries = req->numEntries; - newReq->payloadSize = req->payloadSize; - memcpy(newReq->payload, req->payload, req->payloadSize); - - return newReq; -} - -/* - *---------------------------------------------------------------------- - * - * HgfsSendRequest -- - * - * Send out an HGFS request via transport layer, and wait for the reply. - * - * Results: - * Returns zero on success, negative number on error. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsSendRequest(HgfsReq *req) // IN/OUT: Outgoing request -{ - int ret; - - ASSERT(req); - ASSERT(req->payloadSize <= req->bufferSize); - req->state = HGFS_REQ_STATE_UNSENT; - - LOG(10, (KERN_DEBUG "VMware hgfs: HgfsSendRequest: Sending request id %d\n", - req->id)); - ret = HgfsTransportSendRequest(req); - LOG(10, (KERN_DEBUG "VMware hgfs: HgfsSendRequest: request finished, " - "return %d\n", ret)); - - return ret; -} - -/* - *---------------------------------------------------------------------- - * - * HgfsRequestFreeMemory -- - * - * Frees memory allocated for a request. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void HgfsRequestFreeMemory(struct kref *kref) -{ - HgfsReq *req = container_of(kref, HgfsReq, kref); - - LOG(10, (KERN_DEBUG "VMware hgfs: %s: freeing request %d\n", - __func__, req->id)); - HgfsTransportFreeRequest(req); -} - -/* - *---------------------------------------------------------------------- - * - * HgfsRequestPutRef -- - * - * Decrease reference count of HGFS request. - * - * Results: - * None - * - * Side effects: - * May cause request to be destroyed. - * - *---------------------------------------------------------------------- - */ - -void -HgfsRequestPutRef(HgfsReq *req) // IN: Request -{ - if (req) { - LOG(10, (KERN_DEBUG "VMware hgfs: %s: request %d\n", - __func__, req->id)); - kref_put(&req->kref, HgfsRequestFreeMemory); - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsRequestGetRef -- - * - * Increment reference count of HGFS request. - * - * Results: - * Pointer to the same HGFS request. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsReq * -HgfsRequestGetRef(HgfsReq *req) // IN: Request -{ - if (req) { - LOG(10, (KERN_DEBUG "VMware hgfs: %s: request %d\n", - __func__, req->id)); - kref_get(&req->kref); - } - - return req; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsReplyStatus -- - * - * Return reply status. - * - * Results: - * Returns reply status as per the protocol. - * XXX: Needs changes when vmci headers are added. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsStatus -HgfsReplyStatus(HgfsReq *req) // IN -{ - HgfsReply *rep; - - rep = (HgfsReply *)(HGFS_REQ_PAYLOAD(req)); - - return rep->status; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsCompleteReq -- - * - * Marks request as completed and wakes up sender. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsCompleteReq(HgfsReq *req) // IN: Request -{ - ASSERT(req); - - req->state = HGFS_REQ_STATE_COMPLETED; - /* Wake up the client process waiting for the reply to this request. */ - wake_up(&req->queue); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsFailReq -- - * - * Marks request as failed and calls HgfsCompleteReq to wake up - * sender. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void HgfsFailReq(HgfsReq *req, // IN: erequest to be marked failed - int error) // IN: error code -{ - HgfsReply *reply = req->payload; - - reply->id = req->id; - reply->status = error; - - req->payloadSize = sizeof *reply; - HgfsCompleteReq(req); -} diff --git a/open-vm-tools/modules/linux/vmhgfs/request.h b/open-vm-tools/modules/linux/vmhgfs/request.h deleted file mode 100644 index 6559265b3..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/request.h +++ /dev/null @@ -1,158 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * request.h -- - * - * Functions dealing with the creation, deletion, and sending of HGFS - * requests are defined here. - */ - -#ifndef _HGFS_DRIVER_REQUEST_H_ -#define _HGFS_DRIVER_REQUEST_H_ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include -#include "compat_sched.h" -#include "compat_spinlock.h" - -#include "hgfs.h" /* For common HGFS definitions. */ -#include "vm_basic_types.h" -#include "vm_basic_defs.h" - -/* Macros for accessing the payload portion of the HGFS request packet. */ -#define HGFS_REQ_PAYLOAD(hgfsReq) ((hgfsReq)->payload) - -/* XXX: Needs change when VMCI is supported. */ -#define HGFS_REQ_PAYLOAD_V3(hgfsReq) (HGFS_REQ_PAYLOAD(hgfsReq) + sizeof(HgfsRequest)) -#define HGFS_REP_PAYLOAD_V3(hgfsRep) (HGFS_REQ_PAYLOAD(hgfsRep) + sizeof(HgfsReply)) - -/* - * HGFS_REQ_STATE_ALLOCATED: - * The filesystem half has allocated the request from the slab - * allocator. The request is not on any list. - * - * HGFS_REQ_STATE_UNSENT: - * The filesystem half of the driver has filled in the request fields - * and placed the request in the global unsent list. It is now the - * request handler's responsibility to submit this request to - * the channel. Requests in this state are on the global unsent list. - * - * HGFS_REQ_STATE_SUBMITTED: - * The packet has been sent, but the reply will arrive asynchronously. - * The request will be on the hgfsRepPending list, and whenever - * the reply arrives, the reply handler will remove the request from - * the hgfsRepPending list and stuff the reply into the request's - * packet buffer. - * - * This is only for asynchronous channel communication. - * - * HGFS_REQ_STATE_COMPLETED: - * The request handler sent the request and received a reply. The reply - * is stuffed in the request's packet buffer. Requests in this state - * are not on any list. - */ -typedef enum { - HGFS_REQ_STATE_ALLOCATED, - HGFS_REQ_STATE_UNSENT, - HGFS_REQ_STATE_SUBMITTED, - HGFS_REQ_STATE_COMPLETED, /* Both header and payload were received. */ -} HgfsState; - -/* - * Each page that is sent from guest to host is described in the following - * format. - */ -typedef struct HgfsDataPacket { - struct page *page; - uint32 offset; - uint32 len; -} HgfsDataPacket; - -/* - * A request to be sent to the user process. - */ -typedef struct HgfsReq { - - /* Reference count */ - struct kref kref; - - /* Links to place the object on various lists. */ - struct list_head list; - - /* ID of the transport (its address) */ - void *transportId; - - /* - * When clients wait for the reply to a request, they'll wait on this - * wait queue. - */ - wait_queue_head_t queue; - - /* Current state of the request. */ - HgfsState state; - - /* ID of this request */ - uint32 id; - - /* Pointer to payload in the buffer */ - void *payload; - - /* Total size of the payload.*/ - size_t payloadSize; - - /* - * Size of the data buffer (below), not including size of chunk - * used by transport. Must be enough to hold both request and - * reply (but not at the same time). Initialized in channels. - */ - size_t bufferSize; - - /* - * Used by read and write calls. Hgfs client passes in - * pages to the vmci channel using datapackets and vmci channel - * uses it to pass PA's to the host. - */ - HgfsDataPacket *dataPacket; - - /* Number of entries in data packet */ - uint32 numEntries; - - /* - * Packet of data, for both incoming and outgoing messages. - * Include room for the command. - */ - unsigned char buffer[]; -} HgfsReq; - -/* Public functions (with respect to the entire module). */ -HgfsReq *HgfsGetNewRequest(void); -HgfsReq *HgfsCopyRequest(HgfsReq *req); -int HgfsSendRequest(HgfsReq *req); -HgfsReq *HgfsRequestGetRef(HgfsReq *req); -void HgfsRequestPutRef(HgfsReq *req); -#define HgfsFreeRequest(req) HgfsRequestPutRef(req) -HgfsStatus HgfsReplyStatus(HgfsReq *req); -void HgfsCompleteReq(HgfsReq *req); -void HgfsFailReq(HgfsReq *req, int error); - -#endif // _HGFS_DRIVER_REQUEST_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/stubs.c b/open-vm-tools/modules/linux/vmhgfs/stubs.c deleted file mode 100644 index 36d5e16bd..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/stubs.c +++ /dev/null @@ -1,85 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * stubs.c - * - * Contains stubs and helper functions. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include "kernelStubs.h" -#include "module.h" -#include "vm_assert.h" - -/* - *---------------------------------------------------------------------- - * - * Debug -- - * - * If debugging is enabled, output debug information. - * - * Result - * None - * - * Side-effects - * None - * - *---------------------------------------------------------------------- - */ - -void -Debug(char const *fmt, // IN: Format string - ...) // IN: Arguments -{ - va_list args; - int numBytes; - static char out[128]; - - va_start(args, fmt); - numBytes = Str_Vsnprintf(out, sizeof out, fmt, args); - va_end(args); - - if (numBytes > 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s", out)); - } -} - - -/* - *---------------------------------------------------------------------- - * - * Log -- - * - * Needs to be defined. - * - * Result - * None - * - * Side-effects - * None - * - *---------------------------------------------------------------------- - */ -void -Log(const char *string, ...) -{ - // do nothing. -} diff --git a/open-vm-tools/modules/linux/vmhgfs/super.c b/open-vm-tools/modules/linux/vmhgfs/super.c deleted file mode 100644 index 78d205717..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/super.c +++ /dev/null @@ -1,387 +0,0 @@ -/********************************************************* - * Copyright (C) 2006-2016 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 - * - *********************************************************/ - -/* - * super.c -- - * - * Superblock operations for the filesystem portion of the vmhgfs driver. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include "compat_fs.h" -#include "compat_statfs.h" -#include "compat_kernel.h" -#include "compat_slab.h" -#include "compat_sched.h" -#include "compat_version.h" - -#include "hgfsProto.h" -#include "escBitvector.h" -#include "cpName.h" -#include "hgfsUtil.h" -#include "request.h" -#include "fsutil.h" -#include "hgfsDevLinux.h" -#include "module.h" -#include "vm_assert.h" - - -/* Hgfs filesystem superblock operations */ -static struct inode *HgfsAllocInode(struct super_block *sb); -static void HgfsDestroyInode(struct inode *inode); -static void HgfsPutSuper(struct super_block *sb); -#if defined VMW_STATFS_2618 -static int HgfsStatfs(struct dentry *dentry, - struct compat_kstatfs *stat); -#else -static int HgfsStatfs(struct super_block *sb, - struct compat_kstatfs *stat); -#endif - -struct super_operations HgfsSuperOperations = { - .alloc_inode = HgfsAllocInode, - .destroy_inode = HgfsDestroyInode, - .put_super = HgfsPutSuper, - .statfs = HgfsStatfs, -}; - - -/* - *----------------------------------------------------------------------------- - * - * HgfsAllocInode -- - * - * Hgfs superblock 'alloc_inode' method. Called by the kernel to allocate - * a new inode struct. We use this VFS method instead of read_inode because - * we want to control both how we allocate and how we fill in the inode. - * - * Results: - * Non-null: A valid inode. - * null: Error in inode allocation. - * - * Side effects: - * Allocates memory. - * - *----------------------------------------------------------------------------- - */ - -static struct inode * -HgfsAllocInode(struct super_block *sb) // IN: Superblock for the inode -{ - HgfsInodeInfo *iinfo; - - iinfo = kmem_cache_alloc(hgfsInodeCache, GFP_KERNEL); - if (!iinfo) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsAllocInode: " - "can't allocate memory\n")); - return NULL; - } - - return &iinfo->inode; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsDestroyInode -- - * - * Hgfs superblock 'destroy_inode' method. Called by the kernel when it - * deallocates an inode. We use this method instead of clear_inode because - * we want to control both how we deallocate and how we clear the inode. - * - * Results: - * None - * - * Side effects: - * Frees memory associated with inode. - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsDestroyInode(struct inode *inode) // IN: The VFS inode -{ - kmem_cache_free(hgfsInodeCache, INODE_GET_II_P(inode)); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsPutSuper -- - * - * Hgfs superblock 'put_super' method. Called after a umount(2) of the - * filesystem succeeds. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsPutSuper(struct super_block *sb) // IN: The superblock -{ - HgfsSuperInfo *si; - - ASSERT(sb); - - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPutSuper: was called\n")); - - si = HGFS_SB_TO_COMMON(sb); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) - bdi_destroy(&si->bdi); -#endif - kfree(si->shareName); - kfree(si); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsPackQueryVolumeRequest -- - * - * Setup the query volume request, depending on the op version. - * - * Results: - * Returns zero on success, or negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsPackQueryVolumeRequest(struct dentry *dentry, // IN: File pointer for this open - HgfsOp opUsed, // IN: Op to be used. - HgfsReq *req) // IN/OUT: Packet to write into -{ - char *name; - uint32 *nameLength; - size_t requestSize; - int result; - - ASSERT(dentry); - ASSERT(req); - - switch (opUsed) { - case HGFS_OP_QUERY_VOLUME_INFO_V3: { - HgfsRequest *requestHeader; - HgfsRequestQueryVolumeV3 *requestV3; - - requestHeader = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req)); - requestHeader->op = opUsed; - requestHeader->id = req->id; - - requestV3 = (HgfsRequestQueryVolumeV3 *)HGFS_REQ_PAYLOAD_V3(req); - - /* We'll use these later. */ - name = requestV3->fileName.name; - nameLength = &requestV3->fileName.length; - requestV3->fileName.flags = 0; - requestV3->fileName.fid = HGFS_INVALID_HANDLE; - requestV3->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE; - requestV3->reserved = 0; - requestSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); - break; - } - case HGFS_OP_QUERY_VOLUME_INFO: { - HgfsRequestQueryVolume *request; - - request = (HgfsRequestQueryVolume *)(HGFS_REQ_PAYLOAD(req)); - request->header.op = opUsed; - request->header.id = req->id; - - /* We'll use these later. */ - name = request->fileName.name; - nameLength = &request->fileName.length; - requestSize = sizeof *request; - break; - } - default: - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: unexpected " - "OP type encountered\n")); - return -EPROTO; - } - - /* Build full name to send to server. */ - if (HgfsBuildPath(name, req->bufferSize - (requestSize - 1), - dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: build path failed\n")); - return -EINVAL; - } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: opening \"%s\"\n", - name)); - - /* Convert to CP name. */ - result = CPName_ConvertTo(name, - req->bufferSize - (requestSize - 1), - name); - if (result < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: CP conversion failed\n")); - return -EINVAL; - } - - *nameLength = (uint32) result; - req->payloadSize = requestSize + result; - - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsStatfs -- - * - * Hgfs superblock 'statfs' method. Called when statfs(2) is invoked on the - * filesystem. - * - * Results: - * 0 on success - * error < 0 on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -#if defined VMW_STATFS_2618 -static int -HgfsStatfs(struct dentry *dentry, // IN : The directory entry - struct compat_kstatfs *stat) // OUT: Stat to fill in -#else -static int -HgfsStatfs(struct super_block *sb, // IN : The superblock - struct compat_kstatfs *stat) // OUT: Stat to fill in -#endif -{ - HgfsReq *req; - int result = 0; - struct dentry *dentryToUse; - struct super_block *sbToUse; - HgfsOp opUsed; - HgfsStatus replyStatus; - uint64 freeBytes; - uint64 totalBytes; - - ASSERT(stat); -#if defined VMW_STATFS_2618 - ASSERT(dentry); - ASSERT(dentry->d_sb); - dentryToUse = dentry; - sbToUse = dentry->d_sb; -#else - ASSERT(sb); - ASSERT(sb->s_root); - dentryToUse = sb->s_root; - sbToUse = sb; -#endif - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsStatfs: was called\n")); - memset(stat, 0, sizeof *stat); - - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsStatfs: out of memory while " - "getting new request\n")); - result = -ENOMEM; - goto out; - } - - retry: - opUsed = hgfsVersionQueryVolumeInfo; - result = HgfsPackQueryVolumeRequest(dentryToUse, opUsed, req); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsStatfs: error packing request\n")); - goto out; - } - - result = HgfsSendRequest(req); - if (result == 0) { - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsStatfs: got reply\n")); - replyStatus = HgfsReplyStatus(req); - result = HgfsStatusConvertToLinux(replyStatus); - - /* - * If the statfs succeeded on the server, copy the stats - * into the kstatfs struct, otherwise return an error. - */ - switch (result) { - case 0: - stat->f_type = HGFS_SUPER_MAGIC; - stat->f_bsize = sbToUse->s_blocksize; - stat->f_namelen = PATH_MAX; - if (opUsed == HGFS_OP_QUERY_VOLUME_INFO_V3) { - totalBytes = ((HgfsReplyQueryVolumeV3 *)HGFS_REP_PAYLOAD_V3(req))->totalBytes; - freeBytes = ((HgfsReplyQueryVolumeV3 *)HGFS_REP_PAYLOAD_V3(req))->freeBytes; - } else { - totalBytes = ((HgfsReplyQueryVolume *)HGFS_REQ_PAYLOAD(req))->totalBytes; - freeBytes = ((HgfsReplyQueryVolume *)HGFS_REQ_PAYLOAD(req))->freeBytes; - } - stat->f_blocks = totalBytes >> sbToUse->s_blocksize_bits; - stat->f_bfree = freeBytes >> sbToUse->s_blocksize_bits; - stat->f_bavail = stat->f_bfree; - break; - - case -EPERM: - /* - * We're cheating! This will cause statfs will return success. - * We're doing this because an old server will complain when it gets - * a statfs on a per-share mount. Rather than have 'df' spit an - * error, let's just return all zeroes. - */ - result = 0; - break; - - case -EPROTO: - /* Retry with older version(s). Set globally. */ - if (opUsed == HGFS_OP_QUERY_VOLUME_INFO_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsStatfs: Version 3 not " - "supported. Falling back to version 1.\n")); - hgfsVersionQueryVolumeInfo = HGFS_OP_QUERY_VOLUME_INFO; - goto retry; - } - break; - - default: - break; - } - } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsStatfs: timed out\n")); - } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsStatfs: server returned error: " - "%d\n", result)); - } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsStatfs: unknown error: %d\n", - result)); - } - -out: - HgfsFreeRequest(req); - return result; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/transport.c b/open-vm-tools/modules/linux/vmhgfs/transport.c deleted file mode 100644 index 24446052a..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/transport.c +++ /dev/null @@ -1,574 +0,0 @@ -/********************************************************* - * Copyright (C) 2009-2016 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 - * - *********************************************************/ - -/* - * transport.c -- - * - * This file handles the transport mechanisms available for HGFS. - * This acts as a glue between the HGFS filesystem driver and the - * actual transport channels (backdoor, tcp, vsock, ...). - * - * The sends happen in the process context, where as a kernel thread - * handles the asynchronous replies. A queue of pending replies is - * maintained and is protected by a spinlock. The channel opens and close - * is protected by a mutex. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include "compat_mutex.h" -#include "compat_sched.h" -#include "compat_spinlock.h" -#include "compat_version.h" - -/* Must be included after semaphore.h. */ -#include -/* Must be included after sched.h. */ -#include /* for spin_lock_bh */ - - -#include "hgfsDevLinux.h" -#include "hgfsProto.h" -#include "module.h" -#include "request.h" -#include "transport.h" -#include "vm_assert.h" - -static HgfsTransportChannel *hgfsChannel; /* Current active channel. */ -static compat_mutex_t hgfsChannelLock; /* Lock to protect hgfsChannel. */ -static struct list_head hgfsRepPending; /* Reply pending queue. */ -static spinlock_t hgfsRepQueueLock; /* Reply pending queue lock. */ - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportOpenChannel -- - * - * Opens given communication channel with HGFS server. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsTransportOpenChannel(HgfsTransportChannel *channel) -{ - Bool ret; - - switch (channel->status) { - case HGFS_CHANNEL_UNINITIALIZED: - case HGFS_CHANNEL_DEAD: - ret = FALSE; - break; - - case HGFS_CHANNEL_CONNECTED: - ret = TRUE; - break; - - case HGFS_CHANNEL_NOTCONNECTED: - ret = channel->ops.open(channel); - if (ret) { - channel->status = HGFS_CHANNEL_CONNECTED; - } - break; - - default: - ret = FALSE; - ASSERT(0); /* Not reached. */ - } - - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportCloseChannel -- - * - * Closes currently open communication channel. Has to be called - * while holdingChannelLock. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsTransportCloseChannel(HgfsTransportChannel *channel) -{ - if (channel->status == HGFS_CHANNEL_CONNECTED || - channel->status == HGFS_CHANNEL_DEAD) { - - channel->ops.close(channel); - channel->status = HGFS_CHANNEL_NOTCONNECTED; - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportSetupNewChannel -- - * - * Find a new workable channel. - * - * Results: - * TRUE on success, otherwise FALSE. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static Bool -HgfsTransportSetupNewChannel(void) -{ - HgfsTransportChannel *newChannel; - - newChannel = HgfsGetBdChannel(); - LOG(10, (KERN_DEBUG LGPFX "%s CHANNEL: Bd channel\n", __func__)); - ASSERT(newChannel); - hgfsChannel = newChannel; - return HgfsTransportOpenChannel(newChannel); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransporAddPendingRequest -- - * - * Adds a request to the hgfsRepPending queue. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsTransportAddPendingRequest(HgfsReq *req) // IN: Request to add -{ - ASSERT(req); - - spin_lock_bh(&hgfsRepQueueLock); - list_add_tail(&req->list, &hgfsRepPending); - spin_unlock_bh(&hgfsRepQueueLock); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportRemovePendingRequest -- - * - * Dequeues the request from the hgfsRepPending queue. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsTransportRemovePendingRequest(HgfsReq *req) // IN: Request to dequeue -{ - ASSERT(req); - - spin_lock_bh(&hgfsRepQueueLock); - list_del_init(&req->list); - spin_unlock_bh(&hgfsRepQueueLock); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportFlushPendingRequests -- - * - * Complete all submitted requests with an error, called when - * we are about to tear down communication channel. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsTransportFlushPendingRequests(void) -{ - struct HgfsReq *req; - - spin_lock_bh(&hgfsRepQueueLock); - - list_for_each_entry(req, &hgfsRepPending, list) { - if (req->state == HGFS_REQ_STATE_SUBMITTED) { - LOG(6, (KERN_DEBUG LGPFX "%s: injecting error reply to req id: %d\n", - __func__, req->id)); - HgfsFailReq(req, -EIO); - } - } - - spin_unlock_bh(&hgfsRepQueueLock); -} - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportGetPendingRequest -- - * - * Attempts to locate request with specified ID in the queue of - * pending (waiting for server's reply) requests. - * - * Results: - * NULL if request not found; otherwise address of the request - * structure. - * - * Side effects: - * Increments reference count of the request. - * - *---------------------------------------------------------------------- - */ - -HgfsReq * -HgfsTransportGetPendingRequest(HgfsHandle id) // IN: id of the request -{ - HgfsReq *cur, *req = NULL; - - spin_lock_bh(&hgfsRepQueueLock); - - list_for_each_entry(cur, &hgfsRepPending, list) { - if (cur->id == id) { - ASSERT(cur->state == HGFS_REQ_STATE_SUBMITTED); - req = HgfsRequestGetRef(cur); - break; - } - } - - spin_unlock_bh(&hgfsRepQueueLock); - - return req; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportAllocateRequest -- - * - * Allocates HGFS request structre using channel-specific allocator. - * - * Results: - * NULL on failure; otherwisepointer to newly allocated request. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsReq * -HgfsTransportAllocateRequest(size_t bufferSize) // IN: size of the buffer -{ - HgfsReq *req = NULL; - /* - * We use a temporary variable to make sure we stamp the request with - * same channel as we used to make allocation since hgfsChannel can - * be changed while we do allocation. - */ - HgfsTransportChannel *currentChannel = hgfsChannel; - - ASSERT(currentChannel); - - req = currentChannel->ops.allocate(bufferSize); - if (req) { - req->transportId = currentChannel; - } - - return req; -} - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportFreeRequest -- - * - * Free HGFS request structre using channel-specific free function. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -HgfsTransportFreeRequest(HgfsReq *req) // IN: size of the buffer -{ - /* - * We cannot use hgfsChannel structre because global channel could - * changes in the meantime. We remember the channel when we do - * allocation and call the same channel for de-allocation. Smart. - */ - - HgfsTransportChannel *channel = (HgfsTransportChannel *)req->transportId; - channel->ops.free(req); - return; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportSendRequest -- - * - * Sends the request via channel communication. - * - * Results: - * Zero on success, non-zero error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -int -HgfsTransportSendRequest(HgfsReq *req) // IN: Request to send -{ - HgfsReq *origReq = req; - int ret = -EIO; - - ASSERT(req); - ASSERT(req->state == HGFS_REQ_STATE_UNSENT); - ASSERT(req->payloadSize <= req->bufferSize); - - compat_mutex_lock(&hgfsChannelLock); - - HgfsTransportAddPendingRequest(req); - - do { - - if (unlikely(hgfsChannel->status != HGFS_CHANNEL_CONNECTED)) { - if (hgfsChannel->status == HGFS_CHANNEL_DEAD) { - HgfsTransportCloseChannel(hgfsChannel); - HgfsTransportFlushPendingRequests(); - } - - if (!HgfsTransportSetupNewChannel()) { - ret = -EIO; - goto out; - } - } - - ASSERT(hgfsChannel->ops.send); - - /* If channel changed since we created request we need to adjust */ - if (req->transportId != hgfsChannel) { - - HgfsTransportRemovePendingRequest(req); - - if (req != origReq) { - HgfsRequestPutRef(req); - } - - req = HgfsCopyRequest(origReq); - if (req == NULL) { - req = origReq; - ret = -ENOMEM; - goto out; - } - - HgfsTransportAddPendingRequest(req); - } - - ret = hgfsChannel->ops.send(hgfsChannel, req); - if (likely(ret == 0)) - break; - - LOG(4, (KERN_DEBUG LGPFX "%s: send failed with error %d\n", - __func__, ret)); - - if (ret == -EINTR) { - /* Don't retry when we are interrupted by some signal. */ - goto out; - } - - hgfsChannel->status = HGFS_CHANNEL_DEAD; - - } while (1); - - ASSERT(req->state == HGFS_REQ_STATE_COMPLETED || - req->state == HGFS_REQ_STATE_SUBMITTED); - -out: - compat_mutex_unlock(&hgfsChannelLock); - - if (likely(ret == 0)) { - /* - * Send succeeded, wait for the reply. - * Right now, we cannot cancel request once they - * are dispatched to the host. - */ - wait_event(req->queue, - req->state == HGFS_REQ_STATE_COMPLETED); - } - - HgfsTransportRemovePendingRequest(req); - - /* - * If we used a copy of request because we changed transport we - * need to copy payload back into original request. - */ - if (req != origReq) { - ASSERT(req->payloadSize <= origReq->bufferSize); - origReq->payloadSize = req->payloadSize; - memcpy(origReq->payload, req->payload, req->payloadSize); - HgfsRequestPutRef(req); - } - - return ret; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportInit -- - * - * Initialize the transport. - * - * Starts the reply thread, for handling incoming packets on the - * connected socket. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsTransportInit(void) -{ - INIT_LIST_HEAD(&hgfsRepPending); - spin_lock_init(&hgfsRepQueueLock); - compat_mutex_init(&hgfsChannelLock); - - compat_mutex_lock(&hgfsChannelLock); - - hgfsChannel = HgfsGetBdChannel(); - ASSERT(hgfsChannel); - - compat_mutex_unlock(&hgfsChannelLock); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportMarkDead -- - * - * Marks current channel as dead so it can be cleaned up and - * fails all submitted requests. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -HgfsTransportMarkDead(void) -{ - LOG(8, (KERN_DEBUG LGPFX "%s entered.\n", __func__)); - - compat_mutex_lock(&hgfsChannelLock); - - if (hgfsChannel) { - hgfsChannel->status = HGFS_CHANNEL_DEAD; - } - HgfsTransportFlushPendingRequests(); - - compat_mutex_unlock(&hgfsChannelLock); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsTransportExit -- - * - * Teardown the transport. - * - * Results: - * None - * - * Side effects: - * Cleans up everything, frees queues, closes channel. - * - *---------------------------------------------------------------------- - */ - -void -HgfsTransportExit(void) -{ - LOG(8, (KERN_DEBUG LGPFX "%s entered.\n", __func__)); - - compat_mutex_lock(&hgfsChannelLock); - ASSERT(hgfsChannel); - HgfsTransportCloseChannel(hgfsChannel); - hgfsChannel = NULL; - compat_mutex_unlock(&hgfsChannelLock); - - ASSERT(list_empty(&hgfsRepPending)); - LOG(8, (KERN_DEBUG LGPFX "%s exited.\n", __func__)); -} - - diff --git a/open-vm-tools/modules/linux/vmhgfs/transport.h b/open-vm-tools/modules/linux/vmhgfs/transport.h deleted file mode 100644 index 571c4ab2c..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/transport.h +++ /dev/null @@ -1,71 +0,0 @@ -/********************************************************* - * Copyright (C) 2009-2016 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 - * - *********************************************************/ - -/* - * transport.h -- - */ - -#ifndef _HGFS_DRIVER_TRANSPORT_H_ -#define _HGFS_DRIVER_TRANSPORT_H_ - -#include "request.h" -#include "compat_mutex.h" -#include "hgfsProto.h" - -/* - * There are the operations a channel should implement. - */ -struct HgfsTransportChannel; -typedef struct HgfsTransportChannelOps { - Bool (*open)(struct HgfsTransportChannel *); - void (*close)(struct HgfsTransportChannel *); - HgfsReq* (*allocate)(size_t payloadSize); - int (*send)(struct HgfsTransportChannel *, HgfsReq *); - void (*free)(HgfsReq *); -} HgfsTransportChannelOps; - -typedef enum { - HGFS_CHANNEL_UNINITIALIZED, - HGFS_CHANNEL_NOTCONNECTED, - HGFS_CHANNEL_CONNECTED, - HGFS_CHANNEL_DEAD, /* Error has been detected, need to shut it down. */ -} HgfsChannelStatus; - -typedef struct HgfsTransportChannel { - const char *name; /* Channel name. */ - HgfsTransportChannelOps ops; /* Channel ops. */ - HgfsChannelStatus status; /* Connection status. */ - void *priv; /* Channel private data. */ - compat_mutex_t connLock; /* Protect _this_ struct. */ -} HgfsTransportChannel; - -/* Public functions (with respect to the entire module). */ -void HgfsTransportInit(void); -void HgfsTransportExit(void); -HgfsReq *HgfsTransportAllocateRequest(size_t payloadSize); -void HgfsTransportFreeRequest(HgfsReq *req); -int HgfsTransportSendRequest(HgfsReq *req); -HgfsReq *HgfsTransportGetPendingRequest(HgfsHandle id); -void HgfsTransportRemovePendingRequest(HgfsReq *req); -void HgfsTransportFinishRequest(HgfsReq *req, Bool success, Bool do_put); -void HgfsTransportFlushRequests(void); -void HgfsTransportMarkDead(void); - -HgfsTransportChannel *HgfsGetBdChannel(void); - -#endif // _HGFS_DRIVER_TRANSPORT_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h b/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h deleted file mode 100644 index 8b614a900..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2016 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 - * - *********************************************************/ - -/* - * vmhgfs_version.h -- - * - * Version definitions for the Linux vmhgfs driver. - */ - -#ifndef _VMHGFS_VERSION_H_ -#define _VMHGFS_VERSION_H_ - -#define VMHGFS_DRIVER_VERSION 2.0.21.0 -#define VMHGFS_DRIVER_VERSION_COMMAS 2,0,21,0 -#define VMHGFS_DRIVER_VERSION_STRING "2.0.21.0" - -#endif /* _VMHGFS_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vmsync/COPYING b/open-vm-tools/modules/linux/vmsync/COPYING deleted file mode 100644 index d511905c1..000000000 --- a/open-vm-tools/modules/linux/vmsync/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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; either version 2 of the License, or - (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/open-vm-tools/modules/linux/vmsync/Makefile b/open-vm-tools/modules/linux/vmsync/Makefile deleted file mode 100644 index 7078c2fdc..000000000 --- a/open-vm-tools/modules/linux/vmsync/Makefile +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware kernel module Makefile to be distributed externally -#### - -#### -#### SRCROOT _must_ be a relative path. -#### -SRCROOT = . - -# -# open-vm-tools doesn't replicate shared source files for different modules; -# instead, files are kept in shared locations. So define a few useful macros -# to be able to handle both cases cleanly. -# -INCLUDE := -ifdef OVT_SOURCE_DIR -AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf -VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1) -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared -INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include -else -AUTOCONF_DIR := $(SRCROOT)/shared/autoconf -INCLUDE += -I$(SRCROOT)/shared -endif - - -VM_UNAME = $(shell uname -r) - -# Header directory for the running kernel -ifdef LINUXINCLUDE -HEADER_DIR = $(LINUXINCLUDE) -else -HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include -endif - -BUILD_DIR = $(HEADER_DIR)/.. - -DRIVER := vmsync -PRODUCT := tools - -# Grep program -GREP = /bin/grep - -vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) -vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi) - -ifndef VM_KBUILD -VM_KBUILD := no -ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes) -VM_KBUILD := yes -endif -export VM_KBUILD -endif - -ifndef VM_KBUILD_SHOWN -ifeq ($(VM_KBUILD), no) -VM_DUMMY := $(shell echo >&2 "Using standalone build system.") -else -VM_DUMMY := $(shell echo >&2 "Using kernel build system.") -endif -VM_KBUILD_SHOWN := yes -export VM_KBUILD_SHOWN -endif - -ifneq ($(VM_KBUILD), no) - -VMCCVER := $(shell $(CC) -dumpversion) - -# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles... -ifeq ($(VERSION),) - -DRIVER_KO := $(DRIVER).ko - -.PHONY: $(DRIVER_KO) - -auto-build: $(DRIVER_KO) - cp -f $< $(SRCROOT)/../$(DRIVER).o - -# $(DRIVER_KO) is a phony target, so compare file times explicitly -$(DRIVER): $(DRIVER_KO) - if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi - -# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler -VM_CCVER := $(VMCCVER) -export VM_CCVER -VM_CC := $(CC) -export VM_CC - -MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES)) - -# -# Define a setup target that gets built before the actual driver. -# This target may not be used at all, but if it is then it will be defined -# in Makefile.kernel -# -prebuild:: ; -postbuild:: ; - -$(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) modules - $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild -endif - -vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \ - $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \ - -DKBUILD_BASENAME=\"$(DRIVER)\" \ - -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -CC_WARNINGS := -Wall -Wstrict-prototypes -CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD -ifdef VMX86_DEVEL -CC_OPTS += -DVMX86_DEVEL -endif -ifdef VMX86_DEBUG -CC_OPTS += -DVMX86_DEBUG -endif - -include $(SRCROOT)/Makefile.kernel - -else - -include $(SRCROOT)/Makefile.normal - -endif - -#.SILENT: diff --git a/open-vm-tools/modules/linux/vmsync/Makefile.kernel b/open-vm-tools/modules/linux/vmsync/Makefile.kernel deleted file mode 100644 index 99d42e543..000000000 --- a/open-vm-tools/modules/linux/vmsync/Makefile.kernel +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998 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 -# -########################################################## - -#### -#### VMware vmsync Makefile to be distributed externally -#### - -INCLUDE += -I. - -EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/cachecreate.c, -DVMW_KMEMCR_HAS_DTOR, ) -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, ) - -obj-m += $(DRIVER).o - -$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, $(wildcard $(SRCROOT)/*.c))) - -clean: - rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ - Module.symvers Modules.symvers Module.markers modules.order \ - $(foreach dir,./,$(addprefix $(dir),.*.cmd .*.o.flags *.o))) diff --git a/open-vm-tools/modules/linux/vmsync/sync.c b/open-vm-tools/modules/linux/vmsync/sync.c deleted file mode 100644 index d05ccad5f..000000000 --- a/open-vm-tools/modules/linux/vmsync/sync.c +++ /dev/null @@ -1,711 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * sync.c -- - * - * Linux "sync driver" implementation. - * - * A typical user of vmsync will: - * - * - call ioctl() with the SYNC_IOC_FREEZE to freeze a list of paths. - * The list should be a colon-separated list of paths to be frozen. - * - call ioctl() with the SYNC_IOC_THAW command. - * - * The driver has an internal timer that is set up as soon as devices - * are frozen (i.e., after a successful SYNC_IOC_FREEZE). Subsequent calls - * to SYNC_IOC_FREEZE will not reset the timer. This timer is not designed - * as a way to protect the driver from being an avenue for a DoS attack - * (after all, if the user already has CAP_SYS_ADMIN privileges...), but - * as a way to protect itself from faulty user level apps during testing. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include -#include -#include -#include -#include - -#include "compat_fs.h" -#include "compat_module.h" -#include "compat_namei.h" -#include "compat_mutex.h" -#include "compat_slab.h" -#include "compat_workqueue.h" - -#include "syncDriverIoc.h" -#include "vmsync_version.h" - -/* - * After a successful SYNC_IOC_FREEZE ioctl, a timer will be enabled to thaw - * *all* frozen block devices after this delay. - */ -#define VMSYNC_THAW_TASK_DELAY (30 * HZ) - -/* Module information. */ -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Sync Driver"); -MODULE_VERSION(VMSYNC_DRIVER_VERSION_STRING); -MODULE_LICENSE("GPL v2"); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); - -static int VmSyncRelease(struct inode* inode, - struct file *file); - -static long VmSyncUnlockedIoctl(struct file *file, - unsigned cmd, - unsigned long arg); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) -static int VmSyncIoctl(struct inode *inode, - struct file *file, - unsigned cmd, - unsigned long arg); -#endif - -static int VmSyncOpen(struct inode *inode, - struct file *f); - -static struct file_operations VmSyncFileOps = { - .owner = THIS_MODULE, - .open = VmSyncOpen, - .release = VmSyncRelease, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) - .unlocked_ioctl = VmSyncUnlockedIoctl, -#else - .ioctl = VmSyncIoctl, -#endif -}; - - -typedef struct VmSyncBlockDevice { - struct list_head list; - struct block_device *bdev; - struct nameidata nd; - struct super_block *sb; -} VmSyncBlockDevice; - - -typedef struct VmSyncState { - struct list_head devices; - compat_mutex_t lock; - compat_delayed_work thawTask; -} VmSyncState; - - -/* - * Serializes freeze operations. Used to make sure that two different - * fds aren't allowed to freeze the same device. - */ -static compat_mutex_t gFreezeLock; - -/* A global count of how many devices are currently frozen by the driver. */ -static atomic_t gFreezeCount; - -static compat_kmem_cache *gSyncStateCache; -static compat_kmem_cache *gBlockDeviceCache; - -static compat_kmem_cache_ctor VmSyncBlockDeviceCtor; -static compat_kmem_cache_ctor VmSyncStateCtor; - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncThawDevices -- - * - * Thaws all currently frozen devices. - * - * Results: - * None. - * - * Side effects: - * Devices are thawed, thaw task is cancelled. - * - *----------------------------------------------------------------------------- - */ - -static void -VmSyncThawDevices(void *_state) // IN -{ - struct list_head *cur, *tmp; - VmSyncBlockDevice *dev; - VmSyncState *state; - - state = (VmSyncState *) _state; - - compat_mutex_lock(&state->lock); - cancel_delayed_work(&state->thawTask); - list_for_each_safe(cur, tmp, &state->devices) { - dev = list_entry(cur, VmSyncBlockDevice, list); - if (dev->sb != NULL && dev->sb->s_frozen != SB_UNFROZEN) { - thaw_bdev(dev->bdev, dev->sb); - atomic_dec(&gFreezeCount); - } - list_del_init(&dev->list); - kmem_cache_free(gBlockDeviceCache, dev); - } - compat_mutex_unlock(&state->lock); -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncThawDevicesCallback -- - * - * Wrapper around VmSyncThawDevices used by the work queue. - * - * Results: - * None. - * - * Side effects: - * See VmSyncThawDevices. - * - *----------------------------------------------------------------------------- - */ - -static void -VmSyncThawDevicesCallback(compat_delayed_work_arg data) // IN -{ - VmSyncState *state = COMPAT_DELAYED_WORK_GET_DATA(data, - VmSyncState, thawTask); - VmSyncThawDevices(state); -} - -/* - *----------------------------------------------------------------------------- - * - * VmSyncAddPath -- - * - * Adds the block device associated with the path to the internal list - * of devices to be frozen. - * - * Results: - * 0 on success. - * -EINVAL if path doesn't point to a freezable mount. - * -EALREADY if path is already frozen. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -VmSyncAddPath(const VmSyncState *state, // IN - const char *path, // IN - struct list_head *pathList) // IN -{ - int result; - struct list_head *cur, *tmp; - struct inode *inode; - struct nameidata nd; - VmSyncBlockDevice *dev; - - if ((result = compat_path_lookup(path, LOOKUP_FOLLOW, &nd)) != 0) { - goto exit; - } - inode = compat_vmw_nd_to_dentry(nd)->d_inode; - - /* - * Abort if the inode's superblock isn't backed by a block device, or if - * the superblock is already frozen. - */ - if (inode->i_sb->s_bdev == NULL || - inode->i_sb->s_frozen != SB_UNFROZEN) { - result = (inode->i_sb->s_bdev == NULL) ? -EINVAL : -EALREADY; - compat_path_release(&nd); - goto exit; - } - - /* - * Check if we've already added the block device to the list. - */ - list_for_each_safe(cur, tmp, &state->devices) { - dev = list_entry(cur, VmSyncBlockDevice, list); - if (dev->bdev == inode->i_sb->s_bdev) { - result = 0; - compat_path_release(&nd); - goto exit; - } - } - - /* - * Allocate a new entry and add it to the list. - */ - dev = kmem_cache_alloc(gBlockDeviceCache, GFP_KERNEL); - if (dev == NULL) { - result = -ENOMEM; - compat_path_release(&nd); - goto exit; - } - - /* - * Whenever we add a device to the "freeze list", the reference to - * the nameidata struct is retained until the device is actually - * frozen; this ensures the kernel knows the path is being used. - * Here we copy the nameidata struct so we can release our reference - * at that time. - */ - dev->bdev = inode->i_sb->s_bdev; - memcpy(&dev->nd, &nd, sizeof nd); - list_add_tail(&dev->list, pathList); - result = 0; - -exit: - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncFreezeDevices -- - * - * Tries to freeze all the devices provided by the user. - * - * Results: - * o on success, -errno on error. - * - * Side effects: - * A task is scheduled to automatically thaw devices after a timeout. - * - *----------------------------------------------------------------------------- - */ - -static int -VmSyncFreezeDevices(VmSyncState *state, // IN - const char __user *userPaths) // IN -{ - int result = 0; - char *paths; - char *currPath; - char *nextSep; - struct list_head *cur, *tmp; - struct list_head pathList; - VmSyncBlockDevice *dev; - - INIT_LIST_HEAD(&pathList); - - /* - * XXX: Using getname() will restrict the list of paths to PATH_MAX. - * Although this is not ideal, it shouldn't be a problem. We need an - * upper bound anyway. - */ - paths = getname(userPaths); - if (IS_ERR(paths)) { - return PTR_ERR(paths); - } - - compat_mutex_lock(&gFreezeLock); - compat_mutex_lock(&state->lock); - - /* - * First, try to add all paths to the list of paths to be frozen. - */ - currPath = paths; - do { - nextSep = strchr(currPath, ':'); - if (nextSep != NULL) { - *nextSep = '\0'; - } - result = VmSyncAddPath(state, currPath, &pathList); - /* - * Due to the way our user level app decides which paths to freeze - * now, we need to ignore EINVAL since there's no way to detect - * from user-land which paths are freezable or not. - */ - if (result != 0 && result != -EINVAL) { - break; - } else { - result = 0; - } - currPath = nextSep + 1; - } while (nextSep != NULL); - - /* - * If adding all the requested paths worked, then freeze them. - * Otherwise, clean the list. Make sure we only touch the devices - * added in the current call. - */ - list_for_each_safe(cur, tmp, &pathList) { - dev = list_entry(cur, VmSyncBlockDevice, list); - if (result == 0) { - dev->sb = freeze_bdev(dev->bdev); - compat_path_release(&dev->nd); - if (dev->sb != NULL) { - atomic_inc(&gFreezeCount); - } - list_move_tail(&dev->list, &state->devices); - } else { - list_del_init(&dev->list); - kmem_cache_free(gBlockDeviceCache, dev); - } - } - - compat_mutex_unlock(&state->lock); - compat_mutex_unlock(&gFreezeLock); - - if (result == 0) { - compat_schedule_delayed_work(&state->thawTask, VMSYNC_THAW_TASK_DELAY); - } - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncQuery -- - * - * Writes the number of devices currently frozen by the driver to the - * given address. The address should be in user space and be able to - * hold an int32_t. - * - * Results: - * 0 on success, -errno on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static inline int -VmSyncQuery(void __user *dst) // OUT -{ - int32_t active; - int result = 0; - - active = (int32_t) atomic_read(&gFreezeCount); - if (copy_to_user(dst, &active, sizeof active)) { - result = -EFAULT; - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncUnlockedIoctl -- - * - * Handles the IOCTLs recognized by the driver. - * - * - SYNC_IOC_FREEZE: freezes the block device associated with the - * path passed as a parameter. - * - * - SYNC_IOC_THAW: thaws all currently frozen block devices. - * - * - SYNC_IOC_QUERY: returns the number of block devices currently - * frozen by the driver. This is a global view of the driver state - * and doesn't reflect any fd-specific data. - * - * Results: - * 0 on success, -errno otherwise. - * - * Side effects: - * See ioctl descriptions above. - * - *----------------------------------------------------------------------------- - */ - -static long -VmSyncUnlockedIoctl(struct file *file, // IN - unsigned cmd, // IN - unsigned long arg) // IN/OUT -{ - int result = -ENOTTY; - VmSyncState *state; - - state = (VmSyncState *) file->private_data; - - switch (cmd) { - case SYNC_IOC_FREEZE: - if (!capable(CAP_SYS_ADMIN)) { - result = -EPERM; - break; - } - result = VmSyncFreezeDevices(state, (const char __user *) arg); - break; - - case SYNC_IOC_THAW: - if (!capable(CAP_SYS_ADMIN)) { - result = -EPERM; - break; - } - VmSyncThawDevices(state); - result = 0; - break; - - case SYNC_IOC_QUERY: - result = VmSyncQuery((void __user *)arg); - break; - - default: - printk(KERN_DEBUG "vmsync: unknown ioctl %d\n", cmd); - break; - } - return result; -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) -/* - *----------------------------------------------------------------------------- - * - * VmSyncIoctl -- - * - * Wrapper around VmSyncUnlockedIoctl for kernels < 2.6.11, which don't - * support unlocked_ioctl. - * - * Results: - * See VmSyncUnlockedIoctl. - * - * Side effects: - * See VmSyncUnlockedIoctl. - * - *----------------------------------------------------------------------------- - */ - -static int -VmSyncIoctl(struct inode *inode, // IN - struct file *file, // IN - unsigned cmd, // IN - unsigned long arg) // IN/OUT -{ - return (int) VmSyncUnlockedIoctl(file, cmd, arg); -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncOpen -- - * - * Instantiates a new state object and attached it to the file struct. - * - * Results: - * 0, or -ENOMEM if can't allocate memory. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -VmSyncOpen(struct inode *inode, // IN - struct file *f) // IN -{ - if (capable(CAP_SYS_ADMIN)) { - f->private_data = kmem_cache_alloc(gSyncStateCache, GFP_KERNEL); - if (f->private_data == NULL) { - return -ENOMEM; - } - } - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncRelease -- - * - * If the fd was used to freeze devices, then thaw all frozen block devices. - * - * Results: - * Returns 0. - * - * Side effects: - * Calls VmSyncThawDevices. - * - *----------------------------------------------------------------------------- - */ - -static int -VmSyncRelease(struct inode *inode, // IN - struct file *file) // IN -{ - if (capable(CAP_SYS_ADMIN)) { - VmSyncState *state = (VmSyncState *) file->private_data; - if (!cancel_delayed_work(&state->thawTask)) { - flush_scheduled_work(); - } - VmSyncThawDevices(state); - kmem_cache_free(gSyncStateCache, state); - } - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncBlockDeviceCtor -- - * - * Constructor for VmSyncBlockDevice objects. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VmSyncBlockDeviceCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabelem)) // IN -{ - VmSyncBlockDevice *dev = slabelem; - - INIT_LIST_HEAD(&dev->list); - dev->bdev = NULL; - dev->sb = NULL; -} - - -/* - *----------------------------------------------------------------------------- - * - * VmSyncStateCtor -- - * - * Constructor for VmSyncState objects. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -VmSyncStateCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabelem)) // IN -{ - VmSyncState *state = slabelem; - - INIT_LIST_HEAD(&state->devices); - COMPAT_INIT_DELAYED_WORK(&state->thawTask, - VmSyncThawDevicesCallback, state); - compat_mutex_init(&state->lock); -} - - -/* - *----------------------------------------------------------------------------- - * - * init_module -- - * - * Initializes the structures used by the driver, and creates the - * proc file used by the driver to receive commands. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -init_module(void) -{ - struct proc_dir_entry *controlProcEntry; - - atomic_set(&gFreezeCount, 0); - compat_mutex_init(&gFreezeLock); - - /* Create the slab allocators for the module. */ - gBlockDeviceCache = compat_kmem_cache_create("VmSyncBlockDeviceCache", - sizeof (VmSyncBlockDevice), - 0, - SLAB_HWCACHE_ALIGN, - VmSyncBlockDeviceCtor); - if (gBlockDeviceCache == NULL) { - printk(KERN_ERR "vmsync: no memory for block dev slab allocator\n"); - return -ENOMEM; - } - - gSyncStateCache = compat_kmem_cache_create("VmSyncStateCache", - sizeof (VmSyncState), - 0, - SLAB_HWCACHE_ALIGN, - VmSyncStateCtor); - if (gSyncStateCache == NULL) { - printk(KERN_ERR "vmsync: no memory for sync state slab allocator\n"); - kmem_cache_destroy(gBlockDeviceCache); - return -ENOMEM; - } - - /* Create /proc/driver/vmware-sync */ - controlProcEntry = create_proc_entry("driver/vmware-sync", - S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, - NULL); - if (!controlProcEntry) { - printk(KERN_ERR "vmsync: could not create /proc/driver/vmware-sync\n"); - kmem_cache_destroy(gSyncStateCache); - kmem_cache_destroy(gBlockDeviceCache); - return -EINVAL; - } - - controlProcEntry->proc_fops = &VmSyncFileOps; - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * cleanup_module -- - * - * Unregisters the proc file used by the driver. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -cleanup_module(void) -{ - remove_proc_entry("driver/vmware-sync", NULL); - kmem_cache_destroy(gSyncStateCache); - kmem_cache_destroy(gBlockDeviceCache); -} - diff --git a/open-vm-tools/modules/linux/vmsync/vmsync_version.h b/open-vm-tools/modules/linux/vmsync/vmsync_version.h deleted file mode 100644 index 5b3ed875c..000000000 --- a/open-vm-tools/modules/linux/vmsync/vmsync_version.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmsync_version.h -- - * - * Version definitions for the Linux vmsync driver. - */ - -#ifndef _VMSYNC_VERSION_H_ -#define _VMSYNC_VERSION_H_ - -#define VMSYNC_DRIVER_VERSION 1.1.0.1 -#define VMSYNC_DRIVER_VERSION_COMMAS 1,1,0,1 -#define VMSYNC_DRIVER_VERSION_STRING "1.1.0.1" - -#endif /* _VMSYNC_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vmxnet/COPYING b/open-vm-tools/modules/linux/vmxnet/COPYING deleted file mode 100644 index d511905c1..000000000 --- a/open-vm-tools/modules/linux/vmxnet/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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; either version 2 of the License, or - (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/open-vm-tools/modules/linux/vmxnet/Makefile b/open-vm-tools/modules/linux/vmxnet/Makefile deleted file mode 100644 index 4583a8539..000000000 --- a/open-vm-tools/modules/linux/vmxnet/Makefile +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware kernel module Makefile to be distributed externally -#### - -#### -#### SRCROOT _must_ be a relative path. -#### -SRCROOT = . - -# -# open-vm-tools doesn't replicate shared source files for different modules; -# instead, files are kept in shared locations. So define a few useful macros -# to be able to handle both cases cleanly. -# -INCLUDE := -ifdef OVT_SOURCE_DIR -AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf -VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1) -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared -INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include -else -AUTOCONF_DIR := $(SRCROOT)/shared/autoconf -INCLUDE += -I$(SRCROOT)/shared -endif - - -VM_UNAME = $(shell uname -r) - -# Header directory for the running kernel -ifdef LINUXINCLUDE -HEADER_DIR = $(LINUXINCLUDE) -else -HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include -endif - -BUILD_DIR = $(HEADER_DIR)/.. - -DRIVER := vmxnet -PRODUCT := tools-source - -# Grep program -GREP = /bin/grep - -vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) -vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi) - -ifndef VM_KBUILD -VM_KBUILD := no -ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes) -VM_KBUILD := yes -endif -export VM_KBUILD -endif - -ifndef VM_KBUILD_SHOWN -ifeq ($(VM_KBUILD), no) -VM_DUMMY := $(shell echo >&2 "Using standalone build system.") -else -VM_DUMMY := $(shell echo >&2 "Using kernel build system.") -endif -VM_KBUILD_SHOWN := yes -export VM_KBUILD_SHOWN -endif - -ifneq ($(VM_KBUILD), no) - -VMCCVER := $(shell $(CC) -dumpversion) - -# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles... -ifeq ($(VERSION),) - -DRIVER_KO := $(DRIVER).ko - -.PHONY: $(DRIVER_KO) - -auto-build: $(DRIVER_KO) - cp -f $< $(SRCROOT)/../$(DRIVER).o - -# $(DRIVER_KO) is a phony target, so compare file times explicitly -$(DRIVER): $(DRIVER_KO) - if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi - -# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler -VM_CCVER := $(VMCCVER) -export VM_CCVER -VM_CC := $(CC) -export VM_CC - -MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES)) - -# -# Define a setup target that gets built before the actual driver. -# This target may not be used at all, but if it is then it will be defined -# in Makefile.kernel -# -prebuild:: ; -postbuild:: ; - -$(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) modules - $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild -endif - -vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \ - $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \ - -DKBUILD_BASENAME=\"$(DRIVER)\" \ - -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -CC_WARNINGS := -Wall -Wstrict-prototypes -CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD -ifdef VMX86_DEVEL -CC_OPTS += -DVMX86_DEVEL -endif -ifdef VMX86_DEBUG -CC_OPTS += -DVMX86_DEBUG -endif - -include $(SRCROOT)/Makefile.kernel - -else - -include $(SRCROOT)/Makefile.normal - -endif - -#.SILENT: diff --git a/open-vm-tools/modules/linux/vmxnet/Makefile.kernel b/open-vm-tools/modules/linux/vmxnet/Makefile.kernel deleted file mode 100644 index 528ef48f6..000000000 --- a/open-vm-tools/modules/linux/vmxnet/Makefile.kernel +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998 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 -# -########################################################## - -#### -#### VMware vmxnet Makefile to be distributed externally -#### - -INCLUDE += -I. - -ifdef OVT_SOURCE_DIR -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/shared/vmxnet -endif - -EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) - -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/skblin.c, -DVMW_SKB_LINEARIZE_2618, ) - -obj-m += $(DRIVER).o - -clean: - rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ - Module.symvers Modules.symvers Module.markers modules.order \ - $(foreach dir,./,$(addprefix $(dir),.*.cmd .*.o.flags *.o))) diff --git a/open-vm-tools/modules/linux/vmxnet/README b/open-vm-tools/modules/linux/vmxnet/README deleted file mode 100644 index 5d3924f98..000000000 --- a/open-vm-tools/modules/linux/vmxnet/README +++ /dev/null @@ -1,11 +0,0 @@ -The files in this directory are the source files for the VMware -Virtual Ethernet Adapter driver. In order to build, make certain the -Makefile is correct, especially about whether or not your system is -multi-processor or not, and then just type: - - make - -from this directory. A copy of the module will be left in 'vmxnet.o', -which can then be installed in /lib/modules//net. - -If you have any problems or questions, send mail to support@vmware.com diff --git a/open-vm-tools/modules/linux/vmxnet/vmxnet.c b/open-vm-tools/modules/linux/vmxnet/vmxnet.c deleted file mode 100644 index 33afb9b9e..000000000 --- a/open-vm-tools/modules/linux/vmxnet/vmxnet.c +++ /dev/null @@ -1,3146 +0,0 @@ -/********************************************************* - * Copyright (C) 1999 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 - * - *********************************************************/ - -/* - * vmxnet.c: A virtual network driver for VMware. - */ -#include "driver-config.h" -#include "compat_module.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) -#include -#endif - -#include "compat_slab.h" -#include "compat_spinlock.h" -#include "compat_pci.h" -#include "compat_pci_mapping.h" -#include "compat_timer.h" -#include "compat_ethtool.h" -#include "compat_netdevice.h" -#include "compat_skbuff.h" -#include -#include "compat_ioport.h" -#ifndef KERNEL_2_1 -#include -#endif -#include "compat_interrupt.h" - -#include - -#include -#include -#include - -#include "vm_basic_types.h" -#include "vmnet_def.h" -#include "vmxnet_def.h" -#include "vmxnet2_def.h" -#include "vm_device_version.h" -#include "vmxnetInt.h" -#include "net.h" -#include "eth_public.h" -#include "vmxnet_version.h" - -static int vmxnet_debug = 1; - -#define VMXNET_WATCHDOG_TIMEOUT (5 * HZ) - -#if defined(CONFIG_NET_POLL_CONTROLLER) || defined(HAVE_POLL_CONTROLLER) -#define VMW_HAVE_POLL_CONTROLLER -#endif - -static int vmxnet_open(struct net_device *dev); -static int vmxnet_start_tx(struct sk_buff *skb, struct net_device *dev); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static compat_irqreturn_t vmxnet_interrupt(int irq, void *dev_id, - struct pt_regs * regs); -#else -static compat_irqreturn_t vmxnet_interrupt(int irq, void *dev_id); -#endif -#ifdef VMW_HAVE_POLL_CONTROLLER -static void vmxnet_netpoll(struct net_device *dev); -#endif -static int vmxnet_close(struct net_device *dev); -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 defined(HAVE_CHANGE_MTU) || defined(HAVE_NET_DEVICE_OPS) -static int vmxnet_change_mtu(struct net_device *dev, int new_mtu); -#endif - -static Bool vmxnet_check_version(unsigned int ioaddr); -static Bool vmxnet_probe_features(struct net_device *dev, Bool morphed, - Bool probeFromResume); -static void vmxnet_release_private_data(Vmxnet_Private *lp, - struct pci_dev *pdev); -static int vmxnet_probe_device(struct pci_dev *pdev, const struct pci_device_id *id); -static void vmxnet_remove_device(struct pci_dev *pdev); - -static Bool vmxnet_alloc_shared_mem(struct pci_dev *pdev, size_t size, - void **vaOut, dma_addr_t *paOut); - -#ifdef CONFIG_PM - -/* - * Prototype of suspend and resume handlers are different depending on the - * version of Linux kernel. - */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) - -# define VMXNET_SUSPEND_DEVICE(pdev, state) \ - static int vmxnet_suspend_device(struct pci_dev *pdev, pm_message_t state) -# define VMXNET_RESUME_DEVICE(pdev) \ - static int vmxnet_resume_device(struct pci_dev *pdev) - -# define VMXNET_SET_POWER_STATE_D0(pdev) pci_set_power_state(pdev, PCI_D0) - -# define VMXNET_SET_POWER_STATE(pdev, state) \ - pci_set_power_state(pdev, pci_choose_state(pdev, state)) - -# define VMXNET_PM_RETURN(ret) return ret - -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 6) - -# define VMXNET_SUSPEND_DEVICE(pdev, state) \ - static int vmxnet_suspend_device(struct pci_dev *pdev, u32 state) -# define VMXNET_RESUME_DEVICE(pdev) \ - static int vmxnet_resume_device(struct pci_dev *pdev) -# define VMXNET_SET_POWER_STATE_D0(pdev) (pdev)->current_state = 0 -# define VMXNET_SET_POWER_STATE(pdev, state) \ - do { \ - (pdev)->current_state = state; \ - } while (0) -# define VMXNET_PM_RETURN(ret) return ret - -#else - -# define VMXNET_SUSPEND_DEVICE(pdev, state) \ - static void vmxnet_suspend_device(struct pci_dev *pdev) -# define VMXNET_RESUME_DEVICE(pdev) \ - static void vmxnet_resume_device(struct pci_dev *pdev) -# define VMXNET_SET_POWER_STATE_D0(pdev) -# define VMXNET_SET_POWER_STATE(pdev, state) -# define VMXNET_PM_RETURN(ret) - -#endif - -VMXNET_SUSPEND_DEVICE(pdev, state); -VMXNET_RESUME_DEVICE(pdev); - -#endif /* CONFIG_PM */ - -#ifdef MODULE -static int debug = -1; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) - module_param(debug, int, 0444); -#else - MODULE_PARM(debug, "i"); -#endif -#endif - -#ifdef VMXNET_DO_ZERO_COPY -#undef VMXNET_DO_ZERO_COPY -#endif - -#if defined(MAX_SKB_FRAGS) && \ - ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) ) && \ - ( LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 0) ) -#define VMXNET_DO_ZERO_COPY -#endif - -#define VMXNET_GET_LO_ADDR(dma) ((uint32)(dma)) -#define VMXNET_GET_HI_ADDR(dma) ((uint16)(((uint64)(dma)) >> 32)) -#define VMXNET_GET_DMA_ADDR(sge) ((dma_addr_t)((((uint64)(sge).addrHi) << 32) | \ - (sge).addrLow)) - -#define VMXNET_FILL_SG(sg, dma, size)\ -do{\ - (sg).addrLow = VMXNET_GET_LO_ADDR(dma);\ - (sg).addrHi = VMXNET_GET_HI_ADDR(dma);\ - (sg).length = size;\ -} while (0) - -#ifdef VMXNET_DO_ZERO_COPY -#include -#include -#include -#include - -/* - * Tx buffer size that we need for copying header - * max header is: 14(ip) + 4(vlan) + ip (60) + tcp(60) = 138 - * round it up to the power of 2 - */ -#define TX_PKT_HEADER_SIZE 256 - -/* Constants used for Zero Copy Tx */ -#define ETHERNET_HEADER_SIZE 14 -#define VLAN_TAG_LENGTH 4 -#define ETH_FRAME_TYPE_LOCATION 12 -#define ETH_TYPE_VLAN_TAG 0x0081 /* in NBO */ -#define ETH_TYPE_IP 0x0008 /* in NBO */ - -#define PKT_OF_PROTO(skb, type) \ - (*(uint16*)(skb->data + ETH_FRAME_TYPE_LOCATION) == (type) || \ - (*(uint16*)(skb->data + ETH_FRAME_TYPE_LOCATION) == ETH_TYPE_VLAN_TAG && \ - *(uint16*)(skb->data + ETH_FRAME_TYPE_LOCATION + VLAN_TAG_LENGTH) == (type))) - -#define PKT_OF_IPV4(skb) PKT_OF_PROTO(skb, ETH_TYPE_IP) - -#if defined(NETIF_F_TSO) -#define VMXNET_DO_TSO - -#if defined(NETIF_F_GSO) /* 2.6.18 and upwards */ -#define VMXNET_SKB_MSS(skb) skb_shinfo(skb)->gso_size -#else -#define VMXNET_SKB_MSS(skb) skb_shinfo(skb)->tso_size -#endif -#endif - -#endif // VMXNET_DO_ZERO_COPY - -#ifdef VMXNET_DO_TSO -static int disable_lro = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) - module_param(disable_lro, int, 0); -#else - MODULE_PARM(disable_lro, "i"); -#endif -#endif - -#ifdef VMXNET_DEBUG -#define VMXNET_LOG(msg...) printk(KERN_ERR msg) -#else -#define VMXNET_LOG(msg...) -#endif // VMXNET_DEBUG - -/* Data structure used when determining what hardware the driver supports. */ - -static const struct pci_device_id vmxnet_chips[] = - { - { - PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_NET), - .driver_data = VMXNET_CHIP, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), - .driver_data = LANCE_CHIP, - }, - { - 0, - }, - }; - -static struct pci_driver vmxnet_driver = { - .name = "vmxnet", - .id_table = vmxnet_chips, - .probe = vmxnet_probe_device, - .remove = vmxnet_remove_device, -#ifdef CONFIG_PM - .suspend = vmxnet_suspend_device, - .resume = vmxnet_resume_device, -#endif - }; - -#if defined(HAVE_CHANGE_MTU) || defined(HAVE_NET_DEVICE_OPS) -static int -vmxnet_change_mtu(struct net_device *dev, int new_mtu) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - - if (new_mtu < VMXNET_MIN_MTU || new_mtu > VMXNET_MAX_MTU) { - return -EINVAL; - } - - if (new_mtu > 1500 && !lp->jumboFrame) { - return -EINVAL; - } - - dev->mtu = new_mtu; - return 0; -} - -#endif - - -#ifdef SET_ETHTOOL_OPS -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_settings -- - * - * Get device-specific settings. - * - * Results: - * 0 on success, errno on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -vmxnet_get_settings(struct net_device *dev, - struct ethtool_cmd *ecmd) -{ - ecmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_TP; - ecmd->advertising = ADVERTISED_TP; - ecmd->port = PORT_TP; - ecmd->transceiver = XCVR_INTERNAL; - - if (netif_carrier_ok(dev)) { - ecmd->speed = 1000; - ecmd->duplex = DUPLEX_FULL; - } else { - ecmd->speed = -1; - ecmd->duplex = -1; - } - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_drvinfo -- - * - * Ethtool callback to return driver information - * - * Results: - * None. - * - * Side effects: - * Updates *drvinfo - * - *---------------------------------------------------------------------------- - */ - -static void -vmxnet_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *drvinfo) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - - strncpy(drvinfo->driver, vmxnet_driver.name, sizeof(drvinfo->driver)); - drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0'; - - strncpy(drvinfo->version, VMXNET_DRIVER_VERSION_STRING, - sizeof(drvinfo->version)); - drvinfo->driver[sizeof(drvinfo->version) - 1] = '\0'; - - strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); - drvinfo->fw_version[sizeof(drvinfo->fw_version) - 1] = '\0'; - - strncpy(drvinfo->bus_info, pci_name(lp->pdev), ETHTOOL_BUSINFO_LEN); -} - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_tx_csum -- - * - * Ethtool op to check whether or not hw csum offload is enabled. - * - * Result: - * 1 if csum offload is currently used and 0 otherwise. - * - * Side-effects: - * None - * - *---------------------------------------------------------------------------- - */ - -static uint32 -vmxnet_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_rx_csum -- - * - * Ethtool op to check whether or not rx csum offload is enabled. - * - * Result: - * Always return 1 to indicate that rx csum is enabled. - * - * Side-effects: - * None - * - *---------------------------------------------------------------------------- - */ - -static uint32 -vmxnet_get_rx_csum(struct net_device *netdev) -{ - return 1; -} - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_set_tx_csum -- - * - * Ethtool op to change if hw csum offloading should be used or not. - * If the device supports hardware checksum capability netdev features bit - * is set/reset. This bit is referred to while setting hw checksum required - * flag (VMXNET2_TX_HW_XSUM) in xmit ring entry. - * - * Result: - * 0 on success. -EOPNOTSUPP if ethtool asks to set hw checksum and device - * does not support it. - * - * Side-effects: - * None - * - *---------------------------------------------------------------------------- - */ - -static int -vmxnet_set_tx_csum(struct net_device *netdev, uint32 val) -{ - if (val) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - struct Vmxnet_Private *lp = netdev_priv(netdev); - if (lp->capabilities & (VMNET_CAP_IP4_CSUM | VMNET_CAP_HW_CSUM)) { - netdev->features |= NETIF_F_HW_CSUM; - return 0; - } -#endif - return -EOPNOTSUPP; - } else { - netdev->features &= ~NETIF_F_HW_CSUM; - } - return 0; -} - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_set_rx_csum -- - * - * Ethtool op to change if hw csum offloading should be used or not for - * received packets. Hardware checksum on received packets cannot be turned - * off. Hence we fail the ethtool op which turns h/w csum off. - * - * Result: - * 0 when rx csum is set. -EOPNOTSUPP when ethtool tries to reset rx csum. - * - * Side-effects: - * None - * - *---------------------------------------------------------------------------- - */ - -static int -vmxnet_set_rx_csum(struct net_device *netdev, uint32 val) -{ - if (val) { - return 0; - } else { - return -EOPNOTSUPP; - } -} - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_set_tso -- - * - * Ethtool handler to set TSO. If the data is non-zero, TSO is - * enabled. Othewrise, it is disabled. - * - * Results: - * 0 if successful, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -# ifdef VMXNET_DO_TSO -static int -vmxnet_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct Vmxnet_Private *lp = netdev_priv(dev); - - if (!lp->tso) { - return -EINVAL; - } - dev->features |= NETIF_F_TSO; - } else { - dev->features &= ~NETIF_F_TSO; - } - return 0; -} -# endif -#endif - - -static struct ethtool_ops -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 - .get_tso = ethtool_op_get_tso, - .set_tso = vmxnet_set_tso, -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) - .get_ufo = ethtool_op_get_ufo, -# endif -# endif -#endif -}; - - -#else /* !defined(SET_ETHTOOL_OPS) */ - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_settings -- - * - * Ethtool handler to get device settings. - * - * Results: - * 0 if successful, error code otherwise. Settings are copied to addr. - * - * Side effects: - * None. - * - * - *---------------------------------------------------------------------------- - */ - -#ifdef ETHTOOL_GSET -static int -vmxnet_get_settings(struct net_device *dev, void *addr) -{ - struct ethtool_cmd cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.speed = 1000; // 1 Gb - cmd.duplex = 1; // full-duplex - cmd.maxtxpkt = 1; // no tx coalescing - cmd.maxrxpkt = 1; // no rx coalescing - cmd.autoneg = 0; // no autoneg - cmd.advertising = 0; // advertise nothing - - return copy_to_user(addr, &cmd, sizeof(cmd)); -} -#endif - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_link -- - * - * Ethtool handler to get the link state. - * - * Results: - * 0 if successful, error code otherwise. The link status is copied to - * addr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -#ifdef ETHTOOL_GLINK -static int -vmxnet_get_link(struct net_device *dev, void *addr) -{ - compat_ethtool_value value = {ETHTOOL_GLINK}; - value.data = netif_carrier_ok(dev) ? 1 : 0; - return copy_to_user(addr, &value, sizeof(value)); -} -#endif - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_get_tso -- - * - * Ethtool handler to get the TSO setting. - * - * Results: - * 0 if successful, error code otherwise. The TSO setting is copied to - * addr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -#ifdef VMXNET_DO_TSO -static int -vmxnet_get_tso(struct net_device *dev, void *addr) -{ - compat_ethtool_value value = { ETHTOOL_GTSO }; - value.data = (dev->features & NETIF_F_TSO) ? 1 : 0; - if (copy_to_user(addr, &value, sizeof(value))) { - return -EFAULT; - } - return 0; -} -#endif - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_set_tso -- - * - * Ethtool handler to set TSO. If the data in addr is non-zero, TSO is - * enabled. Othewrise, it is disabled. - * - * Results: - * 0 if successful, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -#ifdef VMXNET_DO_TSO -static int -vmxnet_set_tso(struct net_device *dev, void *addr) -{ - compat_ethtool_value value; - if (copy_from_user(&value, addr, sizeof(value))) { - return -EFAULT; - } - - if (value.data) { - struct Vmxnet_Private *lp = netdev_priv(dev); - - if (!lp->tso) { - return -EINVAL; - } - dev->features |= NETIF_F_TSO; - } else { - dev->features &= ~NETIF_F_TSO; - } - return 0; -} -#endif - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_ethtool_ioctl -- - * - * Handler for ethtool ioctl calls. - * - * Results: - * If ethtool op is supported, the outcome of the op. Otherwise, - * -EOPNOTSUPP. - * - * Side effects: - * - * - *---------------------------------------------------------------------------- - */ - -#ifdef SIOCETHTOOL -static int -vmxnet_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) -{ - uint32_t cmd; - if (copy_from_user(&cmd, ifr->ifr_data, sizeof(cmd))) { - return -EFAULT; - } - switch (cmd) { -#ifdef ETHTOOL_GSET - case ETHTOOL_GSET: - return vmxnet_get_settings(dev, ifr->ifr_data); -#endif -#ifdef ETHTOOL_GLINK - case ETHTOOL_GLINK: - return vmxnet_get_link(dev, ifr->ifr_data); -#endif -#ifdef VMXNET_DO_TSO - case ETHTOOL_GTSO: - return vmxnet_get_tso(dev, ifr->ifr_data); - case ETHTOOL_STSO: - return vmxnet_set_tso(dev, ifr->ifr_data); -#endif - default: - return -EOPNOTSUPP; - } -} -#endif - - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_ioctl -- - * - * Handler for ioctl calls. - * - * Results: - * If ioctl is supported, the result of that operation. Otherwise, - * -EOPNOTSUPP. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -vmxnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - switch (cmd) { -#ifdef SIOCETHTOOL - case SIOCETHTOOL: - return vmxnet_ethtool_ioctl(dev, ifr); -#endif - } - return -EOPNOTSUPP; -} -#endif /* SET_ETHTOOL_OPS */ - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_init -- - * - * Initialization, called by Linux when the module is loaded. - * - * Results: - * Returns 0 for success, negative errno value otherwise. - * - * Side effects: - * See vmxnet_probe_device, which does all the work. - * - *----------------------------------------------------------------------------- - */ - -static int -vmxnet_init(void) -{ - int err; - - if (vmxnet_debug > 0) { - vmxnet_debug = debug; - } - - printk(KERN_INFO "VMware vmxnet virtual NIC driver\n"); - - err = pci_register_driver(&vmxnet_driver); - if (err < 0) { - return err; - } - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_exit -- - * - * Cleanup, called by Linux when the module is unloaded. - * - * Results: - * None. - * - * Side effects: - * Unregisters all vmxnet devices with Linux and frees memory. - * - *----------------------------------------------------------------------------- - */ - -static void -vmxnet_exit(void) -{ - pci_unregister_driver(&vmxnet_driver); -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) -/* - *----------------------------------------------------------------------------- - * - * vmxnet_tx_timeout -- - * - * Network device tx_timeout routine. Called by Linux when the tx - * queue has been stopped for more than dev->watchdog_timeo jiffies. - * - * Results: - * None. - * - * Side effects: - * Tries to restart the transmit queue. - * - *----------------------------------------------------------------------------- - */ -static void -vmxnet_tx_timeout(struct net_device *dev) -{ - netif_wake_queue(dev); -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) */ - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_link_check -- - * - * Propagate device link status to netdev. - * - * Results: - * None. - * - * Side effects: - * Rearms timer for next check. - * - *----------------------------------------------------------------------------- - */ - -static void -vmxnet_link_check(unsigned long data) // IN: netdevice pointer -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) - struct net_device *dev = (struct net_device *)data; - struct Vmxnet_Private *lp = netdev_priv(dev); - uint32 status; - int ok; - - status = inl(dev->base_addr + VMXNET_STATUS_ADDR); - ok = (status & VMXNET_STATUS_CONNECTED) != 0; - if (ok != netif_carrier_ok(dev)) { - if (ok) { - netif_carrier_on(dev); - } else { - netif_carrier_off(dev); - } - } - - /* - * It would be great if vmxnet2 could generate interrupt when link - * state changes. Maybe next time. Let's just poll media every - * two seconds (2 seconds is same interval pcnet32 uses). - */ - mod_timer(&lp->linkCheckTimer, jiffies + 2 * HZ); -#else - /* - * Nothing to do on kernels before 2.3.43. They do not have - * netif_carrier_*, and as we've lived without link state for - * years, let's live without it forever on these kernels. - */ -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) */ -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_morph_device -- - * - * Morph a lance device into vmxnet device. - * - * Results: - * Returns 0 on success, -1 on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static int -vmxnet_morph_device(unsigned int morphAddr) // IN -{ - uint16 magic; - - /* Read morph port to verify that we can morph the adapter. */ - magic = inw(morphAddr); - if (magic != LANCE_CHIP && magic != VMXNET_CHIP) { - printk(KERN_ERR "Invalid magic, read: 0x%08X\n", magic); - return -1; - } - - /* Morph adapter. */ - outw(VMXNET_CHIP, morphAddr); - - /* Verify that we morphed correctly. */ - - magic = inw(morphAddr); - if (magic != VMXNET_CHIP) { - printk(KERN_ERR "Couldn't morph adapter. Invalid magic, read: 0x%08X\n", - magic); - goto morph_back; - } - - return 0; - -morph_back: - /* Morph back to LANCE hw. */ - outw(LANCE_CHIP, morphAddr); - return -1; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_unmorph_device -- - * - * Morph a vmxnet adapter back to vlance. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -vmxnet_unmorph_device(unsigned int morphAddr) // IN -{ - uint16 magic; - - /* Read morph port to verify that we can morph the adapter. */ - magic = inw(morphAddr); - if (magic != VMXNET_CHIP) { - printk(KERN_ERR "Adapter not morphed, magic: 0x%08X\n", magic); - return; - } - - /* Unmorph adapter. */ - outw(LANCE_CHIP, morphAddr); - - /* Verify that we morphed correctly. */ - - magic = inw(morphAddr); - if (magic != LANCE_CHIP) { - printk(KERN_ERR "Couldn't unmorph adapter. Invalid magic, read: 0x%08X\n", - magic); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_probe_device -- - * - * Most of the initialization at module load time is done here. - * - * Results: - * Returns 0 for success, an error otherwise. - * - * Side effects: - * Switches device from vlance to vmxnet mode, creates ethernet - * structure for device, and registers device with network stack. - * - *----------------------------------------------------------------------------- - */ - -static int -vmxnet_probe_device(struct pci_dev *pdev, // IN: vmxnet PCI device - const struct pci_device_id *id) // IN: matching device ID -{ -#ifdef HAVE_NET_DEVICE_OPS - /* - * .ndo_set_features not required as existing initialization - * takes care of the necessary checks. The init routine appropriately - * sets netdev->hw_features after validating the device capabilities. - * ndo_set_features only required if driver is changing - * any other intenal variables besides the netdev->features. - */ - static const struct net_device_ops vmxnet_netdev_ops = { - .ndo_open = &vmxnet_open, - .ndo_start_xmit = &vmxnet_start_tx, - .ndo_stop = &vmxnet_close, - .ndo_get_stats = &vmxnet_get_stats, -#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) - .ndo_set_multicast_list = &vmxnet_set_multicast_list, -#else - .ndo_set_rx_mode = &vmxnet_set_multicast_list, -#endif - .ndo_change_mtu = &vmxnet_change_mtu, -# ifdef VMW_HAVE_POLL_CONTROLLER - .ndo_poll_controller = vmxnet_netpoll, -# endif - .ndo_set_mac_address = &vmxnet_set_mac_address, - .ndo_tx_timeout = &vmxnet_tx_timeout, - }; -#endif /* HAVE_NET_DEVICE_OPS */ - struct Vmxnet_Private *lp; - struct net_device *dev; - unsigned int ioaddr, reqIOAddr, reqIOSize; - unsigned int irq_line; - Bool morphed = FALSE; - int i; - - i = pci_enable_device(pdev); - if (i) { - printk(KERN_ERR "Cannot enable vmxnet adapter %s: error %d\n", - pci_name(pdev), i); - return i; - } - pci_set_master(pdev); - irq_line = pdev->irq; - ioaddr = pci_resource_start(pdev, 0); - - reqIOAddr = ioaddr; - /* Found adapter, adjust ioaddr to match the adapter we found. */ - if (id->driver_data == VMXNET_CHIP) { - reqIOSize = VMXNET_CHIP_IO_RESV_SIZE; - } else { - /* - * Since this is a vlance adapter we can only use it if - * its I/0 space is big enough for the adapter to be - * capable of morphing. This is the first requirement - * for this adapter to potentially be morphable. The - * layout of a morphable LANCE adapter is - * - * I/O space: - * - * |------------------| - * | LANCE IO PORTS | - * |------------------| - * | MORPH PORT | - * |------------------| - * | VMXNET IO PORTS | - * |------------------| - * - * VLance has 8 ports of size 4 bytes, the morph port is 4 bytes, and - * Vmxnet has 10 ports of size 4 bytes. - * - * We shift up the ioaddr with the size of the LANCE I/O space since - * we want to access the vmxnet ports. We also shift the ioaddr up by - * the MORPH_PORT_SIZE so other port access can be independent of - * whether we are Vmxnet or a morphed VLance. This means that when - * we want to access the MORPH port we need to subtract the size - * from ioaddr to get to it. - */ - - ioaddr += LANCE_CHIP_IO_RESV_SIZE + MORPH_PORT_SIZE; - reqIOSize = LANCE_CHIP_IO_RESV_SIZE + MORPH_PORT_SIZE + - VMXNET_CHIP_IO_RESV_SIZE; - } - /* Do not attempt to morph non-morphable AMD PCnet */ - if (reqIOSize > pci_resource_len(pdev, 0)) { - printk(KERN_INFO "vmxnet: Device in slot %s is not supported by this driver.\n", - pci_name(pdev)); - goto pci_disable; - } - - /* - * Request I/O region with adjusted base address and size. The adjusted - * values are needed and used if we release the region in case of failure. - */ - - if (!compat_request_region(reqIOAddr, reqIOSize, VMXNET_CHIP_NAME)) { - printk(KERN_INFO "vmxnet: Another driver already loaded for device in slot %s.\n", - pci_name(pdev)); - goto pci_disable; - } - - /* Morph the underlying hardware if we found a VLance adapter. */ - if (id->driver_data == LANCE_CHIP) { - if (vmxnet_morph_device(ioaddr - MORPH_PORT_SIZE) == 0) { - morphed = TRUE; - } else { - goto release_reg; - } - } - - printk(KERN_INFO "Found vmxnet/PCI at %#x, irq %u.\n", ioaddr, irq_line); - - if (!vmxnet_check_version(ioaddr)) { - goto morph_back; - } - - dev = alloc_etherdev(sizeof *lp); - if (!dev) { - printk(KERN_ERR "Unable to allocate ethernet device\n"); - goto morph_back; - } - - lp = netdev_priv(dev); - lp->pdev = pdev; - - dev->base_addr = ioaddr; - - if (!vmxnet_probe_features(dev, morphed, FALSE)) { - goto free_dev; - } - - dev->irq = irq_line; - -#ifdef HAVE_NET_DEVICE_OPS - dev->netdev_ops = &vmxnet_netdev_ops; -#else - dev->open = &vmxnet_open; - dev->hard_start_xmit = &vmxnet_start_tx; - dev->stop = &vmxnet_close; - dev->get_stats = &vmxnet_get_stats; - dev->set_multicast_list = &vmxnet_set_multicast_list; -#ifdef HAVE_CHANGE_MTU - dev->change_mtu = &vmxnet_change_mtu; -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) - dev->tx_timeout = &vmxnet_tx_timeout; -#endif -#ifdef VMW_HAVE_POLL_CONTROLLER - dev->poll_controller = vmxnet_netpoll; -#endif - /* Do this after ether_setup(), which sets the default value. */ - dev->set_mac_address = &vmxnet_set_mac_address; -#endif /* HAVE_NET_DEVICE_OPS */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) - dev->watchdog_timeo = VMXNET_WATCHDOG_TIMEOUT; -#endif - -#ifdef SET_ETHTOOL_OPS - SET_ETHTOOL_OPS(dev, &vmxnet_ethtool_ops); -#else - dev->do_ioctl = vmxnet_ioctl; -#endif - - COMPAT_SET_MODULE_OWNER(dev); - COMPAT_SET_NETDEV_DEV(dev, &pdev->dev); - - if (register_netdev(dev)) { - printk(KERN_ERR "Unable to register device\n"); - goto free_dev_dd; - } - /* - * Use deferrable timer - we want 2s interval, but if it will - * be 2 seconds or 10 seconds, we do not care. - */ - compat_init_timer_deferrable(&lp->linkCheckTimer); - lp->linkCheckTimer.data = (unsigned long)dev; - lp->linkCheckTimer.function = vmxnet_link_check; - vmxnet_link_check(lp->linkCheckTimer.data); - - /* Do this after register_netdev(), which sets device name */ - VMXNET_LOG("%s: %s at %#3lx assigned IRQ %d.\n", - dev->name, lp->name, dev->base_addr, dev->irq); - - pci_set_drvdata(pdev, dev); -#ifdef CONFIG_PM - /* - * Initialize pci_dev's current_state for .suspend to work properly. - */ - - VMXNET_SET_POWER_STATE_D0(pdev); -#endif - return 0; - -free_dev_dd: - vmxnet_release_private_data(lp, pdev); -free_dev: - free_netdev(dev); -morph_back: - if (morphed) { - vmxnet_unmorph_device(ioaddr - MORPH_PORT_SIZE); - } -release_reg: - release_region(reqIOAddr, reqIOSize); -pci_disable: - pci_disable_device(pdev); - return -EBUSY; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_check_version -- - * - * Helper to check version of the device backend to see if it is - * compatible with the driver. Called from .probe or .resume. - * - * Results: - * TRUE/FALSE on success/failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static Bool -vmxnet_check_version(unsigned int ioaddr) // IN: -{ - /* VMware's version of the magic number */ - unsigned int low_vmware_version; - - low_vmware_version = inl(ioaddr + VMXNET_LOW_VERSION); - if ((low_vmware_version & 0xffff0000) != (VMXNET2_MAGIC & 0xffff0000)) { - printk(KERN_ERR "Driver version 0x%08X doesn't match version 0x%08X\n", - VMXNET2_MAGIC, low_vmware_version); - return FALSE; - } else { - /* - * The low version looked OK so get the high version and make sure that - * our version is supported. - */ - unsigned int high_vmware_version = inl(ioaddr + VMXNET_HIGH_VERSION); - if ((VMXNET2_MAGIC < low_vmware_version) || - (VMXNET2_MAGIC > high_vmware_version)) { - printk(KERN_ERR - "Driver version 0x%08X doesn't match version 0x%08X, 0x%08X\n", - VMXNET2_MAGIC, low_vmware_version, high_vmware_version); - return FALSE; - } - } - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_probe_features -- - * - * Helper to probe device features and capabilities and initialize various - * driver state. Called from the .probe and .resume handlers. During - * .resume phase this function validates that compatible - * feature/capabilities (or other state) is obtained from the device as - * during the .probe phase prior to guest suspend or hibernate. - * - * Results: - * Boolean indicating success/failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static Bool -vmxnet_probe_features(struct net_device *dev, // IN: - Bool morphed, // IN: - Bool probeFromResume) // IN: -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - unsigned int numRxBuffers, numRxBuffers2, maxNumRxBuffers, defNumRxBuffers; - unsigned int numTxBuffers, maxNumTxBuffers, defNumTxBuffers; - Bool enhanced = FALSE; - int i; - unsigned int ioaddr = dev->base_addr; - - VMXNET_ASSERT(lp); - - outl(VMXNET_CMD_GET_FEATURES, dev->base_addr + VMXNET_COMMAND_ADDR); - if (probeFromResume) { - if ((lp->features & inl(dev->base_addr + VMXNET_COMMAND_ADDR)) != - lp->features) { - return FALSE; - } - } else { - lp->features = inl(dev->base_addr + VMXNET_COMMAND_ADDR); - } - - outl(VMXNET_CMD_GET_CAPABILITIES, dev->base_addr + VMXNET_COMMAND_ADDR); - if (probeFromResume) { - if ((lp->capabilities & inl(dev->base_addr + VMXNET_COMMAND_ADDR)) != - lp->capabilities) { - return FALSE; - } - } else { - lp->capabilities = inl(dev->base_addr + VMXNET_COMMAND_ADDR); - } - - /* determine the features supported */ - lp->zeroCopyTx = FALSE; - lp->partialHeaderCopyEnabled = FALSE; - lp->tso = FALSE; - lp->chainTx = FALSE; - lp->chainRx = FALSE; - lp->jumboFrame = FALSE; - lp->lpd = FALSE; - - printk(KERN_INFO "features:"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - if (lp->capabilities & VMNET_CAP_IP4_CSUM) { - dev->features |= NETIF_F_HW_CSUM; - printk(" ipCsum"); - } - if (lp->capabilities & VMNET_CAP_HW_CSUM) { - dev->features |= NETIF_F_HW_CSUM; - printk(" hwCsum"); - } -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) - dev->features |= NETIF_F_RXCSUM; - printk( " rxCsum"); -#endif - -#ifdef VMXNET_DO_ZERO_COPY - if (lp->capabilities & VMNET_CAP_SG && - lp->features & VMXNET_FEATURE_ZERO_COPY_TX){ - dev->features |= NETIF_F_SG; - lp->zeroCopyTx = TRUE; - printk(" zeroCopy"); - - if (lp->capabilities & VMNET_CAP_ENABLE_HEADER_COPY) { - lp->partialHeaderCopyEnabled = TRUE; - printk(" partialHeaderCopy"); - } - - if (lp->capabilities & VMNET_CAP_TX_CHAIN) { - lp->chainTx = TRUE; - } - - if (lp->capabilities & VMNET_CAP_RX_CHAIN) { - lp->chainRx = TRUE; - } - - if (lp->chainRx && lp->chainTx && - (lp->features & VMXNET_FEATURE_JUMBO_FRAME)) { - lp->jumboFrame = TRUE; - printk(" jumboFrame"); - } - } - -#ifdef VMXNET_DO_TSO - if ((lp->capabilities & VMNET_CAP_TSO) && - (lp->capabilities & (VMNET_CAP_IP4_CSUM | VMNET_CAP_HW_CSUM)) && - // tso only makes sense if we have hw csum offload - lp->chainTx && lp->zeroCopyTx && - lp->features & VMXNET_FEATURE_TSO) { - dev->features |= NETIF_F_TSO; - lp->tso = TRUE; - printk(" tso"); - } - - if ((lp->capabilities & VMNET_CAP_LPD) && - (lp->features & VMXNET_FEATURE_LPD) && - !disable_lro) { - lp->lpd = TRUE; - printk(" lpd"); - } -#endif -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) - dev->hw_features = dev->features & (~NETIF_F_RXCSUM); -#endif - - printk("\n"); - - /* check if this is enhanced vmxnet device */ - if ((lp->features & VMXNET_FEATURE_TSO) && - (lp->features & VMXNET_FEATURE_JUMBO_FRAME)) { - enhanced = TRUE; - } - - /* determine rx/tx ring sizes */ - if (enhanced) { - maxNumRxBuffers = ENHANCED_VMXNET2_MAX_NUM_RX_BUFFERS; - defNumRxBuffers = ENHANCED_VMXNET2_DEFAULT_NUM_RX_BUFFERS; - } else { - maxNumRxBuffers = VMXNET2_MAX_NUM_RX_BUFFERS; - defNumRxBuffers = VMXNET2_DEFAULT_NUM_RX_BUFFERS; - } - - outl(VMXNET_CMD_GET_NUM_RX_BUFFERS, dev->base_addr + VMXNET_COMMAND_ADDR); - numRxBuffers = inl(dev->base_addr + VMXNET_COMMAND_ADDR); - if (numRxBuffers == 0 || numRxBuffers > maxNumRxBuffers) { - numRxBuffers = defNumRxBuffers; - } - - if (lp->jumboFrame || lp->lpd) { - numRxBuffers2 = numRxBuffers * 4; - if (numRxBuffers2 > VMXNET2_MAX_NUM_RX_BUFFERS2) { - numRxBuffers2 = VMXNET2_MAX_NUM_RX_BUFFERS2; - } - } else { - numRxBuffers2 = 1; - } - - printk(KERN_INFO "numRxBuffers = %d, numRxBuffers2 = %d\n", - numRxBuffers, numRxBuffers2); - if (lp->tso || lp->jumboFrame) { - maxNumTxBuffers = VMXNET2_MAX_NUM_TX_BUFFERS_TSO; - defNumTxBuffers = VMXNET2_DEFAULT_NUM_TX_BUFFERS_TSO; - } else { - maxNumTxBuffers = VMXNET2_MAX_NUM_TX_BUFFERS; - defNumTxBuffers = VMXNET2_DEFAULT_NUM_TX_BUFFERS; - } - - outl(VMXNET_CMD_GET_NUM_TX_BUFFERS, dev->base_addr + VMXNET_COMMAND_ADDR); - numTxBuffers = inl(dev->base_addr + VMXNET_COMMAND_ADDR); - if (numTxBuffers == 0 || numTxBuffers > maxNumTxBuffers) { - numTxBuffers = defNumTxBuffers; - } - - lp->ddSize = sizeof(Vmxnet2_DriverData) + - (numRxBuffers + numRxBuffers2) * sizeof(Vmxnet2_RxRingEntry) + - numTxBuffers * sizeof(Vmxnet2_TxRingEntry); - VMXNET_LOG("vmxnet: numRxBuffers=((%d+%d)*%d) numTxBuffers=(%d*%d) ddSize=%d\n", - numRxBuffers, numRxBuffers2, (uint32)sizeof(Vmxnet2_RxRingEntry), - numTxBuffers, (uint32)sizeof(Vmxnet2_TxRingEntry), - (int)lp->ddSize); - if (!vmxnet_alloc_shared_mem(lp->pdev, lp->ddSize, (void **)&lp->dd, &lp->ddPA)) { - printk(KERN_ERR "Unable to allocate memory for driver data\n"); - return FALSE; - } - memset(lp->dd, 0, lp->ddSize); - spin_lock_init(&lp->txLock); - lp->numRxBuffers = numRxBuffers; - lp->numRxBuffers2 = numRxBuffers2; - lp->numTxBuffers = numTxBuffers; - /* So that the vmkernel can check it is compatible */ - lp->dd->magic = VMXNET2_MAGIC; - lp->dd->length = lp->ddSize; - lp->name = VMXNET_CHIP_NAME; - - /* - * Store whether we are morphed so we can figure out how to - * clean up when we unload. - */ - lp->morphed = morphed; - - if (lp->capabilities & VMNET_CAP_VMXNET_APROM) { - for (i = 0; i < ETH_ALEN; i++) { - dev->dev_addr[i] = inb(ioaddr + VMXNET_APROM_ADDR + i); - } - for (i = 0; i < ETH_ALEN; i++) { - outb(dev->dev_addr[i], ioaddr + VMXNET_MAC_ADDR + i); - } - } else { - /* - * Be backwards compatible and use the MAC address register to - * get MAC address. - */ - for (i = 0; i < ETH_ALEN; i++) { - dev->dev_addr[i] = inb(ioaddr + VMXNET_MAC_ADDR + i); - } - } - -#ifdef VMXNET_DO_ZERO_COPY - lp->txBufferStart = NULL; - lp->dd->txBufferPhysStart = 0; - lp->dd->txBufferPhysLength = 0; - - if (lp->partialHeaderCopyEnabled) { - lp->txBufferSize = numTxBuffers * TX_PKT_HEADER_SIZE; - - if (vmxnet_alloc_shared_mem(lp->pdev, lp->txBufferSize, - (void **)&lp->txBufferStart, &lp->txBufferPA)) { - lp->dd->txBufferPhysStart = (uint32)lp->txBufferPA; - lp->dd->txBufferPhysLength = (uint32)lp->txBufferSize; - lp->dd->txPktMaxSize = TX_PKT_HEADER_SIZE; - } else { - lp->partialHeaderCopyEnabled = FALSE; - printk(KERN_INFO "failed to allocate tx buffer, disable partialHeaderCopy\n"); - } - } -#endif - - return TRUE; -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_alloc_shared_mem -- - * - * Attempts to allocate dma-able memory that uses a 32-bit PA. - * - * Results: - * TRUE on success, otherwise FALSE. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -#define FITS_IN_32_BITS(_x) ((_x) == ((_x) & 0xFFFFFFFF)) - -static Bool -vmxnet_alloc_shared_mem(struct pci_dev *pdev, // IN: - size_t size, // IN: - void **vaOut, // OUT: - dma_addr_t *paOut) // OUT: -{ - void *va = NULL; - dma_addr_t pa = 0; - - /* DMA-mapping.txt says 32-bit DMA by default */ - va = compat_pci_alloc_consistent(pdev, size, &pa); - if (!va) { - *vaOut = NULL; - *paOut = 0; - return FALSE; - } - - VMXNET_ASSERT(FITS_IN_32_BITS(pa) && - FITS_IN_32_BITS((uint64)pa + (size - 1))); - *vaOut = va; - *paOut = pa; - - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_remove_device -- - * - * Cleanup, called for each device on unload. - * - * Results: - * None. - * - * Side effects: - * Unregisters vmxnet device with Linux and frees memory. - * - *----------------------------------------------------------------------------- - */ -static void -vmxnet_remove_device(struct pci_dev* pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct Vmxnet_Private *lp = netdev_priv(dev); - - /* - * Do this before device is gone so we never call netif_carrier_* after - * unregistering netdevice. - */ - compat_del_timer_sync(&lp->linkCheckTimer); - unregister_netdev(dev); - - /* Unmorph adapter if it was morphed. */ - - if (lp->morphed) { - vmxnet_unmorph_device(dev->base_addr - MORPH_PORT_SIZE); - release_region(dev->base_addr - - (LANCE_CHIP_IO_RESV_SIZE + MORPH_PORT_SIZE), - VMXNET_CHIP_IO_RESV_SIZE + - (LANCE_CHIP_IO_RESV_SIZE + MORPH_PORT_SIZE)); - } else { - release_region(dev->base_addr, VMXNET_CHIP_IO_RESV_SIZE); - } - - vmxnet_release_private_data(lp, pdev); - free_netdev(dev); - pci_disable_device(pdev); -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_release_private_data -- - * - * Helper to release/free some private driver data. Called from the - * .remove handler and the .suspend handler. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static void -vmxnet_release_private_data(Vmxnet_Private *lp, // IN: - struct pci_dev *pdev) // IN: -{ -#ifdef VMXNET_DO_ZERO_COPY - if (lp->partialHeaderCopyEnabled && lp->txBufferStart) { - compat_pci_free_consistent(pdev, lp->txBufferSize, - lp->txBufferStart, lp->txBufferPA); - lp->txBufferStart = NULL; - } -#endif - - if (lp->dd) { - compat_pci_free_consistent(pdev, lp->ddSize, lp->dd, lp->ddPA); - lp->dd = NULL; - } -} - - -#ifdef CONFIG_PM -/* - *----------------------------------------------------------------------------- - * - * vmxnet_suspend_device -- - * - * Suspend PM handler. - * - * Results: - * Returns 0 for success. - * - * Side effects: - * Morphs device back to lance mode. - * - *----------------------------------------------------------------------------- - */ - -VMXNET_SUSPEND_DEVICE(/* struct pci_dev * */ pdev, // IN: pci device - /* pm_message_t */ state) // IN: state -{ - /* - * Suspend needs to: - * 1. Disable IRQ. - * 2. Morph back to vlance. - * 3. Disable bus-mastering. - * 4. Put device to low power state. - * 5. Enable wake up. - * - * TODO: implement 5. - */ - - struct net_device *dev = pci_get_drvdata(pdev); - struct Vmxnet_Private *lp = netdev_priv(dev); - - if (lp->devOpen) { - /* - * Close the device first (and unmap rings, frees skbs, etc) - * since morphing will reset the device. However, still - * keep the device marked as "opened" so we can reopen it at - * resume time. - */ - vmxnet_close(dev); - lp->devOpen = TRUE; - } - - if (lp->morphed) { /* Morph back to vlance. */ - vmxnet_unmorph_device(dev->base_addr - MORPH_PORT_SIZE); - } - - pci_disable_device(pdev); /* Disables bus-mastering. */ - vmxnet_release_private_data(lp, pdev); - - VMXNET_SET_POWER_STATE(pdev, state); - VMXNET_PM_RETURN(0); -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_resume_device -- - * - * Resume PM handler. - * TODO: check capability of the device on resume. - * - * Results: - * Returns 0 for success, an error otherwise. - * - * Side effects: - * Morphs device to vxmnet mode. - * - *----------------------------------------------------------------------------- - */ - -VMXNET_RESUME_DEVICE(/* struct pci_dev* */ pdev) // IN: pci device -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct Vmxnet_Private *lp = netdev_priv(dev); - int ret; - - ret = pci_enable_device(pdev); /* Does not enable bus-mastering. */ - if (ret) { - printk(KERN_ERR "Cannot resume vmxnet adapter %s: error %d\n", - pci_name(pdev), ret); - VMXNET_PM_RETURN(ret); - } - - pci_set_master(pdev); - - if (lp->morphed) { - if (vmxnet_morph_device(dev->base_addr - MORPH_PORT_SIZE) != 0) { - ret = -ENODEV; - goto disable_pci; - } - } - - if (!vmxnet_check_version(dev->base_addr) || - !vmxnet_probe_features(dev, lp->morphed, TRUE)) { - ret = -ENODEV; - goto disable_pci; - } - - if (lp->devOpen) { - /* - * The adapter was closed at suspend time. So mark it as closed, then - * try to reopen it. - */ - - lp->devOpen = FALSE; - ret = vmxnet_open(dev); - if (ret) { - /* - * We do not unmorph the device here since that would be handled in - * the .remove handler. - */ - - printk(KERN_ERR "Could not open vmxnet adapter %s: error %d\n", - pci_name(pdev), ret); - goto disable_pci; - } - } - - VMXNET_SET_POWER_STATE_D0(pdev); - VMXNET_PM_RETURN(0); - -disable_pci: - pci_disable_device(pdev); /* Disables bus-mastering. */ - VMXNET_PM_RETURN(ret); -} -#endif - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_init_ring -- - * - * Initializes buffer rings in Vmxnet_Private structure. Allocates skbs - * to receive into. Called by vmxnet_open. - * - * Results: - * 0 on success; -1 on failure to allocate skbs. - * - * Side effects: - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_init_ring(struct net_device *dev) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - Vmxnet2_DriverData *dd = lp->dd; - unsigned int i; - size_t offset; - - offset = sizeof(*dd); - - dd->rxRingLength = lp->numRxBuffers; - dd->rxRingOffset = offset; - lp->rxRing = (Vmxnet2_RxRingEntry *)((uintptr_t)dd + offset); - offset += lp->numRxBuffers * sizeof(Vmxnet2_RxRingEntry); - - dd->rxRingLength2 = lp->numRxBuffers2; - dd->rxRingOffset2 = offset; - lp->rxRing2 = (Vmxnet2_RxRingEntry *)((uintptr_t)dd + offset); - offset += lp->numRxBuffers2 * sizeof(Vmxnet2_RxRingEntry); - - dd->txRingLength = lp->numTxBuffers; - dd->txRingOffset = offset; - lp->txRing = (Vmxnet2_TxRingEntry *)((uintptr_t)dd + offset); - offset += lp->numTxBuffers * sizeof(Vmxnet2_TxRingEntry); - - VMXNET_LOG("vmxnet_init_ring: offset=%"FMT64"d length=%d\n", - (uint64)offset, dd->length); - - for (i = 0; i < lp->numRxBuffers; i++) { - lp->rxSkbuff[i] = dev_alloc_skb(PKT_BUF_SZ + COMPAT_NET_IP_ALIGN); - if (lp->rxSkbuff[i] == NULL) { - unsigned int j; - - printk (KERN_ERR "%s: vmxnet_init_ring dev_alloc_skb failed.\n", dev->name); - for (j = 0; j < i; j++) { - compat_dev_kfree_skb(lp->rxSkbuff[j], FREE_WRITE); - lp->rxSkbuff[j] = NULL; - } - return -ENOMEM; - } - - skb_reserve(lp->rxSkbuff[i], COMPAT_NET_IP_ALIGN); - - lp->rxRing[i].paddr = compat_pci_map_single(lp->pdev, lp->rxSkbuff[i]->data, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - lp->rxRing[i].bufferLength = PKT_BUF_SZ; - lp->rxRing[i].actualLength = 0; - lp->rxRing[i].ownership = VMXNET2_OWNERSHIP_NIC; - } - -#ifdef VMXNET_DO_ZERO_COPY - if (lp->jumboFrame || lp->lpd) { - struct pci_dev *pdev = lp->pdev; - - dd->maxFrags = MAX_SKB_FRAGS; - - for (i = 0; i < lp->numRxBuffers2; i++) { - lp->rxPages[i] = alloc_page(GFP_KERNEL); - if (lp->rxPages[i] == NULL) { - unsigned int j; - - printk (KERN_ERR "%s: vmxnet_init_ring alloc_page failed.\n", dev->name); - for (j = 0; j < i; j++) { - put_page(lp->rxPages[j]); - lp->rxPages[j] = NULL; - } - for (j = 0; j < lp->numRxBuffers; j++) { - compat_dev_kfree_skb(lp->rxSkbuff[j], FREE_WRITE); - lp->rxSkbuff[j] = NULL; - } - return -ENOMEM; - } - - lp->rxRing2[i].paddr = pci_map_page(pdev, lp->rxPages[i], 0, - PAGE_SIZE, PCI_DMA_FROMDEVICE); - lp->rxRing2[i].bufferLength = PAGE_SIZE; - lp->rxRing2[i].actualLength = 0; - lp->rxRing2[i].ownership = VMXNET2_OWNERSHIP_NIC_FRAG; - } - } else -#endif - { - // dummy rxRing2 tacked on to the end, with a single unusable entry - lp->rxRing2[0].paddr = 0; - lp->rxRing2[0].bufferLength = 0; - lp->rxRing2[0].actualLength = 0; - lp->rxRing2[0].ownership = VMXNET2_OWNERSHIP_DRIVER; - } - - dd->rxDriverNext = 0; - dd->rxDriverNext2 = 0; - - for (i = 0; i < lp->numTxBuffers; i++) { - lp->txRing[i].ownership = VMXNET2_OWNERSHIP_DRIVER; - lp->txBufInfo[i].skb = NULL; - lp->txBufInfo[i].eop = 0; - lp->txRing[i].sg.sg[0].addrHi = 0; - lp->txRing[i].sg.addrType = NET_SG_PHYS_ADDR; - } - - dd->txDriverCur = dd->txDriverNext = 0; - dd->savedRxNICNext = dd->savedRxNICNext2 = dd->savedTxNICNext = 0; - dd->txStopped = FALSE; - - if (lp->lpd) { - dd->featureCtl |= VMXNET_FEATURE_LPD; - } - - return 0; -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_open -- - * - * Network device open routine. Called by Linux when the interface is - * brought up. - * - * Results: - * 0 on success; else negative errno value. - * - * Side effects: - * Allocates an IRQ if not already allocated. Sets our Vmxnet_Private - * structure to be the shared area with the lower layer. - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_open(struct net_device *dev) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - uint32 ddPA; - - /* - * The .suspend handler frees driver data, so we need this check. - */ - if (UNLIKELY(!lp->dd)) { - return -ENOMEM; - } - - if (dev->irq == 0 || request_irq(dev->irq, &vmxnet_interrupt, - COMPAT_IRQF_SHARED, dev->name, (void *)dev)) { - return -EAGAIN; - } - - if (vmxnet_debug > 1) { - printk(KERN_DEBUG "%s: vmxnet_open() irq %d lp %p.\n", - dev->name, dev->irq, lp); - } - - if (vmxnet_init_ring(dev)) { - return -ENOMEM; - } - - ddPA = VMXNET_GET_LO_ADDR(lp->ddPA); - outl(ddPA, ioaddr + VMXNET_INIT_ADDR); - outl(lp->dd->length, ioaddr + VMXNET_INIT_LENGTH); - -#ifdef VMXNET_DO_ZERO_COPY - if (lp->partialHeaderCopyEnabled) { - outl(VMXNET_CMD_PIN_TX_BUFFERS, ioaddr + VMXNET_COMMAND_ADDR); - } - // Pin the Tx buffers if partial header copy is enabled -#endif - - lp->dd->txStopped = FALSE; - netif_start_queue(dev); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) - dev->interrupt = 0; - dev->start = 1; -#endif - - lp->devOpen = TRUE; - - COMPAT_NETDEV_MOD_INC_USE_COUNT; - - return 0; -} - -#ifdef VMXNET_DO_ZERO_COPY -/* - *----------------------------------------------------------------------------- - * - * vmxnet_unmap_buf -- - * - * Unmap the PAs of the tx entry that we pinned for DMA. - * - * Results: - * None. - * - * Side effects: - * None - *----------------------------------------------------------------------------- - */ - -void -vmxnet_unmap_buf(struct sk_buff *skb, - struct Vmxnet2_TxBuf *tb, - Vmxnet2_TxRingEntry *xre, - struct pci_dev *pdev) -{ - int sgIdx; - - // unmap the mapping for skb->data if needed - if (tb->sgForLinear >= 0) { - pci_unmap_single(pdev, - VMXNET_GET_DMA_ADDR(xre->sg.sg[(int)tb->sgForLinear]), - xre->sg.sg[(int)tb->sgForLinear].length, - PCI_DMA_TODEVICE); - VMXNET_LOG("vmxnet_unmap_buf: sg[%d] (%uB)\n", (int)tb->sgForLinear, - xre->sg.sg[(int)tb->sgForLinear].length); - } - - // unmap the mapping for skb->frags[] - for (sgIdx = tb->firstSgForFrag; sgIdx < xre->sg.length; sgIdx++) { - pci_unmap_page(pdev, - VMXNET_GET_DMA_ADDR(xre->sg.sg[sgIdx]), - xre->sg.sg[sgIdx].length, - PCI_DMA_TODEVICE); - VMXNET_LOG("vmxnet_unmap_buf: sg[%d] (%uB)\n", sgIdx, - xre->sg.sg[sgIdx].length); - } -} - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_map_pkt -- - * - * Map the buffers/pages that we need for DMA and populate the SG. - * - * "offset" indicates the position inside the pkt where mapping should start. - * "startSgIdx" indicates the first free sg slot of the first tx entry - * (pointed to by txDriverNext). - * - * The caller should guarantee the first tx has at least one sg slot - * available. The caller should also ensure that enough tx entries are - * available for this pkt. - * - * Results: - * None. - * - * Side effects: - * 1. Ownership of all tx entries used (EXCEPT the 1st one) are updated. - * The only flag set is VMXNET2_TX_MORE if needed. caller is - * responsible to set up other flags after this call returns. - * 2. lp->dd->numTxPending is updated - * 3. txBufInfo corresponding to used tx entries (including the 1st one) - * are updated - * 4. txDriverNext is advanced accordingly - * - *----------------------------------------------------------------------------- - */ - -void -vmxnet_map_pkt(struct sk_buff *skb, - int offset, - struct Vmxnet_Private *lp, - int startSgIdx) -{ - int nextFrag = 0, nextSg = startSgIdx; - struct skb_frag_struct *frag; - Vmxnet2_DriverData *dd = lp->dd; - Vmxnet2_TxRingEntry *xre; - struct Vmxnet2_TxBuf *tb; - dma_addr_t dma; - - VMXNET_ASSERT(startSgIdx < VMXNET2_SG_DEFAULT_LENGTH); - - lp->numTxPending++; - tb = &lp->txBufInfo[dd->txDriverNext]; - xre = &lp->txRing[dd->txDriverNext]; - - if (offset == skb_headlen(skb)) { - tb->sgForLinear = -1; - tb->firstSgForFrag = nextSg; - } else if (offset < skb_headlen(skb)) { - /* we need to map some of the non-frag data. */ - dma = pci_map_single(lp->pdev, - skb->data + offset, - skb_headlen(skb) - offset, - PCI_DMA_TODEVICE); - VMXNET_FILL_SG(xre->sg.sg[nextSg], dma, skb_headlen(skb) - offset); - VMXNET_LOG("vmxnet_map_pkt: txRing[%u].sg[%d] -> data %p offset %u size %u\n", - dd->txDriverNext, nextSg, skb->data, offset, skb_headlen(skb) - offset); - tb->sgForLinear = nextSg++; - tb->firstSgForFrag = nextSg; - } else { - // all non-frag data is copied, skip it - tb->sgForLinear = -1; - tb->firstSgForFrag = nextSg; - - offset -= skb_headlen(skb); - - for ( ; nextFrag < skb_shinfo(skb)->nr_frags; nextFrag++){ - int fragSize; - frag = &skb_shinfo(skb)->frags[nextFrag]; -#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) - fragSize = frag->size; -#else - fragSize = skb_frag_size(frag); -#endif - - // skip those frags that are completely copied - if (offset >= fragSize){ - offset -= fragSize; - } else { - // map the part of the frag that is not copied - dma = pci_map_page(lp->pdev, -#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) - frag->page, -#else - frag->page.p, -#endif - frag->page_offset + offset, - fragSize - offset, - PCI_DMA_TODEVICE); - VMXNET_FILL_SG(xre->sg.sg[nextSg], dma, fragSize - offset); - VMXNET_LOG("vmxnet_map_tx: txRing[%u].sg[%d] -> frag[%d]+%u (%uB)\n", - dd->txDriverNext, nextSg, nextFrag, offset, fragSize - offset); - nextSg++; - nextFrag++; - - break; - } - } - } - - // map the remaining frags, we might need to use additional tx entries - for ( ; nextFrag < skb_shinfo(skb)->nr_frags; nextFrag++) { - int fragSize; - frag = &skb_shinfo(skb)->frags[nextFrag]; -#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) - fragSize = frag->size; -#else - fragSize = skb_frag_size(frag); -#endif - - dma = pci_map_page(lp->pdev, -#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) - frag->page, -#else - frag->page.p, -#endif - frag->page_offset, - fragSize, - PCI_DMA_TODEVICE); - - if (nextSg == VMXNET2_SG_DEFAULT_LENGTH) { - xre->flags = VMXNET2_TX_MORE; - xre->sg.length = VMXNET2_SG_DEFAULT_LENGTH; - tb->skb = skb; - tb->eop = 0; - - // move to the next tx entry - VMXNET_INC(dd->txDriverNext, dd->txRingLength); - xre = &lp->txRing[dd->txDriverNext]; - tb = &lp->txBufInfo[dd->txDriverNext]; - - // the new tx entry must be available - VMXNET_ASSERT(xre->ownership == VMXNET2_OWNERSHIP_DRIVER && tb->skb == NULL); - - /* - * we change it even before the sg are populated but this is - * fine, because the first tx entry's ownership is not - * changed yet - */ - xre->ownership = VMXNET2_OWNERSHIP_NIC; - tb->sgForLinear = -1; - tb->firstSgForFrag = 0; - lp->numTxPending ++; - - nextSg = 0; - } - VMXNET_FILL_SG(xre->sg.sg[nextSg], dma, fragSize); - VMXNET_LOG("vmxnet_map_tx: txRing[%u].sg[%d] -> frag[%d] (%uB)\n", - dd->txDriverNext, nextSg, nextFrag, fragSize); - nextSg++; - } - - // setup the last tx entry - xre->flags = 0; - xre->sg.length = nextSg; - tb->skb = skb; - tb->eop = 1; - - VMXNET_ASSERT(nextSg <= VMXNET2_SG_DEFAULT_LENGTH); - VMXNET_INC(dd->txDriverNext, dd->txRingLength); -} -#endif - -/* - *----------------------------------------------------------------------------- - * - * check_tx_queue -- - * - * Loop through the tx ring looking for completed transmits. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ -static void -check_tx_queue(struct net_device *dev) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - Vmxnet2_DriverData *dd = lp->dd; - int completed = 0; - - /* - * The .suspend handler frees driver data, so we need this check. - */ - while (dd) { - Vmxnet2_TxRingEntry *xre = &lp->txRing[dd->txDriverCur]; - struct sk_buff *skb = lp->txBufInfo[dd->txDriverCur].skb; - - if (xre->ownership != VMXNET2_OWNERSHIP_DRIVER || skb == NULL) { - break; - } -#ifdef VMXNET_DO_ZERO_COPY - if (lp->zeroCopyTx) { - VMXNET_LOG("unmap txRing[%u]\n", dd->txDriverCur); - vmxnet_unmap_buf(skb, &lp->txBufInfo[dd->txDriverCur], xre, lp->pdev); - } else -#endif - { - compat_pci_unmap_single(lp->pdev, xre->sg.sg[0].addrLow, - xre->sg.sg[0].length, - PCI_DMA_TODEVICE); - } - if (lp->txBufInfo[dd->txDriverCur].eop) { - compat_dev_kfree_skb_irq(skb, FREE_WRITE); - } - lp->txBufInfo[dd->txDriverCur].skb = NULL; - - completed ++; - - VMXNET_INC(dd->txDriverCur, dd->txRingLength); - } - - if (completed){ - lp->numTxPending -= completed; - - // XXX conditionally wake up the queue based on the # of freed entries - if (netif_queue_stopped(dev)) { - netif_wake_queue(dev); - dd->txStopped = FALSE; - } - } -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_tx -- - * - * Network device hard_start_xmit helper routine. This is called by - * the drivers hard_start_xmit routine when it wants to send a packet. - * - * Results: - * VMXNET_CALL_TRANSMIT: The driver should ask the virtual NIC to - * transmit a packet. - * VMXNET_DEFER_TRANSMIT: This transmit is deferred because of - * transmit clustering. - * VMXNET_STOP_TRANSMIT: We ran out of queue space so the caller - * should stop transmitting. - * - * Side effects: - * The drivers tx ring may get modified. - * - *----------------------------------------------------------------------------- - */ -Vmxnet_TxStatus -vmxnet_tx(struct sk_buff *skb, struct net_device *dev) -{ - Vmxnet_TxStatus status = VMXNET_DEFER_TRANSMIT; - struct Vmxnet_Private *lp = netdev_priv(dev); - Vmxnet2_DriverData *dd = lp->dd; - unsigned long flags; - Vmxnet2_TxRingEntry *xre; -#ifdef VMXNET_DO_TSO - int mss; -#endif - - /* - * The .suspend handler frees driver data, so we need this check. - */ - if (UNLIKELY(!dd)) { - return VMXNET_STOP_TRANSMIT; - } - - xre = &lp->txRing[dd->txDriverNext]; - -#ifdef VMXNET_DO_ZERO_COPY - if (lp->zeroCopyTx) { - int txEntries, sgCount; - unsigned int headerSize; - - /* conservatively estimate the # of tx entries needed in the worse case */ - sgCount = (lp->partialHeaderCopyEnabled ? 2 : 1) + skb_shinfo(skb)->nr_frags; - txEntries = (sgCount + VMXNET2_SG_DEFAULT_LENGTH - 1) / VMXNET2_SG_DEFAULT_LENGTH; - - if (UNLIKELY(!lp->chainTx && txEntries > 1)) { - /* - * rare case, no tx desc chaining support but the pkt need more than 1 - * tx entry, linearize it - */ - if (compat_skb_linearize(skb) != 0) { - VMXNET_LOG("vmxnet_tx: skb_linearize failed\n"); - compat_dev_kfree_skb(skb, FREE_WRITE); - return VMXNET_DEFER_TRANSMIT; - } - - txEntries = 1; - } - - VMXNET_LOG("\n%d(%d) bytes, %d frags, %d tx entries\n", skb->len, - skb_headlen(skb), skb_shinfo(skb)->nr_frags, txEntries); - - spin_lock_irqsave(&lp->txLock, flags); - - /* check for the availability of tx ring entries */ - if (dd->txRingLength - lp->numTxPending < txEntries) { - dd->txStopped = TRUE; - netif_stop_queue(dev); - check_tx_queue(dev); - - spin_unlock_irqrestore(&lp->txLock, flags); - VMXNET_LOG("queue stopped\n"); - return VMXNET_STOP_TRANSMIT; - } - - /* copy protocol headers if needed */ - if (LIKELY(lp->partialHeaderCopyEnabled)) { - unsigned int pos = dd->txDriverNext * dd->txPktMaxSize; - char *header = lp->txBufferStart + pos; - - /* figure out the protocol and header sizes */ - - /* PR 171928 - * compat_skb_ip_header isn't updated in rhel5 for - * vlan tagging. using these macros causes incorrect - * computation of the headerSize - */ - headerSize = ETHERNET_HEADER_SIZE; - if (UNLIKELY((skb_headlen(skb) < headerSize))) { - - if (skb_is_nonlinear(skb)) { - compat_skb_linearize(skb); - } - /* - * drop here if we don't have a complete ETH header for delivery - */ - if (skb_headlen(skb) < headerSize) { - compat_dev_kfree_skb(skb, FREE_WRITE); - spin_unlock_irqrestore(&lp->txLock, flags); - return VMXNET_DEFER_TRANSMIT; - } - } - if (UNLIKELY(*(uint16*)(skb->data + ETH_FRAME_TYPE_LOCATION) == - ETH_TYPE_VLAN_TAG)) { - headerSize += VLAN_TAG_LENGTH; - if (UNLIKELY(skb_headlen(skb) < headerSize)) { - - if (skb_is_nonlinear(skb)) { - compat_skb_linearize(skb); - } - /* - * drop here if we don't have a ETH header and a complete VLAN tag - */ - if (skb_headlen(skb) < headerSize) { - compat_dev_kfree_skb(skb, FREE_WRITE); - spin_unlock_irqrestore(&lp->txLock, flags); - return VMXNET_DEFER_TRANSMIT; - } - } - } - if (LIKELY(PKT_OF_IPV4(skb))){ - // PR 171928 -- compat_skb_ip_header broken with vconfig - // please do not rewrite using compat_skb_ip_header - struct iphdr *ipHdr = (struct iphdr *)(skb->data + headerSize); - - if (UNLIKELY(skb_headlen(skb) < headerSize + sizeof(*ipHdr))) { - - if (skb_is_nonlinear(skb)) { - compat_skb_linearize(skb); - } - } - if (LIKELY(skb_headlen(skb) > headerSize + sizeof(*ipHdr)) && - (LIKELY(ipHdr->version == 4))) { - headerSize += ipHdr->ihl << 2; - if (LIKELY(ipHdr->protocol == IPPROTO_TCP)) { - /* - * tcp traffic, copy all protocol headers - * refrain from using compat_skb macros PR 171928 - */ - struct tcphdr *tcpHdr = (struct tcphdr *) - (skb->data + headerSize); - /* - * tcp->doff is near the end of the tcpHdr, use the - * entire struct as the required size - */ - if (skb->len < headerSize + sizeof(*tcpHdr)) { - compat_dev_kfree_skb(skb, FREE_WRITE); - spin_unlock_irqrestore(&lp->txLock, flags); - return VMXNET_DEFER_TRANSMIT; - } - if (skb_headlen(skb) < (headerSize + sizeof(*tcpHdr))) { - /* - * linearized portion of the skb doesn't have a tcp header - */ - compat_skb_linearize(skb); - } - headerSize += tcpHdr->doff << 2; - } - } - } - - if (skb_copy_bits(skb, 0, header, headerSize) != 0) { - compat_dev_kfree_skb(skb, FREE_WRITE); - spin_unlock_irqrestore(&lp->txLock, flags); - return VMXNET_DEFER_TRANSMIT; - } - - xre->sg.sg[0].addrLow = dd->txBufferPhysStart + pos; - xre->sg.sg[0].addrHi = 0; - xre->sg.sg[0].length = headerSize; - vmxnet_map_pkt(skb, headerSize, lp, 1); - } else { - headerSize = 0; - vmxnet_map_pkt(skb, 0, lp, 0); - } - -#ifdef VMXNET_DO_TSO - mss = VMXNET_SKB_MSS(skb); - if (mss) { - xre->flags |= VMXNET2_TX_TSO; - xre->tsoMss = mss; - dd->txNumDeferred += ((skb->len - headerSize) + mss - 1) / mss; - } else -#endif - { - dd->txNumDeferred++; - } - } else /* zero copy not enabled */ -#endif - { - struct Vmxnet2_TxBuf *tb; - dma_addr_t dmaAddr; - - spin_lock_irqsave(&lp->txLock, flags); - - if (lp->txBufInfo[dd->txDriverNext].skb != NULL) { - dd->txStopped = TRUE; - netif_stop_queue(dev); - check_tx_queue(dev); - - spin_unlock_irqrestore(&lp->txLock, flags); - return VMXNET_STOP_TRANSMIT; - } - - lp->numTxPending ++; - - dmaAddr = compat_pci_map_single(lp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - VMXNET_FILL_SG(xre->sg.sg[0], dmaAddr, skb->len); - xre->sg.length = 1; - xre->flags = 0; - - tb = &lp->txBufInfo[dd->txDriverNext]; - tb->skb = skb; - tb->sgForLinear = -1; - tb->firstSgForFrag = -1; - tb->eop = 1; - - VMXNET_INC(dd->txDriverNext, dd->txRingLength); - dd->txNumDeferred++; - dd->stats.copyTransmits++; - } - - /* at this point, xre must point to the 1st tx entry for the pkt */ - if (skb->ip_summed == VM_TX_CHECKSUM_PARTIAL && - ((dev->features & NETIF_F_HW_CSUM) != 0)) { - xre->flags |= VMXNET2_TX_HW_XSUM | VMXNET2_TX_CAN_KEEP; - } else { - xre->flags |= VMXNET2_TX_CAN_KEEP; - } - if (lp->numTxPending > dd->txRingLength - 5) { - xre->flags |= VMXNET2_TX_RING_LOW; - status = VMXNET_CALL_TRANSMIT; - } - - wmb(); - xre->ownership = VMXNET2_OWNERSHIP_NIC; - - if (dd->txNumDeferred >= dd->txClusterLength) { - dd->txNumDeferred = 0; - status = VMXNET_CALL_TRANSMIT; - } - - dev->trans_start = jiffies; - - lp->stats.tx_packets++; - dd->stats.pktsTransmitted++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - lp->stats.tx_bytes += skb->len; -#endif - - if (lp->numTxPending > dd->stats.maxTxsPending) { - dd->stats.maxTxsPending = lp->numTxPending; - } - - check_tx_queue(dev); - - spin_unlock_irqrestore(&lp->txLock, flags); - - return status; -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_start_tx -- - * - * Network device hard_start_xmit routine. Called by Linux when it has - * a packet for us to transmit. - * - * Results: - * 0 on success; 1 if no resources. - * - * Side effects: - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_start_tx(struct sk_buff *skb, struct net_device *dev) -{ - int retVal = 0; - Vmxnet_TxStatus xs = vmxnet_tx(skb, dev); - switch (xs) { - case VMXNET_CALL_TRANSMIT: - inl(dev->base_addr + VMXNET_TX_ADDR); - break; - case VMXNET_DEFER_TRANSMIT: - break; - case VMXNET_STOP_TRANSMIT: - retVal = 1; - break; - } - - return retVal; -} - -#ifdef VMXNET_DO_ZERO_COPY -/* - *---------------------------------------------------------------------------- - * - * vmxnet_drop_frags -- - * - * return the entries in the 2nd ring to the hw. The entries returned are - * from rxDriverNext2 to the entry with VMXNET2_RX_FRAG_EOP set. - * - * Result: - * None - * - * Side-effects: - * None - * - *---------------------------------------------------------------------------- - */ -static void -vmxnet_drop_frags(Vmxnet_Private *lp) -{ - Vmxnet2_DriverData *dd = lp->dd; - Vmxnet2_RxRingEntry *rre2; - uint16 flags; - - do { - rre2 = &lp->rxRing2[dd->rxDriverNext2]; - flags = rre2->flags; - VMXNET_ASSERT(rre2->ownership == VMXNET2_OWNERSHIP_DRIVER_FRAG); - - rre2->ownership = VMXNET2_OWNERSHIP_NIC_FRAG; - VMXNET_INC(dd->rxDriverNext2, dd->rxRingLength2); - } while(!(flags & VMXNET2_RX_FRAG_EOP)); -} - -/* - *---------------------------------------------------------------------------- - * - * vmxnet_rx_frags -- - * - * get data from the 2nd rx ring and append the frags to the skb. Multiple - * rx entries in the 2nd rx ring are processed until the one with - * VMXNET2_RX_FRAG_EOP set. - * - * Result: - * 0 on success - * -1 on error - * - * Side-effects: - * frags are appended to skb. related fields in skb are updated - * - *---------------------------------------------------------------------------- - */ -static int -vmxnet_rx_frags(Vmxnet_Private *lp, struct sk_buff *skb) -{ - Vmxnet2_DriverData *dd = lp->dd; - struct pci_dev *pdev = lp->pdev; - struct page *newPage; - int numFrags = 0; - Vmxnet2_RxRingEntry *rre2; - uint16 flags; -#ifdef VMXNET_DEBUG - uint32 firstFrag = dd->rxDriverNext2; -#endif - - do { - rre2 = &lp->rxRing2[dd->rxDriverNext2]; - flags = rre2->flags; - VMXNET_ASSERT(rre2->ownership == VMXNET2_OWNERSHIP_DRIVER_FRAG); - - if (rre2->actualLength > 0) { - newPage = alloc_page(GFP_ATOMIC); - if (UNLIKELY(newPage == NULL)) { - skb_shinfo(skb)->nr_frags = numFrags; - skb->len += skb->data_len; - skb->truesize += PAGE_SIZE; - - compat_dev_kfree_skb(skb, FREE_WRITE); - - vmxnet_drop_frags(lp); - - return -1; - } - - pci_unmap_page(pdev, rre2->paddr, PAGE_SIZE, PCI_DMA_FROMDEVICE); -#if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) - skb_shinfo(skb)->frags[numFrags].page = lp->rxPages[dd->rxDriverNext2]; -#else - __skb_frag_set_page(&skb_shinfo(skb)->frags[numFrags], - lp->rxPages[dd->rxDriverNext2]); -#endif - skb_shinfo(skb)->frags[numFrags].page_offset = 0; - skb_shinfo(skb)->frags[numFrags].size = rre2->actualLength; - skb->data_len += rre2->actualLength; - skb->truesize += PAGE_SIZE; - numFrags++; - - /* refill the buffer */ - lp->rxPages[dd->rxDriverNext2] = newPage; - rre2->paddr = pci_map_page(pdev, newPage, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); - rre2->bufferLength = PAGE_SIZE; - rre2->actualLength = 0; - wmb(); - } - - rre2->ownership = VMXNET2_OWNERSHIP_NIC_FRAG; - VMXNET_INC(dd->rxDriverNext2, dd->rxRingLength2); - } while (!(flags & VMXNET2_RX_FRAG_EOP)); - - VMXNET_ASSERT(numFrags > 0); - skb_shinfo(skb)->nr_frags = numFrags; - skb->len += skb->data_len; - skb->truesize += PAGE_SIZE; - VMXNET_LOG("vmxnet_rx: %dB from rxRing[%d](%dB)+rxRing2[%d, %d)(%dB)\n", - skb->len, dd->rxDriverNext, skb_headlen(skb), - firstFrag, dd->rxDriverNext2, skb->data_len); - return 0; -} -#endif - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_rx -- - * - * Receive a packet. - * - * Results: - * 0 - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_rx(struct net_device *dev) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - Vmxnet2_DriverData *dd = lp->dd; - - if (!lp->devOpen || !dd) { - return 0; - } - - while (1) { - struct sk_buff *skb, *newSkb; - Vmxnet2_RxRingEntry *rre; - - rre = &lp->rxRing[dd->rxDriverNext]; - if (rre->ownership != VMXNET2_OWNERSHIP_DRIVER) { - break; - } - - if (UNLIKELY(rre->actualLength == 0)) { -#ifdef VMXNET_DO_ZERO_COPY - if (rre->flags & VMXNET2_RX_WITH_FRAG) { - vmxnet_drop_frags(lp); - } -#endif - lp->stats.rx_errors++; - goto next_pkt; - } - - skb = lp->rxSkbuff[dd->rxDriverNext]; - - /* refill the rx ring */ - newSkb = dev_alloc_skb(PKT_BUF_SZ + COMPAT_NET_IP_ALIGN); - if (UNLIKELY(newSkb == NULL)) { - printk(KERN_DEBUG "%s: Memory squeeze, dropping packet.\n", dev->name); -#ifdef VMXNET_DO_ZERO_COPY - if (rre->flags & VMXNET2_RX_WITH_FRAG) { - vmxnet_drop_frags(lp); - } -#endif - lp->stats.rx_errors++; - goto next_pkt; - } - skb_reserve(newSkb, COMPAT_NET_IP_ALIGN); - - compat_pci_unmap_single(lp->pdev, rre->paddr, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - skb_put(skb, rre->actualLength); - - lp->rxSkbuff[dd->rxDriverNext] = newSkb; - rre->paddr = compat_pci_map_single(lp->pdev, newSkb->data, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - rre->bufferLength = PKT_BUF_SZ; - - -#ifdef VMXNET_DO_ZERO_COPY - if (rre->flags & VMXNET2_RX_WITH_FRAG) { - if (vmxnet_rx_frags(lp, skb) < 0) { - lp->stats.rx_errors++; - goto next_pkt; - } - } else -#endif - { - VMXNET_LOG("vmxnet_rx: %dB from rxRing[%d]\n", skb->len, dd->rxDriverNext); - } - - if (skb->len < (ETH_MIN_FRAME_LEN - 4)) { - /* - * Ethernet header vlan tags are 4 bytes. Some vendors generate - * ETH_MIN_FRAME_LEN frames including vlan tags. When vlan tag - * is stripped, such frames become ETH_MIN_FRAME_LEN - 4. (PR106153) - */ - if (skb->len != 0) { - printk(KERN_DEBUG "%s: Runt pkt (%d bytes) entry %d!\n", dev->name, - skb->len, dd->rxDriverNext); - } - lp->stats.rx_errors++; - } else { - if (rre->flags & VMXNET2_RX_HW_XSUM_OK) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - - skb->dev = dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - lp->stats.rx_bytes += skb->len; -#endif - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - lp->stats.rx_packets++; - dd->stats.pktsReceived++; - } - -next_pkt: - rre->ownership = VMXNET2_OWNERSHIP_NIC; - VMXNET_INC(dd->rxDriverNext, dd->rxRingLength); - } - - return 0; -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_interrupt -- - * - * Interrupt handler. Calls vmxnet_rx to receive a packet. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static compat_irqreturn_t -vmxnet_interrupt(int irq, void *dev_id, struct pt_regs * regs) -#else -static compat_irqreturn_t -vmxnet_interrupt(int irq, void *dev_id) -#endif -{ - struct net_device *dev = (struct net_device *)dev_id; - struct Vmxnet_Private *lp; - Vmxnet2_DriverData *dd; - - if (dev == NULL) { - printk (KERN_DEBUG "vmxnet_interrupt(): irq %d for unknown device.\n", irq); - return COMPAT_IRQ_NONE; - } - - - lp = netdev_priv(dev); - outl(VMXNET_CMD_INTR_ACK, dev->base_addr + VMXNET_COMMAND_ADDR); - - dd = lp->dd; - if (LIKELY(dd)) { - dd->stats.interrupts++; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) - if (dev->interrupt) { - printk(KERN_DEBUG "%s: Re-entering the interrupt handler.\n", dev->name); - } - dev->interrupt = 1; -#endif - - vmxnet_rx(dev); - - if (lp->numTxPending > 0) { - spin_lock(&lp->txLock); - check_tx_queue(dev); - spin_unlock(&lp->txLock); - } - - if (netif_queue_stopped(dev) && dd && !dd->txStopped) { - netif_wake_queue(dev); - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) - dev->interrupt = 0; -#endif - return COMPAT_IRQ_HANDLED; -} - - -#ifdef VMW_HAVE_POLL_CONTROLLER -/* - *----------------------------------------------------------------------------- - * - * vmxnet_netpoll -- - * - * Poll network controller. We reuse hardware interrupt for this. - * - * Results: - * None. - * - * Side effects: - * Packets received/transmitted/whatever. - * - *----------------------------------------------------------------------------- - */ -static void -vmxnet_netpoll(struct net_device *dev) -{ - disable_irq(dev->irq); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) - vmxnet_interrupt(dev->irq, dev, NULL); -#else - vmxnet_interrupt(dev->irq, dev); -#endif - enable_irq(dev->irq); -} -#endif /* VMW_HAVE_POLL_CONTROLLER */ - - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_close -- - * - * Network device stop (close) routine. Called by Linux when the - * interface is brought down. - * - * Results: - * 0 for success (always). - * - * Side effects: - * Flushes pending transmits. Frees IRQs and shared memory area. - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_close(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct Vmxnet_Private *lp = netdev_priv(dev); - int i; - unsigned long flags; - - if (vmxnet_debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard\n", dev->name); - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) - dev->start = 0; -#endif - - netif_stop_queue(dev); - - lp->devOpen = FALSE; - - spin_lock_irqsave(&lp->txLock, flags); - if (lp->numTxPending > 0) { - //Wait absurdly long (2sec) for all the pending packets to be returned. - printk(KERN_DEBUG "vmxnet_close: Pending tx = %d\n", lp->numTxPending); - for (i = 0; i < 200 && lp->numTxPending > 0; i++) { - outl(VMXNET_CMD_CHECK_TX_DONE, dev->base_addr + VMXNET_COMMAND_ADDR); - udelay(10000); - check_tx_queue(dev); - } - - //This can happen when the related vmxnet device is disabled or when - //something's wrong with the pNIC, or even both. - //Will go ahead and free these skb's anyways (possibly dangerous, - //but seems to work in practice) - if (lp->numTxPending > 0) { - printk(KERN_EMERG "vmxnet_close: %s failed to finish all pending tx (%d).\n" - "Is the related vmxnet device disabled?\n" - "This virtual machine may be in an inconsistent state.\n", - dev->name, lp->numTxPending); - lp->numTxPending = 0; - } - } - spin_unlock_irqrestore(&lp->txLock, flags); - - outl(0, ioaddr + VMXNET_INIT_ADDR); - - free_irq(dev->irq, dev); - - for (i = 0; lp->dd && i < lp->dd->txRingLength; i++) { - if (lp->txBufInfo[i].skb != NULL && lp->txBufInfo[i].eop) { - compat_dev_kfree_skb(lp->txBufInfo[i].skb, FREE_WRITE); - lp->txBufInfo[i].skb = NULL; - } - } - - for (i = 0; i < lp->numRxBuffers; i++) { - if (lp->rxSkbuff[i] != NULL) { - compat_pci_unmap_single(lp->pdev, lp->rxRing[i].paddr, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - compat_dev_kfree_skb(lp->rxSkbuff[i], FREE_WRITE); - lp->rxSkbuff[i] = NULL; - } - } -#ifdef VMXNET_DO_ZERO_COPY - if (lp->jumboFrame || lp->lpd) { - for (i = 0; i < lp->numRxBuffers2; i++) { - if (lp->rxPages[i] != NULL) { - pci_unmap_page(lp->pdev, lp->rxRing2[i].paddr, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - put_page(lp->rxPages[i]); - lp->rxPages[i] = NULL; - } - } - } -#endif - - COMPAT_NETDEV_MOD_DEC_USE_COUNT; - - return 0; -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_load_multicast -- - * - * Load the multicast filter. - * - * Results: - * return number of entries used to compute LADRF - * - * Side effects: - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_load_multicast (struct net_device *dev) -{ - struct Vmxnet_Private *lp = netdev_priv(dev); - volatile u16 *mcast_table = (u16 *)lp->dd->LADRF; -#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 j, bit, byte; - u32 crc, poly = CRC_POLYNOMIAL_LE; - - /* clear the multicast filter */ - lp->dd->LADRF[0] = 0; - lp->dd->LADRF[1] = 0; - - /* Add addresses */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34) - netdev_for_each_mc_addr(dmi, dev) { - addrs = dmi->addr; -#else - for (i = 0; i < dev->mc_count; i++){ - addrs = dmi->dmi_addr; - dmi = dmi->next; -#endif - - /* multicast address? */ - if (!(*addrs & 1)) - continue; - - crc = 0xffffffff; - for (byte = 0; byte < 6; byte++) { - for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { - int test; - - test = ((bit ^ crc) & 0x01); - crc >>= 1; - - if (test) { - crc = crc ^ poly; - } - } - } - - crc = crc >> 26; - mcast_table [crc >> 4] |= 1 << (crc & 0xf); - } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34) - return netdev_mc_count(dev); -#else - return i; -#endif -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_set_multicast_list -- - * - * Network device set_multicast_list routine. Called by Linux when the - * set of addresses to listen to changes, including both the multicast - * list and the broadcast, promiscuous, multicast, and allmulti flags. - * - * Results: - * None. - * - * Side effects: - * Informs lower layer of the changes. - * - *----------------------------------------------------------------------------- - */ -static void -vmxnet_set_multicast_list(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct Vmxnet_Private *lp = netdev_priv(dev); - - /* - * The .suspend handler frees driver data, so we need this check. - */ - if (UNLIKELY(!lp->dd)) { - return; - } - - lp->dd->ifflags = ~(VMXNET_IFF_PROMISC - |VMXNET_IFF_BROADCAST - |VMXNET_IFF_MULTICAST); - - if (dev->flags & IFF_PROMISC) { - printk(KERN_DEBUG "%s: Promiscuous mode enabled.\n", dev->name); - lp->dd->ifflags |= VMXNET_IFF_PROMISC; - } - if (dev->flags & IFF_BROADCAST) { - lp->dd->ifflags |= VMXNET_IFF_BROADCAST; - } - - if (dev->flags & IFF_ALLMULTI) { - lp->dd->LADRF[0] = 0xffffffff; - lp->dd->LADRF[1] = 0xffffffff; - lp->dd->ifflags |= VMXNET_IFF_MULTICAST; - } else { - if (vmxnet_load_multicast(dev)) { - lp->dd->ifflags |= VMXNET_IFF_MULTICAST; - } - } - outl(VMXNET_CMD_UPDATE_LADRF, ioaddr + VMXNET_COMMAND_ADDR); - - outl(VMXNET_CMD_UPDATE_IFF, ioaddr + VMXNET_COMMAND_ADDR); -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_set_mac_address -- - * - * Network device set_mac_address routine. Called by Linux when someone - * asks to change the interface's MAC address. - * - * Results: - * 0 for success; -EBUSY if interface is up. - * - * Side effects: - * - *----------------------------------------------------------------------------- - */ -static int -vmxnet_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr=p; - unsigned int ioaddr = dev->base_addr; - int i; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - - for (i = 0; i < ETH_ALEN; i++) { - outb(addr->sa_data[i], ioaddr + VMXNET_MAC_ADDR + i); - } - return 0; -} - -/* - *----------------------------------------------------------------------------- - * - * vmxnet_get_stats -- - * - * Network device get_stats routine. Called by Linux when interface - * statistics are requested. - * - * Results: - * Returns a pointer to our private stats structure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ -static struct net_device_stats * -vmxnet_get_stats(struct net_device *dev) -{ - Vmxnet_Private *lp = netdev_priv(dev); - - return &lp->stats; -} - -module_init(vmxnet_init); -module_exit(vmxnet_exit); -MODULE_DEVICE_TABLE(pci, vmxnet_chips); - -/* Module information. */ -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Virtual Ethernet driver"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(VMXNET_DRIVER_VERSION_STRING); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); diff --git a/open-vm-tools/modules/linux/vmxnet/vmxnetInt.h b/open-vm-tools/modules/linux/vmxnet/vmxnetInt.h deleted file mode 100644 index 542232aab..000000000 --- a/open-vm-tools/modules/linux/vmxnet/vmxnetInt.h +++ /dev/null @@ -1,110 +0,0 @@ -/********************************************************* - * Copyright (C) 1998 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 - * - *********************************************************/ - -#ifndef __VMXNETINT_H__ -#define __VMXNETINT_H__ - -#define INCLUDE_ALLOW_MODULE -#include "includeCheck.h" - -#define VMXNET_CHIP_NAME "vmxnet ether" - -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - -#define PKT_BUF_SZ 1536 -#define VMXNET_MIN_MTU (ETH_MIN_FRAME_LEN - 14) -#define VMXNET_MAX_MTU (16 * 1024 - 18) - -typedef enum Vmxnet_TxStatus { - VMXNET_CALL_TRANSMIT, - VMXNET_DEFER_TRANSMIT, - VMXNET_STOP_TRANSMIT -} Vmxnet_TxStatus; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)) -# define MODULE_PARM(var, type) -# define net_device_stats enet_statistics -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)) -# define le16_to_cpu(x) ((__u16)(x)) -# define le32_to_cpu(x) ((__u32)(x)) -#endif - -#if defined(BUG_ON) -#define VMXNET_ASSERT(cond) BUG_ON(!(cond)) -#else -#define VMXNET_ASSERT(cond) -#endif -#define ASSERT(cond) VMXNET_ASSERT(cond) - -struct Vmxnet2_TxBuf { - struct sk_buff *skb; - char sgForLinear; /* the sg entry mapping the linear part - * of the skb, -1 means this tx entry only - * mapps the frags of the skb - */ - char firstSgForFrag; /* the first sg entry mapping the frags */ - Bool eop; -}; - -/* - * Private data area, pointed to by priv field of our struct net_device. - * dd field is shared with the lower layer. - */ -typedef struct Vmxnet_Private { - Vmxnet2_DriverData *dd; - dma_addr_t ddPA; - size_t ddSize; - const char *name; - struct net_device_stats stats; - struct sk_buff *rxSkbuff[ENHANCED_VMXNET2_MAX_NUM_RX_BUFFERS]; - struct page *rxPages[VMXNET2_MAX_NUM_RX_BUFFERS2]; - struct Vmxnet2_TxBuf txBufInfo[VMXNET2_MAX_NUM_TX_BUFFERS_TSO]; - spinlock_t txLock; - int numTxPending; - unsigned int numRxBuffers; - unsigned int numRxBuffers2; - unsigned int numTxBuffers; - Vmxnet2_RxRingEntry *rxRing; - Vmxnet2_RxRingEntry *rxRing2; - Vmxnet2_TxRingEntry *txRing; - - Bool devOpen; - uint32 portID; - - uint32 capabilities; - uint32 features; - - Bool zeroCopyTx; - Bool partialHeaderCopyEnabled; - Bool tso; - Bool chainTx; - Bool chainRx; - Bool jumboFrame; - Bool lpd; - - Bool morphed; // Indicates whether adapter is morphed - size_t txBufferSize; - char *txBufferStart; - dma_addr_t txBufferPA; - struct pci_dev *pdev; - struct timer_list linkCheckTimer; -} Vmxnet_Private; - -#endif /* __VMXNETINT_H__ */ diff --git a/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h b/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h deleted file mode 100644 index fe2ad5385..000000000 --- a/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmxnet_version.h -- - * - * Version definitions for the Linux vmxnet driver. - */ - -#ifndef _VMXNET_VERSION_H_ -#define _VMXNET_VERSION_H_ - -#define VMXNET_DRIVER_VERSION 2.1.0.0 -#define VMXNET_DRIVER_VERSION_COMMAS 2,1,0,0 -#define VMXNET_DRIVER_VERSION_STRING "2.1.0.0" - -#endif /* _VMXNET_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vsock/COPYING b/open-vm-tools/modules/linux/vsock/COPYING deleted file mode 100644 index d511905c1..000000000 --- a/open-vm-tools/modules/linux/vsock/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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; either version 2 of the License, or - (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/open-vm-tools/modules/linux/vsock/Makefile b/open-vm-tools/modules/linux/vsock/Makefile deleted file mode 100644 index 565451abe..000000000 --- a/open-vm-tools/modules/linux/vsock/Makefile +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 1998-2016 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 -# -########################################################## - -#### -#### VMware kernel module Makefile to be distributed externally -#### - -#### -#### SRCROOT _must_ be a relative path. -#### -SRCROOT = . - -# -# open-vm-tools doesn't replicate shared source files for different modules; -# instead, files are kept in shared locations. So define a few useful macros -# to be able to handle both cases cleanly. -# -INCLUDE := -ifdef OVT_SOURCE_DIR -AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf -VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1) -INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared -INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include -else -AUTOCONF_DIR := $(SRCROOT)/shared/autoconf -INCLUDE += -I$(SRCROOT)/shared -endif - - -VM_UNAME = $(shell uname -r) - -# Header directory for the running kernel -ifdef LINUXINCLUDE -HEADER_DIR = $(LINUXINCLUDE) -else -HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include -endif - -BUILD_DIR = $(HEADER_DIR)/.. - -DRIVER := vsock -PRODUCT := tools-source - -# Grep program -GREP = /bin/grep - -vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) -vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi) - -ifndef VM_KBUILD -VM_KBUILD := no -ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes) -VM_KBUILD := yes -endif -export VM_KBUILD -endif - -ifndef VM_KBUILD_SHOWN -ifeq ($(VM_KBUILD), no) -VM_DUMMY := $(shell echo >&2 "Using standalone build system.") -else -VM_DUMMY := $(shell echo >&2 "Using kernel build system.") -endif -VM_KBUILD_SHOWN := yes -export VM_KBUILD_SHOWN -endif - -ifneq ($(VM_KBUILD), no) - -VMCCVER := $(shell $(CC) -dumpversion) - -# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles... -ifeq ($(VERSION),) - -DRIVER_KO := $(DRIVER).ko - -.PHONY: $(DRIVER_KO) - -auto-build: $(DRIVER_KO) - cp -f $< $(SRCROOT)/../$(DRIVER).o - -# $(DRIVER_KO) is a phony target, so compare file times explicitly -$(DRIVER): $(DRIVER_KO) - if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi - -# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler -VM_CCVER := $(VMCCVER) -export VM_CCVER -VM_CC := $(CC) -export VM_CC - -MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES)) - -# -# Define a setup target that gets built before the actual driver. -# This target may not be used at all, but if it is then it will be defined -# in Makefile.kernel -# -prebuild:: ; -postbuild:: ; - -$(DRIVER_KO): prebuild - $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) modules - $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \ - MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild -endif - -vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \ - $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \ - -DKBUILD_BASENAME=\"$(DRIVER)\" \ - -Werror -S -o /dev/null -xc $(1) \ - > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi) - -CC_WARNINGS := -Wall -Wstrict-prototypes -CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD -ifdef VMX86_DEVEL -CC_OPTS += -DVMX86_DEVEL -endif -ifdef VMX86_DEBUG -CC_OPTS += -DVMX86_DEBUG -endif - -include $(SRCROOT)/Makefile.kernel - -else - -include $(SRCROOT)/Makefile.normal - -endif - -#.SILENT: diff --git a/open-vm-tools/modules/linux/vsock/Makefile.kernel b/open-vm-tools/modules/linux/vsock/Makefile.kernel deleted file mode 100644 index 5218df2f8..000000000 --- a/open-vm-tools/modules/linux/vsock/Makefile.kernel +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/make -f -########################################################## -# Copyright (C) 2007,2014 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 -# -########################################################## - -vm_product_defines = $(if $(findstring tools,$(1)), -DVMX86_TOOLS,) -CC_OPTS += $(call vm_product_defines, $(PRODUCT)) - -INCLUDE += -I. -INCLUDE += -I$(SRCROOT)/include -INCLUDE += -I$(SRCROOT)/linux -INCLUDE += -I$(SRCROOT)/common - -EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) -EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/netcreate_num_params.c, -DVMW_NETCREATE_KERNARG, ) - - -MODPOST_VMCI_SYMVERS := $(wildcard $(MODULEBUILDDIR)/VMwareVMCIModule.symvers) - -obj-m += $(DRIVER).o - -$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, $(wildcard $(SRCROOT)/linux/*.c))) - -# -# In open-vm-tools, need to compile the common sources from the shared directory. -# -DRIVERLOG := driverLog.o -$(DRIVER)-y += $(DRIVERLOG) - -VSOCK_PATH := $(shell cd $(SRCROOT) && pwd) -ifdef OVT_SOURCE_DIR -DRIVERLOG_PATH := $(OVT_SOURCE_DIR)/modules/linux/shared -else -DRIVERLOG_PATH := $(VSOCK_PATH)/shared -endif - -$(addprefix $(VSOCK_PATH)/,$(DRIVERLOG)): $(VSOCK_PATH)/%.o: $(DRIVERLOG_PATH)/%.c - $(Q)$(rule_cc_o_c) - -clean: - rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ - Module.symvers Module.markers modules.order \ - $(foreach dir,./ linux/ \ - ,$(addprefix $(dir),.*.cmd .*.o.flags *.o))) - -# -# The VSock kernel module uses symbols from the VMCI kernel module. Copy the -# Module.symvers file here so that the Vsock module knows about the VMCI version. This is not done for tar builds because the tools install takes care of it. -# -prebuild:: -ifneq ($(MODULEBUILDDIR),) -ifeq ($(MODPOST_VMCI_SYMVERS),) - $(shell echo >&2 "Building vSockets without VMCI module symbols.") -else - $(shell echo >&2 "Building vSockets with VMCI module symbols.") - cp -f $(MODPOST_VMCI_SYMVERS) $(SRCROOT)/Module.symvers -endif -endif diff --git a/open-vm-tools/modules/linux/vsock/README b/open-vm-tools/modules/linux/vsock/README deleted file mode 100644 index be731f690..000000000 --- a/open-vm-tools/modules/linux/vsock/README +++ /dev/null @@ -1,17 +0,0 @@ -This files in this directory and its subdirectories are the kernel module -for the VMware VSockets module. In order to build, make certain the Makefile -is correct and then just type - - make - -from this directory. A copy of the module will be left in - - driver-/vsock- - -(e.g. driver-up-2.4.20/vsock-up-2.4.20) for 2.4 series kernels and in - - ../vsock.o - -for 2.6 series kernels. - -If you have any problems or questions, send mail to support@vmware.com diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c deleted file mode 100644 index c068a1a7e..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c +++ /dev/null @@ -1,5494 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2015 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 - * - *********************************************************/ - -/* - * af_vsock.c -- - * - * Linux socket module for the vSockets protocol family. - */ - - -/* - * Implementation notes: - * - * - There are two kinds of sockets: those created by user action (such as - * calling socket(2)) and those created by incoming connection request - * packets. - * - * - There are two "global" tables, one for bound sockets (sockets that have - * specified an address that they are responsible for) and one for connected - * sockets (sockets that have established a connection with another socket). - * These tables are "global" in that all sockets on the system are placed - * within them. - * - Note, though, that the bound table contains an extra entry for a list of - * unbound sockets and SOCK_DGRAM sockets will always remain in that list. - * The bound table is used solely for lookup of sockets when packets are - * received and that's not necessary for SOCK_DGRAM sockets since we create - * a datagram handle for each and need not perform a lookup. Keeping - * SOCK_DGRAM sockets out of the bound hash buckets will reduce the chance - * of collisions when looking for SOCK_STREAM sockets and prevents us from - * having to check the socket type in the hash table lookups. - * - * - Sockets created by user action will either be "client" sockets that - * initiate a connection or "server" sockets that listen for connections; we - * do not support simultaneous connects (two "client" sockets connecting). - * - * - "Server" sockets are referred to as listener sockets throughout this - * implementation because they are in the SS_LISTEN state. When a connection - * request is received (the second kind of socket mentioned above), we create - * a new socket and refer to it as a pending socket. These pending sockets - * are placed on the pending connection list of the listener socket. When - * future packets are received for the address the listener socket is bound - * to, we check if the source of the packet is from one that has an existing - * pending connection. If it does, we process the packet for the pending - * socket. When that socket reaches the connected state, it is removed from - * the listener socket's pending list and enqueued in the listener socket's - * accept queue. Callers of accept(2) will accept connected sockets from the - * listener socket's accept queue. If the socket cannot be accepted for some - * reason then it is marked rejected. Once the connection is accepted, it is - * owned by the user process and the responsibility for cleanup falls with - * that user process. - * - * - It is possible that these pending sockets will never reach the connected - * state; in fact, we may never receive another packet after the connection - * request. Because of this, we must schedule a cleanup function to run in - * the future, after some amount of time passes where a connection should - * have been established. This function ensures that the socket is off all - * lists so it cannot be retrieved, then drops all references to the socket - * so it is cleaned up (sock_put() -> sk_free() -> our sk_destruct - * implementation). Note this function will also cleanup rejected sockets, - * those that reach the connected state but leave it before they have been - * accepted. - * - * - Sockets created by user action will be cleaned up when the user - * process calls close(2), causing our release implementation to be called. - * Our release implementation will perform some cleanup then drop the - * last reference so our sk_destruct implementation is invoked. Our - * sk_destruct implementation will perform additional cleanup that's common - * for both types of sockets. - * - * - A socket's reference count is what ensures that the structure won't be - * freed. Each entry in a list (such as the "global" bound and connected - * tables and the listener socket's pending list and connected queue) ensures - * a reference. When we defer work until process context and pass a socket - * as our argument, we must ensure the reference count is increased to ensure - * the socket isn't freed before the function is run; the deferred function - * will then drop the reference. - * - */ - -#include "driver-config.h" - -#define EXPORT_SYMTAB -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) -# include -/* Use weak: not all kernels export sys_ioctl for use by modules */ -asmlinkage __attribute__((weak)) long -sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -#endif - -#include "compat_cred.h" -#include "compat_module.h" -#include "compat_kernel.h" -#include "compat_sock.h" -#include "compat_version.h" -#include "compat_workqueue.h" -#include "compat_mutex.h" - -#include "vmware.h" - -#include "vsockCommon.h" -#include "vsockPacket.h" -#include "vsockVmci.h" - -#include "vmci_iocontrols.h" - -#include "af_vsock.h" -#include "stats.h" -#include "util.h" -#include "vsock_version.h" -#include "driverLog.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) -# error "Linux kernels before 2.6.9 are not supported." -#endif - -/* - * All kernels above 2.6.33 have the kern parameter for the create - * call in struct net_proto_family. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) && \ - !defined(VMW_NETCREATE_KERNARG) -# define VMW_NETCREATE_KERNARG -#endif - -#define VSOCK_INVALID_FAMILY NPROTO -#define VSOCK_AF_IS_REGISTERED(val) ((val) >= 0 && (val) < NPROTO) - -/* Some kernel versions don't define __user. Define it ourself if so. */ -#ifndef __user -#define __user -#endif - - -/* - * Prototypes - */ -int VSockVmci_GetAFValue(void); - -/* Internal functions. */ -static Bool VSockVmciProtoToNotifyStruct(struct sock *sk, - VSockProtoVersion *proto, - Bool oldPktProto); -static int VSockVmciGetAFValue(void); -static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg); -static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg); -static void VSockVmciPeerAttachCB(VMCIId subId, - VMCI_EventData *ed, void *clientData); -static void VSockVmciPeerDetachCB(VMCIId subId, - VMCI_EventData *ed, void *clientData); -static void VSockVmciRecvPktWork(compat_work_arg work); -static void VSockVmciDelayedSockPut(compat_work_arg work); -static int VSockVmciRecvListen(struct sock *sk, VSockPacket *pkt); -static int VSockVmciRecvConnectingServer(struct sock *sk, - struct sock *pending, VSockPacket *pkt); -static int VSockVmciRecvConnectingClient(struct sock *sk, VSockPacket *pkt); -static int VSockVmciRecvConnectingClientNegotiate(struct sock *sk, - VSockPacket *pkt); -static int VSockVmciRecvConnectingClientInvalid(struct sock *sk, - VSockPacket *pkt); -static int VSockVmciRecvConnected(struct sock *sk, VSockPacket *pkt); -static int __VSockVmciBind(struct sock *sk, struct sockaddr_vm *addr); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) -static struct sock *__VSockVmciCreate(struct socket *sock, struct sock *parent, - unsigned int priority, unsigned short type); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -static struct sock *__VSockVmciCreate(struct socket *sock, struct sock *parent, - gfp_t priority, unsigned short type); -#else -static struct sock *__VSockVmciCreate(struct net *net, - struct socket *sock, struct sock *parent, - gfp_t priority, unsigned short type); -#endif -static void VSockVmciTestUnregister(void); -static int VSockVmciRegisterWithVmci(void); -static void VSockVmciUnregisterWithVmci(void); -static int VSockVmciRegisterAddressFamily(void); -static void VSockVmciUnregisterAddressFamily(void); - -/* Socket operations. */ -static void VSockVmciSkDestruct(struct sock *sk); -static int VSockVmciQueueRcvSkb(struct sock *sk, struct sk_buff *skb); -static int VSockVmciRelease(struct socket *sock); -static int VSockVmciBind(struct socket *sock, - struct sockaddr *addr, int addrLen); -static int VSockVmciDgramConnect(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); -static int VSockVmciGetname(struct socket *sock, - struct sockaddr *addr, int *addrLen, int peer); -static unsigned int VSockVmciPoll(struct file *file, - struct socket *sock, poll_table *wait); -static int VSockVmciListen(struct socket *sock, int backlog); -static int VSockVmciShutdown(struct socket *sock, int mode); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) -typedef int VSockSetsockoptLenType; -#else -typedef unsigned int VSockSetsockoptLenType; -#endif -static int VSockVmciStreamSetsockopt(struct socket *sock, int level, int optname, - char __user *optval, - VSockSetsockoptLenType optlen); - -static int VSockVmciStreamGetsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user * optlen); - -static int VSockVmciDgramSendmsg(struct kiocb *kiocb, - 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 VSockVmciStreamSendmsg(struct kiocb *kiocb, - struct socket *sock, struct msghdr *msg, size_t len); -static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, size_t len, int flags); - -static int VSockVmciCreate( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - struct net *net, -#endif - struct socket *sock, int protocol -#ifdef VMW_NETCREATE_KERNARG - , int kern -#endif - ); - - -/* - * Device operations. - */ -int VSockVmciDevOpen(struct inode *inode, struct file *file); -int VSockVmciDevRelease(struct inode *inode, struct file *file); -static int VSockVmciDevIoctl(struct inode *inode, struct file *filp, - u_int iocmd, unsigned long ioarg); -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) -static long VSockVmciDevUnlockedIoctl(struct file *filp, - u_int iocmd, unsigned long ioarg); -#endif - -/* - * Variables. - */ - -/* Protocol family. */ -static struct proto vsockVmciProto = { - .name = "AF_VMCI", -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - /* Added in 2.6.10. */ - .owner = THIS_MODULE, -#endif - /* - * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab() - * and the allocated slab was assigned to the slab variable in the proto - * struct and was created of size slab_obj_size. - * As of 2.6.12 and later, this slab allocation was moved into - * proto_register() and only done if you specified a non-zero value for - * the second argument (alloc_slab); the size of the slab element was - * changed to obj_size. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) - .slab_obj_size = sizeof (VSockVmciSock), -#else - .obj_size = sizeof (VSockVmciSock), -#endif -}; - -static struct net_proto_family vsockVmciFamilyOps = { - .family = VSOCK_INVALID_FAMILY, - .create = VSockVmciCreate, - .owner = THIS_MODULE, -}; - -/* Socket operations, split for DGRAM and STREAM sockets. */ -static struct proto_ops vsockVmciDgramOps = { - .family = VSOCK_INVALID_FAMILY, - .owner = THIS_MODULE, - .release = VSockVmciRelease, - .bind = VSockVmciBind, - .connect = VSockVmciDgramConnect, - .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 = VSockVmciDgramSendmsg, - .recvmsg = VSockVmciDgramRecvmsg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; - -static struct proto_ops vsockVmciStreamOps = { - .family = VSOCK_INVALID_FAMILY, - .owner = THIS_MODULE, - .release = VSockVmciRelease, - .bind = VSockVmciBind, - .connect = VSockVmciStreamConnect, - .socketpair = sock_no_socketpair, - .accept = VSockVmciAccept, - .getname = VSockVmciGetname, - .poll = VSockVmciPoll, - .ioctl = sock_no_ioctl, - .listen = VSockVmciListen, - .shutdown = VSockVmciShutdown, - .setsockopt = VSockVmciStreamSetsockopt, - .getsockopt = VSockVmciStreamGetsockopt, - .sendmsg = VSockVmciStreamSendmsg, - .recvmsg = VSockVmciStreamRecvmsg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; - -static struct file_operations vsockVmciDeviceOps = { - .owner = THIS_MODULE, -#ifdef HAVE_UNLOCKED_IOCTL - .unlocked_ioctl = VSockVmciDevUnlockedIoctl, -#else - .ioctl = VSockVmciDevIoctl, -#endif -#ifdef HAVE_COMPAT_IOCTL - .compat_ioctl = VSockVmciDevUnlockedIoctl, -#endif - .open = VSockVmciDevOpen, - .release = VSockVmciDevRelease, -}; - -static struct miscdevice vsockVmciDevice = { - .name = "vsock", - .minor = MISC_DYNAMIC_MINOR, - .fops = &vsockVmciDeviceOps, -}; - -typedef struct VSockRecvPktInfo { - compat_work work; - struct sock *sk; - VSockPacket pkt; -} VSockRecvPktInfo; - -typedef struct VSockDelayedSockPut { - compat_work work; - struct sock *sk; -} VSockDelayedSockPut; - -static compat_define_mutex(registrationMutex); -static int devOpenCount = 0; -static int vsockVmciSocketCount = 0; -static int vsockVmciKernClientCount = 0; -static Bool vmciDevicePresent = FALSE; -static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID }; -static VMCIId qpResumedSubId = 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. - */ -#define VSOCK_DEFAULT_QP_SIZE_MIN 128 -#define VSOCK_DEFAULT_QP_SIZE 262144 -#define VSOCK_DEFAULT_QP_SIZE_MAX 262144 - -/* - * The default peer timeout indicates how long we will wait for a peer - * response to a control message. - */ -#define VSOCK_DEFAULT_CONNECT_TIMEOUT (2 * HZ) - -#ifdef VMX86_DEVEL -# define LOG_PACKET(_pkt) VSockVmciLogPkt(__FUNCTION__, __LINE__, _pkt) -#else -# define LOG_PACKET(_pkt) -#endif - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciOldProtoOverride -- - * - * Check to see if the user has asked us to override all sockets to use - * the vsock notify protocol. - * - * Results: - * TRUE if there is a protocol override in effect. - * - oldPktProto is TRUE the original protocol should be used. - * FALSE if there is no override in effect. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciOldProtoOverride(Bool *oldPktProto) // IN -{ - ASSERT(oldPktProto); - - if (PROTOCOL_OVERRIDE != -1) { - if (PROTOCOL_OVERRIDE == 0) { - *oldPktProto = TRUE; - } else { - *oldPktProto = FALSE; - } - Warning("Proto override in use.\n"); - return TRUE; - } - - return FALSE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciProtoToNotifyStruct -- - * - * Given a particular notify protocol version, setup the socket's notify - * struct correctly. - * - * Results: - * TRUE on success. FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciProtoToNotifyStruct(struct sock *sk, // IN - VSockProtoVersion *proto, // IN - Bool oldPktProto) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(proto); - - vsk = vsock_sk(sk); - - if (oldPktProto) { - if (*proto != VSOCK_PROTO_INVALID) { - Warning("Can't set both an old and new protocol\n"); - return FALSE; - } - vsk->notifyOps = &vSockVmciNotifyPktOps; - goto exit; - } - - switch(*proto) { - case VSOCK_PROTO_PKT_ON_NOTIFY: - vsk->notifyOps= &vSockVmciNotifyPktQStateOps; - break; - default: - Warning("Unknown notify protocol version\n"); - return FALSE; - } - -exit: - NOTIFYCALL(vsk, socketInit, sk); - return TRUE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNewProtoSupportedVersions - * - * Gets the supported REQUEST2/NEGOTIATE2 vsock protocol versions. - * - * Results: - * Either 1 specific protocol version (override mode) or - * VSOCK_PROTO_ALL_SUPPORTED. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static VSockProtoVersion -VSockVmciNewProtoSupportedVersions(void) // IN -{ - if (PROTOCOL_OVERRIDE != -1) { - return PROTOCOL_OVERRIDE; - } - - return VSOCK_PROTO_ALL_SUPPORTED; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockSocket_Trusted -- - * - * We allow two kinds of sockets to communicate with a restricted VM: - * 1) trusted sockets - * 2) sockets from applications running as the same user as the VM (this - * is only true for the host side and only when using hosted products) - * - * Results: - * TRUE if trusted communication is allowed to peerCid, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockVmciTrusted(VSockVmciSock *vsock, // IN: Local socket - VMCIId peerCid) // IN: Context ID of peer -{ - return vsock->trusted || vmci_is_context_owner(peerCid, vsock->owner); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockSocket_AllowDgram -- - * - * We allow sending datagrams to and receiving datagrams from a - * restricted VM only if it is trusted as described in - * VSockVmciTrusted. - * - * Results: - * TRUE if datagram communication is allowed to peerCid, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockVmciAllowDgram(VSockVmciSock *vsock, // IN: Local socket - VMCIId peerCid) // IN: Context ID of peer -{ - if (peerCid == VMCI_HYPERVISOR_CONTEXT_ID) { - return TRUE; - } - - if (vsock->cachedPeer != peerCid) { - vsock->cachedPeer = peerCid; - if (!VSockVmciTrusted(vsock, peerCid) && - (vmci_context_get_priv_flags(peerCid) & - VMCI_PRIVILEGE_FLAG_RESTRICTED)) { - vsock->cachedPeerAllowDgram = FALSE; - } else { - vsock->cachedPeerAllowDgram = TRUE; - } - } - - return vsock->cachedPeerAllowDgram; -} - - -/* - *---------------------------------------------------------------------------- - * - * VMCISock_GetAFValue -- - * - * Kernel interface that allows external kernel modules to get the current - * vSockets address family. - * This version of the function is exported to kernel clients and should not - * change. - * - * Results: - * The address family on success, a negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMCISock_GetAFValue(void) -{ - int afvalue; - - compat_mutex_lock(®istrationMutex); - - /* - * Kernel clients are required to explicitly register themselves before they - * can use vSockets. - */ - if (vsockVmciKernClientCount <= 0) { - afvalue = -1; - goto exit; - } - - afvalue = VSockVmciGetAFValue(); - -exit: - compat_mutex_unlock(®istrationMutex); - return afvalue; -} -EXPORT_SYMBOL(VMCISock_GetAFValue); - - -/* - *---------------------------------------------------------------------------- - * - * VMCISock_GetLocalCID -- - * - * Kernel interface that allows external kernel modules to get the current - * VMCI context id. - * This version of the function is exported to kernel clients and should not - * change. - * - * Results: - * The context id on success, a negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VMCISock_GetLocalCID(void) -{ - int cid; - - compat_mutex_lock(®istrationMutex); - - /* - * Kernel clients are required to explicitly register themselves before they - * can use vSockets. - */ - if (vsockVmciKernClientCount <= 0) { - cid = -1; - goto exit; - } - - cid = vmci_get_context_id(); - -exit: - compat_mutex_unlock(®istrationMutex); - return cid; -} -EXPORT_SYMBOL(VMCISock_GetLocalCID); - - -/* - *---------------------------------------------------------------------------- - * - * VMCISock_KernelRegister -- - * - * Allows a kernel client to register with vSockets. Must be called - * before VMCISock_GetAFValue within a kernel module. Note that we don't - * actually register the address family until the first time the module - * needs to use it. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMCISock_KernelRegister(void) -{ - compat_mutex_lock(®istrationMutex); - vsockVmciKernClientCount++; - compat_mutex_unlock(®istrationMutex); -} -EXPORT_SYMBOL(VMCISock_KernelRegister); - - -/* - *---------------------------------------------------------------------------- - * - * VMCISock_KernelDeregister -- - * - * Allows a kernel client to unregister with vSockets. Every call - * to VMCISock_KernRegister must be matched with a call to - * VMCISock_KernUnregister. - * - * Results: - None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VMCISock_KernelDeregister(void) -{ - compat_mutex_lock(®istrationMutex); - vsockVmciKernClientCount--; - VSockVmciTestUnregister(); - compat_mutex_unlock(®istrationMutex); -} -EXPORT_SYMBOL(VMCISock_KernelDeregister); - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciGetAFValue -- - * - * Returns the address family value being used. - * Note: The registration mutex must be held when calling this function. - * - * Results: - * The address family on success, a negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciGetAFValue(void) -{ - int afvalue; - - afvalue = vsockVmciFamilyOps.family; - if (!VSOCK_AF_IS_REGISTERED(afvalue)) { - afvalue = VSockVmciRegisterAddressFamily(); - } - - return afvalue; -} - -/* - *---------------------------------------------------------------------------- - * - * VSockVmci_GetAFValue -- - * - * Returns the address family value being used. - * - * Results: - * The address family on success, a negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmci_GetAFValue(void) -{ - int afvalue; - - compat_mutex_lock(®istrationMutex); - afvalue = VSockVmciGetAFValue(); - compat_mutex_unlock(®istrationMutex); - - return afvalue; -} - - -/* - * Helper functions. - */ - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciQueuePairAlloc -- - * - * Allocates or attaches to a queue pair. Tries to register with trusted - * status if requested but does not fail if the queuepair could not be - * allocate as trusted (running in the guest) - * - * Results: - * 0 on success. A VSock error on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciQueuePairAlloc(VMCIQPair **qpair, // OUT - VMCIHandle *handle, // IN/OUT - uint64 produceSize, // IN - uint64 consumeSize, // IN - VMCIId peer, // IN - uint32 flags, // IN - Bool trusted) // IN -{ - int err = 0; - - if (trusted) { - /* - * Try to allocate our queue pair as trusted. This will only work - * if vsock is running in the host. - */ - - err = vmci_qpair_alloc(qpair, handle, produceSize, consumeSize, - peer, flags, VMCI_PRIVILEGE_FLAG_TRUSTED); - if (err != VMCI_ERROR_NO_ACCESS) { - goto out; - } - } - - err = vmci_qpair_alloc(qpair, handle, produceSize, consumeSize, - peer, flags, VMCI_NO_PRIVILEGE_FLAGS); -out: - if (err < 0) { - Log("Could not attach to queue pair with %d\n", err); - err = VSockVmci_ErrorToVSockError(err); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDatagramCreateHnd -- - * - * Creates a datagram handle. Tries to register with trusted - * status but does not fail if the handler could not be allocated - * as trusted (running in the guest). - * - * Results: - * 0 on success. A VMCI error on error. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciDatagramCreateHnd(VMCIId resourceID, // IN - uint32 flags, // IN - VMCIDatagramRecvCB recvCB, // IN - void *clientData, // IN - VMCIHandle *outHandle) // OUT -{ - int err = 0; - - /* - * Try to allocate our datagram handler as trusted. This will only work - * if vsock is running in the host. - */ - - err = vmci_datagram_create_handle_priv(resourceID, flags, - VMCI_PRIVILEGE_FLAG_TRUSTED, - recvCB, clientData, outHandle); - - if (err == VMCI_ERROR_NO_ACCESS) { - err = vmci_datagram_create_handle(resourceID, flags, recvCB, clientData, - outHandle); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciTestUnregister -- - * - * Tests if it's necessary to unregister the socket family, and does so. - * - * Note that this assumes the registration lock is held. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciTestUnregister(void) -{ - if (devOpenCount <= 0 && vsockVmciSocketCount <= 0 && - vsockVmciKernClientCount <= 0) { - if (VSOCK_AF_IS_REGISTERED(vsockVmciFamilyOps.family)) { - VSockVmciUnregisterAddressFamily(); - } - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvDgramCB -- - * - * VMCI Datagram receive callback. This function is used specifically for - * SOCK_DGRAM 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 -VSockVmciRecvDgramCB(void *data, // IN - VMCIDatagram *dg) // IN -{ - struct sock *sk; - size_t size; - struct sk_buff *skb; - VSockVmciSock *vsk; - - 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. */ - ASSERT(sk->sk_socket ? sk->sk_socket->type == SOCK_DGRAM : 1); - - /* - * This handler is privileged when this module is running on the - * host. We will get datagrams from all endpoints (even VMs that - * are in a restricted context). If we get one from a restricted - * context then the destination socket must be trusted. - * - * NOTE: We access the socket struct without holding the lock here. This - * is ok because the field we are interested is never modified outside - * of the create and destruct socket functions. - */ - vsk = vsock_sk(sk); - if (!VSockVmciAllowDgram(vsk, VMCI_HANDLE_TO_CONTEXT_ID(dg->src))) { - return VMCI_ERROR_NO_ACCESS; - } - - size = VMCI_DG_SIZE(dg); - - /* - * Attach the packet to the socket's receive queue as an sk_buff. - */ - skb = alloc_skb(size, GFP_ATOMIC); - if (skb) { - /* compat_sk_receive_skb() will do a sock_put(), so hold here. */ - sock_hold(sk); - skb_put(skb, size); - memcpy(skb->data, dg, size); - compat_sk_receive_skb(sk, skb, 0); - } - - return VMCI_SUCCESS; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvStreamCB -- - * - * VMCI stream receive callback for control datagrams. This function is - * used specifically for SOCK_STREAM sockets. - * - * This is invoked as part of a tasklet that's scheduled when the VMCI - * interrupt fires. This is run in bottom-half context but it defers most - * of its work to the packet handling work queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvStreamCB(void *data, // IN - VMCIDatagram *dg) // IN -{ - struct sock *sk; - struct sockaddr_vm dst; - struct sockaddr_vm src; - VSockPacket *pkt; - VSockVmciSock *vsk; - VMCIId expectedSrcRid; - Bool bhProcessPkt; - int err; - VSockDelayedSockPut *delayedSockPut; - - ASSERT(dg); - ASSERT(dg->payloadSize <= VMCI_MAX_DG_PAYLOAD_SIZE); - - sk = NULL; - err = VMCI_SUCCESS; - bhProcessPkt = FALSE; - - /* - * Ignore incoming packets from contexts without sockets, or resources that - * aren't vsock implementations. - */ - - expectedSrcRid = - VMCI_HYPERVISOR_CONTEXT_ID == VMCI_HANDLE_TO_CONTEXT_ID(dg->src) ? - VSOCK_PACKET_HYPERVISOR_RID : VSOCK_PACKET_RID; - - if (!VSockAddr_SocketContextStream(VMCI_HANDLE_TO_CONTEXT_ID(dg->src)) || - expectedSrcRid != VMCI_HANDLE_TO_RESOURCE_ID(dg->src)) { - return VMCI_ERROR_NO_ACCESS; - } - - if (VMCI_DG_SIZE(dg) < sizeof *pkt) { - /* Drop datagrams that do not contain full VSock packets. */ - return VMCI_ERROR_INVALID_ARGS; - } - - /* - * We need to preallocate this since we otherwise may end up in a situation - * where we can't put the socket due to out of memory. - */ - delayedSockPut = kmalloc(sizeof *delayedSockPut, GFP_ATOMIC); - if (!delayedSockPut) { - return VMCI_ERROR_NO_MEM; - } - - pkt = (VSockPacket *)dg; - - LOG_PACKET(pkt); - - /* - * Find the socket that should handle this packet. First we look for - * a connected socket and if there is none we look for a socket bound to - * the destintation address. - * - * Note that we don't initialize the family member of the src and dst - * sockaddr_vm since we don't want to call VMCISock_GetAFValue() and - * possibly register the address family. - */ - VSockAddr_InitNoFamily(&src, - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src), - pkt->srcPort); - - VSockAddr_InitNoFamily(&dst, - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst), - pkt->dstPort); - - sk = VSockVmciFindConnectedSocket(&src, &dst); - if (!sk) { - sk = VSockVmciFindBoundSocket(&dst); - if (!sk) { - /* - * We could not find a socket for this specified address. If this - * packet is a RST, we just drop it. If it is another packet, we send - * a RST. Note that we do not send a RST reply to RSTs so that we do - * not continually send RSTs between two endpoints. - * - * Note that since this is a reply, dst is src and src is dst. - */ - if (VSOCK_SEND_RESET_BH(&dst, &src, pkt) < 0) { - Log("unable to send reset.\n"); - } - err = VMCI_ERROR_NOT_FOUND; - goto out; - } - } - - /* - * If the received packet type is beyond all types known to this - * implementation, reply with an invalid message. Hopefully this will help - * when implementing backwards compatibility in the future. - */ - if (pkt->type >= VSOCK_PACKET_TYPE_MAX) { - VSOCK_SEND_INVALID_BH(&dst, &src); - err = VMCI_ERROR_INVALID_ARGS; - goto out; - } - - /* - * This handler is privileged when this module is running on the host. - * We will get datagram connect requests from all endpoints (even VMs that - * are in a restricted context). If we get one from a restricted context - * then the destination socket must be trusted. - * - * NOTE: We access the socket struct without holding the lock here. This - * is ok because the field we are interested is never modified outside - * of the create and destruct socket functions. - */ - vsk = vsock_sk(sk); - if (!VSockVmciAllowDgram(vsk, VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src))) { - err = VMCI_ERROR_NO_ACCESS; - goto out; - } - - /* - * We do most everything in a work queue, but let's fast path the - * notification of reads and writes to help data transfer performance. We - * can only do this if there is no process context code executing for this - * socket since that may change the state. - */ - bh_lock_sock(sk); - - if (!sock_owned_by_user(sk)) { - /* The local context ID may be out of date. */ - vsk->localAddr.svm_cid = dst.svm_cid; - - if (sk->sk_state == SS_CONNECTED) { - NOTIFYCALL(vsk, handleNotifyPkt, sk, pkt, TRUE, &dst, &src, - &bhProcessPkt); - } - } - - bh_unlock_sock(sk); - - if (!bhProcessPkt) { - VSockRecvPktInfo *recvPktInfo; - - recvPktInfo = kmalloc(sizeof *recvPktInfo, GFP_ATOMIC); - if (!recvPktInfo) { - if (VSOCK_SEND_RESET_BH(&dst, &src, pkt) < 0) { - Warning("unable to send reset\n"); - } - err = VMCI_ERROR_NO_MEM; - goto out; - } - - recvPktInfo->sk = sk; - memcpy(&recvPktInfo->pkt, pkt, sizeof recvPktInfo->pkt); - COMPAT_INIT_WORK(&recvPktInfo->work, VSockVmciRecvPktWork, recvPktInfo); - - compat_schedule_work(&recvPktInfo->work); - /* - * Clear sk so that the reference count incremented by one of the Find - * functions above is not decremented below. We need that reference - * count for the packet handler we've scheduled to run. - */ - sk = NULL; - } - -out: - if (sk) { - delayedSockPut->sk = sk; - COMPAT_INIT_WORK(&delayedSockPut->work, VSockVmciDelayedSockPut, - delayedSockPut); - compat_schedule_work(&delayedSockPut->work); - } else { - kfree(delayedSockPut); - } - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciPeerAttachCB -- - * - * Invoked when a peer attaches to a queue pair. - * - * Right now this does not do anything. - * - * Results: - * None. - * - * Side effects: - * May modify socket state and signal socket. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciPeerAttachCB(VMCIId subId, // IN - VMCI_EventData *eData, // IN - void *clientData) // IN -{ - struct sock *sk; - VMCIEventPayload_QP *ePayload; - VSockVmciSock *vsk; - - ASSERT(eData); - ASSERT(clientData); - - sk = (struct sock *)clientData; - ePayload = VMCIEventDataPayload(eData); - - vsk = vsock_sk(sk); - - /* - * We don't ask for delayed CBs when we subscribe to this event (we pass 0 - * as flags to VMCIEvent_Subscribe()). VMCI makes no guarantees in that - * case about what context we might be running in, so it could be BH or - * process, blockable or non-blockable. And bh_lock_sock() is very - * particular about how it gets called (it's *not* the same as - * spin_lock_bh(), it expands directly into a spin_lock()). So we need to - * account for all possible contexts here. - */ - local_bh_disable(); - bh_lock_sock(sk); - - /* - * XXX This is lame, we should provide a way to lookup sockets by qpHandle. - */ - if (VMCI_HANDLE_EQUAL(vsk->qpHandle, ePayload->handle)) { - /* - * XXX This doesn't do anything, but in the future we may want to set - * a flag here to verify the attach really did occur and we weren't just - * sent a datagram claiming it was. - */ - goto out; - } - -out: - bh_unlock_sock(sk); - local_bh_enable(); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleDetach -- - * - * Perform the work necessary when the peer has detached. - * - * Note that this assumes the socket lock is held. - * - * Results: - * None. - * - * Side effects: - * The socket's and its peer's shutdown mask will be set appropriately, - * and any callers waiting on this socket will be awoken. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleDetach(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - if (!VMCI_HANDLE_INVALID(vsk->qpHandle)) { - ASSERT(vsk->qpair); - - sock_set_flag(sk, SOCK_DONE); - - /* On a detach the peer will not be sending or receiving anymore. */ - vsk->peerShutdown = SHUTDOWN_MASK; - - /* - * We should not be sending anymore since the peer won't be there to - * receive, but we can still receive if there is data left in our consume - * queue. - */ - if (VSockVmciStreamHasData(vsk) <= 0) { - if (sk->sk_state == SS_CONNECTING) { - /* - * The peer may detach from a queue pair while we are - * still in the connecting state, i.e., if the peer VM is - * killed after attaching to a queue pair, but before we - * complete the handshake. In that case, we treat the - * detach event like a reset. - */ - - sk->sk_state = SS_UNCONNECTED; - sk->sk_err = ECONNRESET; - sk->sk_error_report(sk); - return; - } - sk->sk_state = SS_UNCONNECTED; - } - sk->sk_state_change(sk); - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciPeerDetachCB -- - * - * Invoked when a peer detaches from a queue pair. - * - * Results: - * None. - * - * Side effects: - * May modify socket state and signal socket. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciPeerDetachCB(VMCIId subId, // IN - VMCI_EventData *eData, // IN - void *clientData) // IN -{ - struct sock *sk; - VMCIEventPayload_QP *ePayload; - VSockVmciSock *vsk; - - ASSERT(eData); - ASSERT(clientData); - - sk = (struct sock *)clientData; - ePayload = VMCIEventDataPayload(eData); - vsk = vsock_sk(sk); - if (VMCI_HANDLE_INVALID(ePayload->handle)) { - return; - } - - /* Same rules for locking as for PeerAttachCB(). */ - local_bh_disable(); - bh_lock_sock(sk); - - /* - * XXX This is lame, we should provide a way to lookup sockets by qpHandle. - */ - if (VMCI_HANDLE_EQUAL(vsk->qpHandle, ePayload->handle)) { - VSockVmciHandleDetach(sk); - } - - bh_unlock_sock(sk); - local_bh_enable(); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciQPResumedCB -- - * - * Invoked when a VM is resumed. We must mark all connected stream sockets - * as detached. - * - * Results: - * None. - * - * Side effects: - * May modify socket state and signal socket. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciQPResumedCB(VMCIId subId, // IN - VMCI_EventData *eData, // IN - void *clientData) // IN -{ - uint32 i; - - spin_lock_bh(&vsockTableLock); - - /* - * XXX This loop should probably be provided by util.{h,c}, but that's for - * another day. - */ - for (i = 0; i < ARRAYSIZE(vsockConnectedTable); i++) { - VSockVmciSock *vsk; - - list_for_each_entry(vsk, &vsockConnectedTable[i], connectedTable) { - struct sock *sk = sk_vsock(vsk); - - /* - * XXX Technically this is racy but the resulting outcome from such - * a race is relatively harmless. My next change will be a fix to - * this. - */ - VSockVmciHandleDetach(sk); - } - } - - spin_unlock_bh(&vsockTableLock); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciPendingWork -- - * - * Releases the resources for a pending socket if it has not reached the - * connected state and been accepted by a user process. - * - * Results: - * None. - * - * Side effects: - * The socket may be removed from the connected list and all its resources - * freed. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciPendingWork(compat_delayed_work_arg work) // IN -{ - struct sock *sk; - struct sock *listener; - VSockVmciSock *vsk; - Bool cleanup; - - vsk = COMPAT_DELAYED_WORK_GET_DATA(work, VSockVmciSock, dwork); - ASSERT(vsk); - - sk = sk_vsock(vsk); - listener = vsk->listener; - cleanup = TRUE; - - ASSERT(listener); - - lock_sock(listener); - lock_sock(sk); - - /* - * The socket should be on the pending list or the accept queue, but not - * both. It's also possible that the socket isn't on either. - */ - ASSERT( ( VSockVmciIsPending(sk) && !VSockVmciInAcceptQueue(sk)) - || (!VSockVmciIsPending(sk) && VSockVmciInAcceptQueue(sk)) - || (!VSockVmciIsPending(sk) && !VSockVmciInAcceptQueue(sk))); - - if (VSockVmciIsPending(sk)) { - VSockVmciRemovePending(listener, sk); - } else if (!vsk->rejected) { - /* - * We are not on the pending list and accept() did not reject us, so we - * must have been accepted by our user process. We just need to drop our - * references to the sockets and be on our way. - */ - cleanup = FALSE; - goto out; - } - - listener->sk_ack_backlog--; - - /* - * We need to remove ourself from the global connected sockets list so - * incoming packets can't find this socket, and to reduce the reference - * count. - */ - if (VSockVmciInConnectedTable(sk)) { - VSockVmciRemoveConnected(sk); - } - - sk->sk_state = SS_FREE; - -out: - release_sock(sk); - release_sock(listener); - if (cleanup) { - sock_put(sk); - } - sock_put(sk); - sock_put(listener); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDelayedSocketPut -- - * - * Drops a reference to the given socket. - * - * Results: - * None. - * - * Side effects: - * Socket may be freed. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciDelayedSockPut(compat_work_arg work) // IN -{ - VSockDelayedSockPut *delayedSockPut; - - delayedSockPut = COMPAT_WORK_GET_DATA(work, VSockDelayedSockPut, work); - ASSERT(delayedSockPut); - - sock_put(delayedSockPut->sk); - kfree(delayedSockPut); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvPktWork -- - * - * Handles an incoming control packet for the provided socket. This is the - * state machine for our stream sockets. - * - * Results: - * None. - * - * Side effects: - * May set state and wakeup threads waiting for socket state to change. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciRecvPktWork(compat_work_arg work) // IN -{ - VSockRecvPktInfo *recvPktInfo; - VSockPacket *pkt; - struct sock *sk; - - recvPktInfo = COMPAT_WORK_GET_DATA(work, VSockRecvPktInfo, work); - ASSERT(recvPktInfo); - - sk = recvPktInfo->sk; - pkt = &recvPktInfo->pkt; - - ASSERT(pkt); - ASSERT(pkt->type < VSOCK_PACKET_TYPE_MAX); - - lock_sock(sk); - - /* The local context ID may be out of date. */ - vsock_sk(sk)->localAddr.svm_cid = VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst); - - switch (sk->sk_state) { - case SS_LISTEN: - VSockVmciRecvListen(sk, pkt); - break; - case SS_CONNECTING: - /* - * Processing of pending connections for servers goes through the - * listening socket, so see VSockVmciRecvListen() for that path. - */ - VSockVmciRecvConnectingClient(sk, pkt); - break; - case SS_CONNECTED: - VSockVmciRecvConnected(sk, pkt); - break; - default: - /* - * Because this function does not run in the same context as - * VSockVmciRecvStreamCB it is possible that the socket - * has closed. We need to let the other side know or it could - * be sitting in a connect and hang forever. Send a reset to prevent - * that. - */ - VSOCK_SEND_RESET(sk, pkt); - goto out; - } - -out: - release_sock(sk); - kfree(recvPktInfo); - /* - * Release reference obtained in the stream callback when we fetched this - * socket out of the bound or connected list. - */ - sock_put(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvListen -- - * - * Receives packets for sockets in the listen state. - * - * Note that this assumes the socket lock is held. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * A new socket may be created and a negotiate control packet is sent. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvListen(struct sock *sk, // IN - VSockPacket *pkt) // IN -{ - struct sock *pending; - VSockVmciSock *vpending; - int err; - uint64 qpSize; - Bool oldRequest = FALSE; - Bool oldPktProto = FALSE; - - ASSERT(sk); - ASSERT(pkt); - ASSERT(sk->sk_state == SS_LISTEN); - - err = 0; - - /* - * Because we are in the listen state, we could be receiving a packet for - * ourself or any previous connection requests that we received. If it's - * the latter, we try to find a socket in our list of pending connections - * and, if we do, call the appropriate handler for the state that that - * socket is in. Otherwise we try to service the connection request. - */ - pending = VSockVmciGetPending(sk, pkt); - if (pending) { - lock_sock(pending); - - /* The local context ID may be out of date. */ - vsock_sk(pending)->localAddr.svm_cid = - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst); - - switch (pending->sk_state) { - case SS_CONNECTING: - err = VSockVmciRecvConnectingServer(sk, pending, pkt); - break; - default: - VSOCK_SEND_RESET(pending, pkt); - err = -EINVAL; - } - - if (err < 0) { - VSockVmciRemovePending(sk, pending); - } - - release_sock(pending); - VSockVmciReleasePending(pending); - - return err; - } - - /* - * The listen state only accepts connection requests. Reply with a reset - * unless we received a reset. - */ - - if (!(pkt->type == VSOCK_PACKET_TYPE_REQUEST || - pkt->type == VSOCK_PACKET_TYPE_REQUEST2)) { - VSOCK_REPLY_RESET(pkt); - return -EINVAL; - } - - if (pkt->u.size == 0) { - VSOCK_REPLY_RESET(pkt); - return -EINVAL; - } - - /* - * If this socket can't accommodate this connection request, we send - * a reset. Otherwise we create and initialize a child socket and reply - * with a connection negotiation. - */ - if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) { - VSOCK_REPLY_RESET(pkt); - return -ECONNREFUSED; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - pending = __VSockVmciCreate(NULL, sk, GFP_KERNEL, sk->sk_type); -#else - pending = __VSockVmciCreate(compat_sock_net(sk), NULL, sk, GFP_KERNEL, - sk->sk_type); -#endif - if (!pending) { - VSOCK_SEND_RESET(sk, pkt); - return -ENOMEM; - } - - vpending = vsock_sk(pending); - ASSERT(vpending); - ASSERT(vsock_sk(sk)->localAddr.svm_port == pkt->dstPort); - - VSockAddr_Init(&vpending->localAddr, - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst), - pkt->dstPort); - VSockAddr_Init(&vpending->remoteAddr, - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src), - pkt->srcPort); - - /* - * If the proposed size fits within our min/max, accept - * it. Otherwise propose our own size. - */ - if (pkt->u.size >= vpending->queuePairMinSize && - pkt->u.size <= vpending->queuePairMaxSize) { - qpSize = pkt->u.size; - } else { - qpSize = vpending->queuePairSize; - } - - /* - * Figure out if we are using old or new requests based on the overrides - * pkt types sent by our peer. - */ - if (VSockVmciOldProtoOverride(&oldPktProto)) { - oldRequest = oldPktProto; - } else { - if (pkt->type == VSOCK_PACKET_TYPE_REQUEST) { - oldRequest = TRUE; - } else if (pkt->type == VSOCK_PACKET_TYPE_REQUEST2) { - oldRequest = FALSE; - } - } - - if (oldRequest) { - /* Handle a REQUEST (or override) */ - VSockProtoVersion version = VSOCK_PROTO_INVALID; - if (VSockVmciProtoToNotifyStruct(pending, &version, TRUE)) { - err = VSOCK_SEND_NEGOTIATE(pending, qpSize); - } else { - err = -EINVAL; - } - } else { - /* Handle a REQUEST2 (or override) */ - int protoInt = pkt->proto; - int pos; - uint16 activeProtoVersion = 0; - - /* - * The list of possible protocols is the intersection of all protocols - * the client supports ... plus all the protocols we support. - */ - protoInt &= VSockVmciNewProtoSupportedVersions(); - - /* We choose the highest possible protocol version and use that one. */ - pos = mssb32(protoInt); - if (pos) { - activeProtoVersion = (1 << (pos - 1)); - if (VSockVmciProtoToNotifyStruct(pending, &activeProtoVersion, FALSE)) { - err = VSOCK_SEND_NEGOTIATE2(pending, qpSize, - activeProtoVersion); - } else { - err = -EINVAL; - } - } else { - err = -EINVAL; - } - } - - if (err < 0) { - VSOCK_SEND_RESET(sk, pkt); - sock_put(pending); - err = VSockVmci_ErrorToVSockError(err); - goto out; - } - - VSockVmciAddPending(sk, pending); - sk->sk_ack_backlog++; - - pending->sk_state = SS_CONNECTING; - vpending->produceSize = vpending->consumeSize = qpSize; - vpending->queuePairSize = qpSize; - - NOTIFYCALL(vpending, processRequest, pending); - - /* - * We might never receive another message for this socket and it's not - * connected to any process, so we have to ensure it gets cleaned up - * ourself. Our delayed work function will take care of that. Note that we - * do not ever cancel this function since we have few guarantees about its - * state when calling cancel_delayed_work(). Instead we hold a reference on - * the socket for that function and make it capable of handling cases where - * it needs to do nothing but release that reference. - */ - vpending->listener = sk; - sock_hold(sk); - sock_hold(pending); - COMPAT_INIT_DELAYED_WORK(&vpending->dwork, VSockVmciPendingWork, vpending); - compat_schedule_delayed_work(&vpending->dwork, HZ); - -out: - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvConnectingServer -- - * - * Receives packets for sockets in the connecting state on the server side. - * - * Connecting sockets on the server side can only receive queue pair offer - * packets. All others should be treated as cause for closing the - * connection. - * - * Note that this assumes the socket lock is held for both sk and pending. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * A queue pair may be created, an attach control packet may be sent, the - * socket may transition to the connected state, and a pending caller in - * accept() may be woken up. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvConnectingServer(struct sock *listener, // IN: the listening socket - struct sock *pending, // IN: the pending connection - VSockPacket *pkt) // IN: current packet -{ - VSockVmciSock *vpending; - VMCIHandle handle; - VMCIQPair *qpair; - Bool isLocal; - uint32 flags; - VMCIId detachSubId; - int err; - int skerr; - - ASSERT(listener); - ASSERT(pkt); - ASSERT(listener->sk_state == SS_LISTEN); - ASSERT(pending->sk_state == SS_CONNECTING); - - vpending = vsock_sk(pending); - detachSubId = VMCI_INVALID_ID; - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_OFFER: - if (VMCI_HANDLE_INVALID(pkt->u.handle)) { - VSOCK_SEND_RESET(pending, pkt); - skerr = EPROTO; - err = -EINVAL; - goto destroy; - } - break; - default: - /* Close and cleanup the connection. */ - VSOCK_SEND_RESET(pending, pkt); - skerr = EPROTO; - err = pkt->type == VSOCK_PACKET_TYPE_RST ? - 0 : - -EINVAL; - goto destroy; - } - - ASSERT(pkt->type == VSOCK_PACKET_TYPE_OFFER); - - /* - * In order to complete the connection we need to attach to the offered - * queue pair and send an attach notification. We also subscribe to the - * detach event so we know when our peer goes away, and we do that before - * attaching so we don't miss an event. If all this succeeds, we update our - * state and wakeup anything waiting in accept() for a connection. - */ - - /* - * We don't care about attach since we ensure the other side has attached by - * specifying the ATTACH_ONLY flag below. - */ - err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH, - VSockVmciPeerDetachCB, - pending, - &detachSubId); - if (err < VMCI_SUCCESS) { - VSOCK_SEND_RESET(pending, pkt); - err = VSockVmci_ErrorToVSockError(err); - skerr = -err; - goto destroy; - } - - vpending->detachSubId = detachSubId; - - /* Now attach to the queue pair the client created. */ - handle = pkt->u.handle; - - /* - * vpending->localAddr always has a context id so we do not - * need to worry about VMADDR_CID_ANY in this case. - */ - isLocal = vpending->remoteAddr.svm_cid == vpending->localAddr.svm_cid; - flags = VMCI_QPFLAG_ATTACH_ONLY; - flags |= isLocal ? VMCI_QPFLAG_LOCAL : 0; - - err = VSockVmciQueuePairAlloc(&qpair, - &handle, - vpending->produceSize, - vpending->consumeSize, - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src), - flags, - VSockVmciTrusted(vpending, - vpending->remoteAddr.svm_cid)); - if (err < 0) { - VSOCK_SEND_RESET(pending, pkt); - skerr = -err; - goto destroy; - } - - ASSERT(VMCI_HANDLE_EQUAL(handle, pkt->u.handle)); - vpending->qpHandle = handle; - vpending->qpair = qpair; - - /* - * When we send the attach message, we must be ready to handle - * incoming control messages on the newly connected socket. So we - * move the pending socket to the connected state before sending - * the attach message. Otherwise, an incoming packet triggered by - * the attach being received by the peer may be processed - * concurrently with what happens below after sending the attach - * message, and that incoming packet will find the listening socket - * instead of the (currently) pending socket. Note that enqueueing - * the socket increments the reference count, so even if a reset - * comes before the connection is accepted, the socket will be - * valid until it is removed from the queue. - * - * If we fail sending the attach below, we remove the socket from - * the connected list and move the socket to SS_UNCONNECTED before - * releasing the lock, so a pending slow path processing of an - * incoming packet will not see the socket in the connected state - * in that case. - */ - pending->sk_state = SS_CONNECTED; - - VSockVmciInsertConnected(vsockConnectedSocketsVsk(vpending), pending); - - /* Notify our peer of our attach. */ - err = VSOCK_SEND_ATTACH(pending, handle); - if (err < 0) { - VSockVmciRemoveConnected(pending); - Log("Could not send attach\n"); - VSOCK_SEND_RESET(pending, pkt); - err = VSockVmci_ErrorToVSockError(err); - skerr = -err; - goto destroy; - } - - /* - * We have a connection. Move the now connected socket from the - * listener's pending list to the accept queue so callers of - * accept() can find it. - */ - VSockVmciRemovePending(listener, pending); - VSockVmciEnqueueAccept(listener, pending); - - /* - * Callers of accept() will be be waiting on the listening socket, not the - * pending socket. - */ - listener->sk_state_change(listener); - - return 0; - -destroy: - pending->sk_err = skerr; - pending->sk_state = SS_UNCONNECTED; - /* - * As long as we drop our reference, all necessary cleanup will handle when - * the cleanup function drops its reference and our destruct implementation - * is called. Note that since the listen handler will remove pending from - * the pending list upon our failure, the cleanup function won't drop the - * additional reference, which is why we do it here. - */ - sock_put(pending); - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvConnectingClient -- - * - * Receives packets for sockets in the connecting state on the client side. - * - * Connecting sockets on the client side should only receive attach packets. - * All others should be treated as cause for closing the connection. - * - * Note that this assumes the socket lock is held for both sk and pending. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * The socket may transition to the connected state and wakeup the pending - * caller of connect(). - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvConnectingClient(struct sock *sk, // IN: socket - VSockPacket *pkt) // IN: current packet -{ - VSockVmciSock *vsk; - int err; - int skerr; - - ASSERT(sk); - ASSERT(pkt); - ASSERT(sk->sk_state == SS_CONNECTING); - - vsk = vsock_sk(sk); - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_ATTACH: - if (VMCI_HANDLE_INVALID(pkt->u.handle) || - !VMCI_HANDLE_EQUAL(pkt->u.handle, vsk->qpHandle)) { - skerr = EPROTO; - err = -EINVAL; - goto destroy; - } - - /* - * Signify the socket is connected and wakeup the waiter in connect(). - * Also place the socket in the connected table for accounting (it can - * already be found since it's in the bound table). - */ - sk->sk_state = SS_CONNECTED; - sk->sk_socket->state = SS_CONNECTED; - VSockVmciInsertConnected(vsockConnectedSocketsVsk(vsk), sk); - sk->sk_state_change(sk); - - break; - case VSOCK_PACKET_TYPE_NEGOTIATE: - case VSOCK_PACKET_TYPE_NEGOTIATE2: - if (pkt->u.size == 0 || - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src) != vsk->remoteAddr.svm_cid || - pkt->srcPort != vsk->remoteAddr.svm_port || - !VMCI_HANDLE_INVALID(vsk->qpHandle) || - vsk->qpair || - vsk->produceSize != 0 || - vsk->consumeSize != 0 || - vsk->attachSubId != VMCI_INVALID_ID || - vsk->detachSubId != VMCI_INVALID_ID) { - skerr = EPROTO; - err = -EINVAL; - - goto destroy; - } - - err = VSockVmciRecvConnectingClientNegotiate(sk, pkt); - if (err) { - skerr = -err; - goto destroy; - } - - break; - case VSOCK_PACKET_TYPE_INVALID: - err = VSockVmciRecvConnectingClientInvalid(sk, pkt); - if (err) { - skerr = -err; - goto destroy; - } - - break; - case VSOCK_PACKET_TYPE_RST: - /* - * Older versions of the linux code (WS 6.5 / ESX 4.0) used to continue - * processing here after they sent an INVALID packet. This meant that we - * got a RST after the INVALID. We ignore a RST after an INVALID. The - * common code doesn't send the RST ... so we can hang if an old version - * of the common code fails between getting a REQUEST and sending an - * OFFER back. Not much we can do about it... except hope that it - * doesn't happen. - */ - if (vsk->ignoreConnectingRst) { - vsk->ignoreConnectingRst = FALSE; - } else { - skerr = ECONNRESET; - err = 0; - goto destroy; - } - - break; - default: - /* Close and cleanup the connection. */ - skerr = EPROTO; - err = -EINVAL; - goto destroy; - } - - ASSERT(pkt->type == VSOCK_PACKET_TYPE_ATTACH || - pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE || - pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2 || - pkt->type == VSOCK_PACKET_TYPE_INVALID || - pkt->type == VSOCK_PACKET_TYPE_RST); - - return 0; - -destroy: - VSOCK_SEND_RESET(sk, pkt); - - sk->sk_state = SS_UNCONNECTED; - sk->sk_err = skerr; - sk->sk_error_report(sk); - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvConnectingClientNegotiate -- - * - * Handles a negotiate packet for a client in the connecting state. - * - * Note that this assumes the socket lock is held for both sk and pending. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * The socket may transition to the connected state and wakeup the pending - * caller of connect(). - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvConnectingClientNegotiate(struct sock *sk, // IN: socket - VSockPacket *pkt) // IN: current packet -{ - int err; - VSockVmciSock *vsk; - VMCIHandle handle; - VMCIQPair *qpair; - VMCIId attachSubId; - VMCIId detachSubId; - Bool isLocal; - uint32 flags; - Bool oldProto = TRUE; - Bool oldPktProto; - VSockProtoVersion version; - - vsk = vsock_sk(sk); - handle = VMCI_INVALID_HANDLE; - attachSubId = VMCI_INVALID_ID; - detachSubId = VMCI_INVALID_ID; - - ASSERT(sk); - ASSERT(pkt); - ASSERT(pkt->u.size > 0); - ASSERT(vsk->remoteAddr.svm_cid == VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src)); - ASSERT(vsk->remoteAddr.svm_port == pkt->srcPort); - ASSERT(VMCI_HANDLE_INVALID(vsk->qpHandle)); - ASSERT(vsk->qpair == NULL); - ASSERT(vsk->produceSize == 0); - ASSERT(vsk->consumeSize == 0); - ASSERT(vsk->attachSubId == VMCI_INVALID_ID); - ASSERT(vsk->detachSubId == VMCI_INVALID_ID); - - /* - * If we have gotten here then we should be past the point where old linux - * vsock could have sent the bogus rst. - */ - vsk->sentRequest = FALSE; - vsk->ignoreConnectingRst = FALSE; - - /* Verify that we're OK with the proposed queue pair size */ - if (pkt->u.size < vsk->queuePairMinSize || - pkt->u.size > vsk->queuePairMaxSize) { - err = -EINVAL; - goto destroy; - } - - /* - * At this point we know the CID the peer is using to talk to us. - */ - - if (vsk->localAddr.svm_cid == VMADDR_CID_ANY) { - vsk->localAddr.svm_cid = VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst); - } - - /* - * Setup the notify ops to be the highest supported version that both the - * server and the client support. - */ - - if (VSockVmciOldProtoOverride(&oldPktProto)) { - oldProto = oldPktProto; - } else { - if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE) { - oldProto = TRUE; - } else if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2) { - oldProto = FALSE; - } - } - - if (oldProto) { - version = VSOCK_PROTO_INVALID; - } else { - version = pkt->proto; - } - - if (!VSockVmciProtoToNotifyStruct(sk, &version, oldProto)) { - err = -EINVAL; - goto destroy; - } - - /* - * Subscribe to attach and detach events first. - * - * XXX We attach once for each queue pair created for now so it is easy - * to find the socket (it's provided), but later we should only subscribe - * once and add a way to lookup sockets by queue pair handle. - */ - err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_ATTACH, - VSockVmciPeerAttachCB, - sk, - &attachSubId); - if (err < VMCI_SUCCESS) { - err = VSockVmci_ErrorToVSockError(err); - goto destroy; - } - - err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH, - VSockVmciPeerDetachCB, - sk, - &detachSubId); - if (err < VMCI_SUCCESS) { - err = VSockVmci_ErrorToVSockError(err); - goto destroy; - } - - /* Make VMCI select the handle for us. */ - handle = VMCI_INVALID_HANDLE; - isLocal = vsk->remoteAddr.svm_cid == vsk->localAddr.svm_cid; - flags = isLocal ? VMCI_QPFLAG_LOCAL : 0; - - err = VSockVmciQueuePairAlloc(&qpair, - &handle, - pkt->u.size, - pkt->u.size, - vsk->remoteAddr.svm_cid, - flags, - VSockVmciTrusted(vsk, vsk->remoteAddr.svm_cid)); - if (err < 0) { - goto destroy; - } - - err = VSOCK_SEND_QP_OFFER(sk, handle); - if (err < 0) { - err = VSockVmci_ErrorToVSockError(err); - goto destroy; - } - - vsk->qpHandle = handle; - vsk->qpair = qpair; - - vsk->produceSize = vsk->consumeSize = pkt->u.size; - - vsk->attachSubId = attachSubId; - vsk->detachSubId = detachSubId; - - NOTIFYCALL(vsk, processNegotiate, sk); - - return 0; - -destroy: - if (attachSubId != VMCI_INVALID_ID) { - vmci_event_unsubscribe(attachSubId); - ASSERT(vsk->attachSubId == VMCI_INVALID_ID); - } - - if (detachSubId != VMCI_INVALID_ID) { - vmci_event_unsubscribe(detachSubId); - ASSERT(vsk->detachSubId == VMCI_INVALID_ID); - } - - if (!VMCI_HANDLE_INVALID(handle)) { - ASSERT(vsk->qpair); - vmci_qpair_detach(&qpair); - ASSERT(VMCI_HANDLE_INVALID(vsk->qpHandle)); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvConnectingClientInvalid -- - * - * Handles an invalid packet for a client in the connecting state. - * - * Note that this assumes the socket lock is held for both sk and pending. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvConnectingClientInvalid(struct sock *sk, // IN: socket - VSockPacket *pkt) // IN: current packet -{ - int err = 0; - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(pkt); - - vsk = vsock_sk(sk); - - if (vsk->sentRequest) { - vsk->sentRequest = FALSE; - vsk->ignoreConnectingRst = TRUE; - - err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize); - if (err < 0) { - err = VSockVmci_ErrorToVSockError(err); - } else { - err = 0; - } - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRecvConnected -- - * - * Receives packets for sockets in the connected state. - * - * Connected sockets should only ever receive detach, wrote, read, or reset - * control messages. Others are treated as errors that are ignored. - * - * Wrote and read signify that the peer has produced or consumed, - * respectively. - * - * Detach messages signify that the connection is being closed cleanly and - * reset messages signify that the connection is being closed in error. - * - * Note that this assumes the socket lock is held. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * A queue pair may be created, an offer control packet sent, and the socket - * may transition to the connecting state. - * - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRecvConnected(struct sock *sk, // IN - VSockPacket *pkt) // IN -{ - VSockVmciSock *vsk; - Bool pktProcessed = FALSE; - - ASSERT(sk); - ASSERT(pkt); - ASSERT(sk->sk_state == SS_CONNECTED); - - /* - * In cases where we are closing the connection, it's sufficient to mark - * the state change (and maybe error) and wake up any waiting threads. - * Since this is a connected socket, it's owned by a user process and will - * be cleaned up when the failure is passed back on the current or next - * system call. Our system call implementations must therefore check for - * error and state changes on entry and when being awoken. - */ - switch (pkt->type) { - case VSOCK_PACKET_TYPE_SHUTDOWN: - if (pkt->u.mode) { - vsk = vsock_sk(sk); - - vsk->peerShutdown |= pkt->u.mode; - sk->sk_state_change(sk); - } - break; - - case VSOCK_PACKET_TYPE_RST: - vsk = vsock_sk(sk); - /* - * It is possible that we sent our peer a message (e.g - * a WAITING_READ) right before we got notified that the peer - * had detached. If that happens then we can get a RST pkt back - * from our peer even though there is data available for us - * to read. In that case, don't shutdown the socket completely - * but instead allow the local client to finish reading data - * off the queuepair. Always treat a RST pkt in connected mode - * like a clean shutdown. - */ - sock_set_flag(sk, SOCK_DONE); - vsk->peerShutdown = SHUTDOWN_MASK; - if (VSockVmciStreamHasData(vsk) <= 0) { - sk->sk_state = SS_DISCONNECTING; - } - sk->sk_state_change(sk); - break; - - default: - vsk = vsock_sk(sk); - NOTIFYCALL(vsk, handleNotifyPkt, sk, pkt, FALSE, NULL, NULL, - &pktProcessed); - if (!pktProcessed) { - return -EINVAL; - } - break; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciSendControlPkt -- - * - * Common code to send a control packet. - * - * Results: - * Size of datagram sent on success, negative error code otherwise. - * If convertError is TRUE, error code is a vsock error, otherwise, - * result is a VMCI error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -__VSockVmciSendControlPkt(VSockPacket *pkt, // IN - struct sockaddr_vm *src, // IN - struct sockaddr_vm *dst, // IN - VSockPacketType type, // IN - uint64 size, // IN - uint64 mode, // IN - VSockWaitingInfo *wait, // IN - VSockProtoVersion proto, // IN - VMCIHandle handle, // IN - Bool convertError) // IN -{ - int err; - - ASSERT(pkt); - /* - * This function can be called in different contexts, so family value is not - * necessarily consistent. - */ - - VSOCK_ADDR_NOFAMILY_ASSERT(src); - VSOCK_ADDR_NOFAMILY_ASSERT(dst); - - VSockPacket_Init(pkt, src, dst, type, size, mode, wait, proto, handle); - LOG_PACKET(pkt); - VSOCK_STATS_CTLPKT_LOG(pkt->type); - err = vmci_datagram_send(&pkt->dg); - if (convertError && (err < 0)) { - return VSockVmci_ErrorToVSockError(err); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciReplyControlPktFast -- - * - * Sends a control packet back to the source of an incoming packet. - * The control packet is allocated in the stack. - * - * Results: - * Size of datagram sent on success, negative error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciReplyControlPktFast(VSockPacket *pkt, // IN - VSockPacketType type, // IN - uint64 size, // IN - uint64 mode, // IN - VSockWaitingInfo *wait, // IN - VMCIHandle handle) // IN -{ - VSockPacket reply; - struct sockaddr_vm src, dst; - - ASSERT(pkt); - - if (pkt->type == VSOCK_PACKET_TYPE_RST) { - return 0; - } else { - VSockPacket_GetAddresses(pkt, &src, &dst); - return __VSockVmciSendControlPkt(&reply, &src, &dst, type, - size, mode, wait, - VSOCK_PROTO_INVALID, handle, TRUE); - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSendControlPktBH -- - * - * Sends a control packet from bottom-half context. The control packet is - * static data to minimize the resource cost. - * - * Results: - * Size of datagram sent on success, negative error code otherwise. Note - * that we return a VMCI error message since that's what callers will need - * to provide. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciSendControlPktBH(struct sockaddr_vm *src, // IN - struct sockaddr_vm *dst, // IN - VSockPacketType type, // IN - uint64 size, // IN - uint64 mode, // IN - VSockWaitingInfo *wait, // IN - VMCIHandle handle) // IN -{ - /* - * Note that it is safe to use a single packet across all CPUs since two - * tasklets of the same type are guaranteed to not ever run simultaneously. - * If that ever changes, or VMCI stops using tasklets, we can use per-cpu - * packets. - */ - static VSockPacket pkt; - - return __VSockVmciSendControlPkt(&pkt, src, dst, type, - size, mode, wait, VSOCK_PROTO_INVALID, - handle, FALSE); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSendControlPkt -- - * - * Sends a control packet. - * - * Results: - * Size of datagram sent on success, negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciSendControlPkt(struct sock *sk, // IN - VSockPacketType type, // IN - uint64 size, // IN - uint64 mode, // IN - VSockWaitingInfo *wait, // IN - VSockProtoVersion proto, // IN - VMCIHandle handle) // IN -{ - VSockPacket *pkt; - VSockVmciSock *vsk; - int err; - - ASSERT(sk); - /* - * New sockets for connection establishment won't have socket structures - * yet; if one exists, ensure it is of the proper type. - */ - ASSERT(sk->sk_socket ? - sk->sk_socket->type == SOCK_STREAM : - 1); - - vsk = vsock_sk(sk); - - if (!VSockAddr_Bound(&vsk->localAddr)) { - return -EINVAL; - } - - if (!VSockAddr_Bound(&vsk->remoteAddr)) { - return -EINVAL; - } - - pkt = kmalloc(sizeof *pkt, GFP_KERNEL); - if (!pkt) { - return -ENOMEM; - } - - err = __VSockVmciSendControlPkt(pkt, &vsk->localAddr, &vsk->remoteAddr, - type, size, mode, wait, proto, handle, - TRUE); - kfree(pkt); - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciBind -- - * - * Common functionality needed to bind the specified address to the - * VSocket. If VMADDR_CID_ANY or VMADDR_PORT_ANY are specified, the context - * ID or port are selected automatically. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * On success, a new datagram handle is created. - * - *---------------------------------------------------------------------------- - */ - -static int -__VSockVmciBind(struct sock *sk, // IN/OUT - struct sockaddr_vm *addr) // IN -{ - static unsigned int port = LAST_RESERVED_PORT + 1; - struct sockaddr_vm newAddr; - VSockVmciSock *vsk; - VMCIId cid; - int err; - - ASSERT(sk); - ASSERT(sk->sk_socket); - ASSERT(addr); - - vsk = vsock_sk(sk); - - /* First ensure this socket isn't already bound. */ - if (VSockAddr_Bound(&vsk->localAddr)) { - return -EINVAL; - } - - /* - * Now bind to the provided address or select appropriate values if none are - * provided (VMADDR_CID_ANY and VMADDR_PORT_ANY). Note that like AF_INET - * prevents binding to a non-local IP address (in most cases), we only allow - * binding to the local CID. - */ - VSockAddr_Init(&newAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); - - cid = vmci_get_context_id(); - if (addr->svm_cid != cid && - addr->svm_cid != VMADDR_CID_ANY) { - return -EADDRNOTAVAIL; - } - - newAddr.svm_cid = addr->svm_cid; - - switch (sk->sk_socket->type) { - case SOCK_STREAM: { - spin_lock_bh(&vsockTableLock); - - if (addr->svm_port == VMADDR_PORT_ANY) { - Bool found = FALSE; - unsigned int i; - - for (i = 0; i < MAX_PORT_RETRIES; i++) { - if (port <= LAST_RESERVED_PORT) { - port = LAST_RESERVED_PORT + 1; - } - - newAddr.svm_port = port++; - - if (!__VSockVmciFindBoundSocket(&newAddr)) { - found = TRUE; - break; - } - } - - if (!found) { - err = -EADDRNOTAVAIL; - goto out; - } - } else { - /* If port is in reserved range, ensure caller has necessary privileges. */ - if (addr->svm_port <= LAST_RESERVED_PORT && - !capable(CAP_NET_BIND_SERVICE)) { - err = -EACCES; - goto out; - } - - newAddr.svm_port = addr->svm_port; - if (__VSockVmciFindBoundSocket(&newAddr)) { - err = -EADDRINUSE; - goto out; - } - - } - break; - } - case SOCK_DGRAM: { - uint32 flags = 0; - - /* VMCI will select a resource ID for us if we provide VMCI_INVALID_ID. */ - newAddr.svm_port = addr->svm_port == VMADDR_PORT_ANY ? - VMCI_INVALID_ID : - addr->svm_port; - - if (newAddr.svm_port <= LAST_RESERVED_PORT && - !capable(CAP_NET_BIND_SERVICE)) { - err = -EACCES; - goto out; - } - - if (newAddr.svm_cid == VMADDR_CID_ANY) { - flags = VMCI_FLAG_ANYCID_DG_HND; - } - - err = VSockVmciDatagramCreateHnd(newAddr.svm_port, flags, - VSockVmciRecvDgramCB, - sk, &vsk->dgHandle); - if (err < VMCI_SUCCESS) { - err = VSockVmci_ErrorToVSockError(err); - goto out; - } - - newAddr.svm_port = VMCI_HANDLE_TO_RESOURCE_ID(vsk->dgHandle); - break; - } - default: { - err = -EINVAL; - goto out; - } - } - /* - * VSockVmci_GetAFValue() acquires a mutex and may sleep, so fill the - * field after unlocking socket tables. - */ - VSockAddr_InitNoFamily(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port); - - /* - * Remove stream sockets from the unbound list and add them to the hash - * table for easy lookup by its address. The unbound list is simply an - * extra entry at the end of the hash table, a trick used by AF_UNIX. - */ - if (sk->sk_socket->type == SOCK_STREAM) { - __VSockVmciRemoveBound(sk); - __VSockVmciInsertBound(vsockBoundSockets(&vsk->localAddr), sk); - spin_unlock_bh(&vsockTableLock); - } - vsk->localAddr.svm_family = VSockVmci_GetAFValue(); - VSOCK_ADDR_ASSERT(&vsk->localAddr); - - return 0; - -out: - if (sk->sk_socket->type == SOCK_STREAM) { - spin_unlock_bh(&vsockTableLock); - } - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciCreate -- - * - * Does the work to create the sock structure. - * Note: If sock is NULL then the type field must be non-zero. - * Otherwise, sock is non-NULL and the type of sock is used in the - * newly created socket. - * - * Results: - * sock structure on success, NULL on failure. - * - * Side effects: - * Allocated sk is added to the unbound sockets list iff it is owned by - * a struct socket. - * - *---------------------------------------------------------------------------- - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) -static struct sock * -__VSockVmciCreate(struct socket *sock, // IN: Owning socket, may be NULL - struct sock *parent, // IN: Parent socket, may be NULL - unsigned int priority, // IN: Allocation flags - unsigned short type) // IN: Socket type if sock is NULL -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -static struct sock * -__VSockVmciCreate(struct socket *sock, // IN: Owning socket, may be NULL - struct sock *parent, // IN: Parent socket, may be NULL - gfp_t priority, // IN: Allocation flags - unsigned short type) // IN: Socket type if sock is NULL -#else -static struct sock * -__VSockVmciCreate(struct net *net, // IN: Network namespace - struct socket *sock, // IN: Owning socket, may be NULL - struct sock *parent, // IN: Parent socket, may be NULL - gfp_t priority, // IN: Allocation flags - unsigned short type) // IN: Socket type if sock is NULL - -#endif -{ - struct sock *sk; - VSockVmciSock *psk; - VSockVmciSock *vsk; - - ASSERT((sock && !type) || (!sock && type)); - - vsk = NULL; - - /* - * From 2.6.9 to until 2.6.12 sk_alloc() used a cache in - * the protocol structure, but you still had to specify the size and cache - * yourself. - * Most recently (in 2.6.24), sk_alloc() was changed to expect the - * network namespace, and the option to zero the sock was dropped. - * - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) - sk = sk_alloc(vsockVmciFamilyOps.family, priority, - vsockVmciProto.slab_obj_size, vsockVmciProto.slab); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - sk = sk_alloc(vsockVmciFamilyOps.family, priority, &vsockVmciProto, 1); -#else - sk = sk_alloc(net, vsockVmciFamilyOps.family, priority, &vsockVmciProto); -#endif - if (!sk) { - return NULL; - } - - /* - * If we go this far, we know the socket family is registered, so there's no - * need to register it now. - */ - compat_mutex_lock(®istrationMutex); - vsockVmciSocketCount++; - compat_mutex_unlock(®istrationMutex); - - sock_init_data(sock, sk); - - /* - * sk->sk_type is normally set in sock_init_data, but only if - * sock is non-NULL. We make sure that our sockets always have a type - * by setting it here if needed. - */ - if (!sock) { - sk->sk_type = type; - } - - vsk = vsock_sk(sk); - VSockAddr_Init(&vsk->localAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); - VSockAddr_Init(&vsk->remoteAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); - - sk->sk_destruct = VSockVmciSkDestruct; - sk->sk_backlog_rcv = VSockVmciQueueRcvSkb; - sk->sk_state = 0; - sock_reset_flag(sk, SOCK_DONE); - - INIT_LIST_HEAD(&vsk->boundTable); - INIT_LIST_HEAD(&vsk->connectedTable); - vsk->dgHandle = VMCI_INVALID_HANDLE; - vsk->qpHandle = VMCI_INVALID_HANDLE; - vsk->qpair = NULL; - vsk->produceSize = vsk->consumeSize = 0; - vsk->listener = NULL; - INIT_LIST_HEAD(&vsk->pendingLinks); - INIT_LIST_HEAD(&vsk->acceptQueue); - vsk->rejected = FALSE; - vsk->sentRequest = FALSE; - vsk->ignoreConnectingRst = FALSE; - vsk->attachSubId = vsk->detachSubId = VMCI_INVALID_ID; - vsk->peerShutdown = 0; - - if (parent) { - psk = vsock_sk(parent); - vsk->trusted = psk->trusted; - vsk->owner = psk->owner; - vsk->queuePairSize = psk->queuePairSize; - vsk->queuePairMinSize = psk->queuePairMinSize; - vsk->queuePairMaxSize = psk->queuePairMaxSize; - vsk->connectTimeout = psk->connectTimeout; - } else { - vsk->trusted = capable(CAP_NET_ADMIN); - vsk->owner = current_uid(); - vsk->queuePairSize = VSOCK_DEFAULT_QP_SIZE; - vsk->queuePairMinSize = VSOCK_DEFAULT_QP_SIZE_MIN; - vsk->queuePairMaxSize = VSOCK_DEFAULT_QP_SIZE_MAX; - vsk->connectTimeout = VSOCK_DEFAULT_CONNECT_TIMEOUT; - } - - vsk->notifyOps = NULL; - - if (sock) { - VSockVmciInsertBound(vsockUnboundSockets, sk); - } - - return sk; -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciRelease -- - * - * Releases the provided socket. - * - * Results: - * None. - * - * Side effects: - * Any pending sockets are also released. - * - *---------------------------------------------------------------------------- - */ - -static void -__VSockVmciRelease(struct sock *sk) // IN -{ - if (sk) { - struct sk_buff *skb; - struct sock *pending; - struct VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - pending = NULL; /* Compiler warning. */ - - if (VSockVmciInBoundTable(sk)) { - VSockVmciRemoveBound(sk); - } - - if (VSockVmciInConnectedTable(sk)) { - VSockVmciRemoveConnected(sk); - } - - if (!VMCI_HANDLE_INVALID(vsk->dgHandle)) { - vmci_datagram_destroy_handle(vsk->dgHandle); - vsk->dgHandle = VMCI_INVALID_HANDLE; - } - - lock_sock(sk); - sock_orphan(sk); - sk->sk_shutdown = SHUTDOWN_MASK; - - while ((skb = skb_dequeue(&sk->sk_receive_queue))) { - kfree_skb(skb); - } - - /* Clean up any sockets that never were accepted. */ - while ((pending = VSockVmciDequeueAccept(sk)) != NULL) { - __VSockVmciRelease(pending); - sock_put(pending); - } - - release_sock(sk); - sock_put(sk); - } -} - - -/* - * Sock operations. - */ - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSkDestruct -- - * - * Destroys the provided socket. This is called by sk_free(), which is - * invoked when the reference count of the socket drops to zero. - * - * Results: - * None. - * - * Side effects: - * Socket count is decremented. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciSkDestruct(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - - if (vsk->attachSubId != VMCI_INVALID_ID) { - vmci_event_unsubscribe(vsk->attachSubId); - vsk->attachSubId = VMCI_INVALID_ID; - } - - if (vsk->detachSubId != VMCI_INVALID_ID) { - vmci_event_unsubscribe(vsk->detachSubId); - vsk->detachSubId = VMCI_INVALID_ID; - } - - if (!VMCI_HANDLE_INVALID(vsk->qpHandle)) { - ASSERT(vsk->qpair); - vmci_qpair_detach(&vsk->qpair); - vsk->qpHandle = VMCI_INVALID_HANDLE; - ASSERT(vsk->qpair == NULL); - vsk->produceSize = vsk->consumeSize = 0; - } - - /* - * Each list entry holds a reference on the socket, so we should not even be - * here if the socket is in one of our lists. If we are we have a stray - * sock_put() that needs to go away. - */ - ASSERT(!VSockVmciInBoundTable(sk)); - ASSERT(!VSockVmciInConnectedTable(sk)); - ASSERT(!VSockVmciIsPending(sk)); - ASSERT(!VSockVmciInAcceptQueue(sk)); - - /* - * When clearing these addresses, there's no need to set the family and - * possibly register the address family with the kernel. - */ - VSockAddr_InitNoFamily(&vsk->localAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); - VSockAddr_InitNoFamily(&vsk->remoteAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); - - NOTIFYCALL(vsk, socketDestruct, sk); - - compat_mutex_lock(®istrationMutex); - vsockVmciSocketCount--; - VSockVmciTestUnregister(); - compat_mutex_unlock(®istrationMutex); - - VSOCK_STATS_CTLPKT_DUMP_ALL(); - VSOCK_STATS_HIST_DUMP_ALL(); - VSOCK_STATS_TOTALS_DUMP_ALL(); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciQueueRcvSkb -- - * - * Receives skb on the socket's receive queue. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciQueueRcvSkb(struct sock *sk, // IN - struct sk_buff *skb) // IN -{ - int err; - - err = sock_queue_rcv_skb(sk, skb); - if (err) { - kfree_skb(skb); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRegisterProto -- - * - * Registers the vSockets protocol family. - * - * Results: - * Zero on success, error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRegisterProto(void) -{ - int err = 0; - - /* - * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab() - * and the allocated slab was assigned to the slab variable in the proto - * struct and was created of size slab_obj_size. As of 2.6.12 and later, - * this slab allocation was moved - * into proto_register() and only done if you specified a non-zero value - * for the second argument (alloc_slab); the size of the slab element was - * changed to obj_size. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) - err = sk_alloc_slab(&vsockVmciProto, "vsock"); - if (err != 0) { - sk_alloc_slab_error(&vsockVmciProto); - } -#else - /* Specify 1 as the second argument so the slab is created for us. */ - err = proto_register(&vsockVmciProto, 1); -#endif - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciUnregisterProto -- - * - * Unregisters the vSockets protocol family. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciUnregisterProto(void) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) - sk_free_slab(&vsockVmciProto); -#else - proto_unregister(&vsockVmciProto); -#endif - - VSOCK_STATS_RESET(); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRegisterAddressFamily -- - * - * Registers our socket address family with the kernel. - * - * Note that this assumes the registration lock is held. - * - * Results: - * The address family value on success, negative error code on failure. - * - * Side effects: - * Callers of socket operations with the returned value, on success, will - * be able to use our socket implementation. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRegisterAddressFamily(void) -{ - int err = 0; - int i; - - /* - * Linux will not allocate an address family to code that is not part of the - * kernel proper, so until that time comes we need a workaround. Here we - * loop through the allowed values and claim the first one that's not - * currently used. Users will then make an ioctl(2) into our module to - * retrieve this value before calling socket(2). - * - * This is undesirable, but it's better than having users' programs break - * when a hard-coded, currently-available value gets assigned to someone - * else in the future. - */ - for (i = NPROTO - 1; i >= 0; i--) { - vsockVmciFamilyOps.family = i; - err = sock_register(&vsockVmciFamilyOps); - if (err) { - vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY; - } else { - vsockVmciDgramOps.family = i; - vsockVmciStreamOps.family = i; - err = i; - break; - } - } - - if (VSOCK_INVALID_FAMILY == vsockVmciFamilyOps.family) { - Warning("Could not register address family.\n"); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciUnregisterAddressFamily -- - * - * Unregisters the address family with the kernel. - * - * Note that this assumes the registration lock is held. - * - * Results: - * None. - * - * Side effects: - * Our socket implementation is no longer accessible. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciUnregisterAddressFamily(void) -{ - if (vsockVmciFamilyOps.family != VSOCK_INVALID_FAMILY) { - sock_unregister(vsockVmciFamilyOps.family); - } - - vsockVmciDgramOps.family = vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY; - vsockVmciStreamOps.family = vsockVmciFamilyOps.family; -} - - - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRegisterWithVmci -- - * - * Registers with the VMCI device, and creates control message - * and event handlers. - * - * Results: - * Zero on success, error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRegisterWithVmci(void) -{ - int err = 0; - uint32 apiVersion; - - /* - * We don't call into the vmci module if the vmci device isn't - * present. - */ - apiVersion = VMCI_KERNEL_API_VERSION_1; - vmciDevicePresent = vmci_device_get(&apiVersion, NULL, NULL, NULL); - if (!vmciDevicePresent) { - Warning("VMCI device not present.\n"); - return -1; - } - - /* - * Create the datagram handle that we will use to send and receive all - * VSocket control messages for this context. - */ - err = VSockVmciDatagramCreateHnd(VSOCK_PACKET_RID, - VMCI_FLAG_ANYCID_DG_HND, - VSockVmciRecvStreamCB, NULL, - &vmciStreamHandle); - if (err < VMCI_SUCCESS) { - Warning("Unable to create datagram handle. (%d)\n", err); - err = VSockVmci_ErrorToVSockError(err); - goto out; - } - - err = vmci_event_subscribe(VMCI_EVENT_QP_RESUMED, - VSockVmciQPResumedCB, - NULL, - &qpResumedSubId); - if (err < VMCI_SUCCESS) { - Warning("Unable to subscribe to QP resumed event. (%d)\n", err); - err = VSockVmci_ErrorToVSockError(err); - qpResumedSubId = VMCI_INVALID_ID; - goto out; - } - -out: - if (err != 0) { - VSockVmciUnregisterWithVmci(); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciUnregisterWithVmci -- - * - * Destroys control message and event handlers, and unregisters - * with the VMCI device - * - * Results: - * None. - * - * Side effects: - * Our socket implementation is no longer accessible. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciUnregisterWithVmci(void) -{ - if (!vmciDevicePresent) { - /* Nothing was registered. */ - return; - } - - if (!VMCI_HANDLE_INVALID(vmciStreamHandle)) { - if (vmci_datagram_destroy_handle(vmciStreamHandle) != VMCI_SUCCESS) { - Warning("Could not destroy VMCI datagram handle.\n"); - } - vmciStreamHandle = VMCI_INVALID_HANDLE; - } - - if (qpResumedSubId != VMCI_INVALID_ID) { - vmci_event_unsubscribe(qpResumedSubId); - qpResumedSubId = VMCI_INVALID_ID; - } - - vmci_device_release(NULL); - vmciDevicePresent = FALSE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStreamHasData -- - * - * Gets the amount of data available for a given stream socket's consume - * queue. - * - * Note that this assumes the socket lock is held. - * - * Results: - * The amount of data available or a VMCI error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int64 -VSockVmciStreamHasData(VSockVmciSock *vsk) // IN -{ - ASSERT(vsk); - - return vmci_qpair_consume_buf_ready(vsk->qpair); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStreamHasSpace -- - * - * Gets the amount of space available for a give stream socket's produce - * queue. - * - * Note that this assumes the socket lock is held. - * - * Results: - * The amount of space available or a VMCI error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int64 -VSockVmciStreamHasSpace(VSockVmciSock *vsk) // IN -{ - ASSERT(vsk); - - return vmci_qpair_produce_free_space(vsk->qpair); -} - - -/* - * Socket operations. - */ - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRelease -- - * - * Releases the provided socket by freeing the contents of its queue. This - * is called when a user process calls close(2) on the socket. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciRelease(struct socket *sock) // IN -{ - __VSockVmciRelease(sock->sk); - sock->sk = NULL; - sock->state = SS_FREE; - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciBind -- - * - * Binds the provided address to the provided socket. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciBind(struct socket *sock, // IN - struct sockaddr *addr, // IN - int addrLen) // IN -{ - int err; - struct sock *sk; - struct sockaddr_vm *vmciAddr; - - sk = sock->sk; - - if (VSockAddr_Cast(addr, addrLen, &vmciAddr) != 0) { - return -EINVAL; - } - - lock_sock(sk); - err = __VSockVmciBind(sk, vmciAddr); - release_sock(sk); - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDgramConnect -- - * - * Connects a datagram socket. This can be called multiple times to change - * the socket's association and can be called with a sockaddr whose family - * is set to AF_UNSPEC to dissolve any existing association. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciDgramConnect(struct socket *sock, // IN - struct sockaddr *addr, // IN - int addrLen, // IN - int flags) // IN -{ - int err; - struct sock *sk; - VSockVmciSock *vsk; - struct sockaddr_vm *remoteAddr; - - sk = sock->sk; - vsk = vsock_sk(sk); - - err = VSockAddr_Cast(addr, addrLen, &remoteAddr); - if (err == -EAFNOSUPPORT && remoteAddr->svm_family == AF_UNSPEC) { - lock_sock(sk); - VSockAddr_Init(&vsk->remoteAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY); - sock->state = SS_UNCONNECTED; - release_sock(sk); - return 0; - } else if (err != 0) { - return -EINVAL; - } - - 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; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciConnectTimeout -- - * - * Asynchronous connection attempts schedule this timeout function - * to notify the connector of an unsuccessfull connection - * attempt. If the socket is still in the connecting state and - * hasn't been closed, we mark the socket as timed out. Otherwise, - * we do nothing. - * - * Results: - * None. - * - * Side effects: - * May destroy the socket. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciConnectTimeout(compat_delayed_work_arg work) // IN -{ - struct sock *sk; - VSockVmciSock *vsk; - - vsk = COMPAT_DELAYED_WORK_GET_DATA(work, VSockVmciSock, dwork); - ASSERT(vsk); - - sk = sk_vsock(vsk); - - lock_sock(sk); - if (sk->sk_state == SS_CONNECTING && (sk->sk_shutdown != SHUTDOWN_MASK)) { - sk->sk_state = SS_UNCONNECTED; - sk->sk_err = ETIMEDOUT; - sk->sk_error_report(sk); - } - release_sock(sk); - - sock_put(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStreamConnect -- - * - * Connects a stream socket. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciStreamConnect(struct socket *sock, // IN - struct sockaddr *addr, // IN - int addrLen, // IN - int flags) // IN -{ - int err; - struct sock *sk; - VSockVmciSock *vsk; - struct sockaddr_vm *remoteAddr; - long timeout; - Bool oldPktProto = FALSE; - DEFINE_WAIT(wait); - - err = 0; - sk = sock->sk; - vsk = vsock_sk(sk); - - lock_sock(sk); - - /* XXX AF_UNSPEC should make us disconnect like AF_INET. */ - switch (sock->state) { - case SS_CONNECTED: - err = -EISCONN; - goto out; - case SS_DISCONNECTING: - err = -EINVAL; - goto out; - case SS_CONNECTING: - /* - * This continues on so we can move sock into the SS_CONNECTED state once - * the connection has completed (at which point err will be set to zero - * also). Otherwise, we will either wait for the connection or return - * -EALREADY should this be a non-blocking call. - */ - err = -EALREADY; - break; - default: - ASSERT(sk->sk_state == SS_FREE || - sk->sk_state == SS_UNCONNECTED || - sk->sk_state == SS_LISTEN); - if ((sk->sk_state == SS_LISTEN) || - VSockAddr_Cast(addr, addrLen, &remoteAddr) != 0) { - err = -EINVAL; - goto out; - } - - /* The hypervisor and well-known contexts do not have socket endpoints. */ - if (!VSockAddr_SocketContextStream(remoteAddr->svm_cid)) { - err = -ENETUNREACH; - goto out; - } - - /* Set the remote address that we are connecting to. */ - memcpy(&vsk->remoteAddr, remoteAddr, sizeof vsk->remoteAddr); - - /* Autobind this socket to the local address if necessary. */ - 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; - } - } - - sk->sk_state = SS_CONNECTING; - - if (VSockVmciOldProtoOverride(&oldPktProto) && oldPktProto) { - err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize); - if (err < 0) { - sk->sk_state = SS_UNCONNECTED; - goto out; - } - } else { - int supportedProtoVersions = VSockVmciNewProtoSupportedVersions(); - err = VSOCK_SEND_CONN_REQUEST2(sk, vsk->queuePairSize, - supportedProtoVersions); - if (err < 0) { - sk->sk_state = SS_UNCONNECTED; - goto out; - } - - vsk->sentRequest = TRUE; - } - - /* - * Mark sock as connecting and set the error code to in progress in case - * this is a non-blocking connect. - */ - sock->state = SS_CONNECTING; - err = -EINPROGRESS; - } - - /* - * The receive path will handle all communication until we are able to enter - * the connected state. Here we wait for the connection to be completed or - * a notification of an error. - */ - timeout = vsk->connectTimeout; - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - while (sk->sk_state != SS_CONNECTED && sk->sk_err == 0) { - if (flags & O_NONBLOCK) { - /* - * If we're not going to block, we schedule a timeout - * function to generate a timeout on the connection attempt, - * in case the peer doesn't respond in a timely manner. We - * hold on to the socket until the timeout fires. - */ - sock_hold(sk); - COMPAT_INIT_DELAYED_WORK(&vsk->dwork, VSockVmciConnectTimeout, vsk); - compat_schedule_delayed_work(&vsk->dwork, timeout); - - /* Skip ahead to preserve error code set above. */ - goto outWait; - } - - release_sock(sk); - timeout = schedule_timeout(timeout); - lock_sock(sk); - - if (signal_pending(current)) { - err = sock_intr_errno(timeout); - goto outWaitError; - } else if (timeout == 0) { - err = -ETIMEDOUT; - goto outWaitError; - } - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - } - - if (sk->sk_err) { - err = -sk->sk_err; - goto outWaitError; - } else { - ASSERT(sk->sk_state == SS_CONNECTED); - err = 0; - } - -outWait: - finish_wait(sk_sleep(sk), &wait); -out: - release_sock(sk); - return err; - -outWaitError: - sk->sk_state = SS_UNCONNECTED; - sock->state = SS_UNCONNECTED; - goto outWait; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciAccept -- - * - * Accepts next available connection request for this socket. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciAccept(struct socket *sock, // IN - struct socket *newsock, // IN/OUT - int flags) // IN -{ - struct sock *listener; - int err; - struct sock *connected; - VSockVmciSock *vconnected; - long timeout; - DEFINE_WAIT(wait); - - err = 0; - listener = sock->sk; - - lock_sock(listener); - - if (sock->type != SOCK_STREAM) { - err = -EOPNOTSUPP; - goto out; - } - - if (listener->sk_state != SS_LISTEN) { - err = -EINVAL; - goto out; - } - - /* - * Wait for children sockets to appear; these are the new sockets created - * upon connection establishment. - */ - timeout = sock_sndtimeo(listener, flags & O_NONBLOCK); - prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); - - while ((connected = VSockVmciDequeueAccept(listener)) == NULL && - listener->sk_err == 0) { - release_sock(listener); - timeout = schedule_timeout(timeout); - lock_sock(listener); - - if (signal_pending(current)) { - err = sock_intr_errno(timeout); - goto outWait; - } else if (timeout == 0) { - err = -EAGAIN; - goto outWait; - } - - prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); - } - - if (listener->sk_err) { - err = -listener->sk_err; - } - - if (connected) { - listener->sk_ack_backlog--; - - lock_sock(connected); - vconnected = vsock_sk(connected); - - /* - * If the listener socket has received an error, then we should reject - * this socket and return. Note that we simply mark the socket rejected, - * drop our reference, and let the cleanup function handle the cleanup; - * the fact that we found it in the listener's accept queue guarantees - * that the cleanup function hasn't run yet. - */ - if (err) { - vconnected->rejected = TRUE; - release_sock(connected); - sock_put(connected); - goto outWait; - } - - newsock->state = SS_CONNECTED; - sock_graft(connected, newsock); - release_sock(connected); - sock_put(connected); - } - -outWait: - finish_wait(sk_sleep(listener), &wait); -out: - release_sock(listener); - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciGetname -- - * - * Provides the local or remote address for the socket. - * - * Results: - * Zero on success, negative error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciGetname(struct socket *sock, // IN - struct sockaddr *addr, // OUT - int *addrLen, // OUT - int peer) // IN -{ - int err; - struct sock *sk; - VSockVmciSock *vsk; - struct sockaddr_vm *vmciAddr; - - sk = sock->sk; - vsk = vsock_sk(sk); - err = 0; - - lock_sock(sk); - - if (peer) { - if (sock->state != SS_CONNECTED) { - err = -ENOTCONN; - goto out; - } - vmciAddr = &vsk->remoteAddr; - } else { - vmciAddr = &vsk->localAddr; - } - - if (!vmciAddr) { - err = -EINVAL; - goto out; - } - - /* - * sys_getsockname() and sys_getpeername() pass us a MAX_SOCK_ADDR-sized - * buffer and don't set addrLen. Unfortunately that macro is defined in - * socket.c instead of .h, so we hardcode its value here. - */ - ASSERT_ON_COMPILE(sizeof *vmciAddr <= 128); - memcpy(addr, vmciAddr, sizeof *vmciAddr); - *addrLen = sizeof *vmciAddr; - -out: - release_sock(sk); - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciPoll -- - * - * Waits on file for activity then provides mask indicating state of socket. - * - * Results: - * Mask of flags containing socket state. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static unsigned int -VSockVmciPoll(struct file *file, // IN - struct socket *sock, // IN - poll_table *wait) // IN -{ - struct sock *sk; - unsigned int mask; - VSockVmciSock *vsk; - - sk = sock->sk; - vsk = vsock_sk(sk); - - poll_wait(file, sk_sleep(sk), wait); - mask = 0; - - if (sk->sk_err) { - /* Signify that there has been an error on this socket. */ - mask |= POLLERR; - } - - /* - * INET sockets treat local write shutdown and peer write shutdown - * as a case of POLLHUP set. - */ - if ((sk->sk_shutdown == SHUTDOWN_MASK) || - ((sk->sk_shutdown & SEND_SHUTDOWN) && - (vsk->peerShutdown & SEND_SHUTDOWN))) { - mask |= POLLHUP; - } - - /* POLLRDHUP wasn't added until 2.6.17. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - if (sk->sk_shutdown & RCV_SHUTDOWN || - vsk->peerShutdown & SEND_SHUTDOWN) { - mask |= POLLRDHUP; - } -#endif - - if (sock->type == SOCK_DGRAM) { - /* - * For datagram sockets we can read if there is something in the queue - * and write as long as the socket isn't shutdown for sending. - */ - if (!skb_queue_empty(&sk->sk_receive_queue) || - (sk->sk_shutdown & RCV_SHUTDOWN)) { - mask |= POLLIN | POLLRDNORM; - } - - if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { - mask |= POLLOUT | POLLWRNORM | POLLWRBAND; - } - } else if (sock->type == SOCK_STREAM) { - lock_sock(sk); - - /* - * Listening sockets that have connections in their accept queue can be read. - */ - if (sk->sk_state == SS_LISTEN && !VSockVmciIsAcceptQueueEmpty(sk)) { - mask |= POLLIN | POLLRDNORM; - } - - /* - * If there is something in the queue then we can read. - */ - if (!VMCI_HANDLE_INVALID(vsk->qpHandle) && - !(sk->sk_shutdown & RCV_SHUTDOWN)) { - Bool dataReadyNow = FALSE; - int32 ret = 0; - NOTIFYCALLRET(vsk, ret, pollIn, sk, 1, &dataReadyNow); - if (ret < 0) { - mask |= POLLERR; - } else { - if (dataReadyNow) { - mask |= POLLIN | POLLRDNORM; - } - } - } - - /* - * 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) { - mask |= POLLIN | POLLRDNORM; - } - - /* - * Connected sockets that can produce data can be written. - */ - if (sk->sk_state == SS_CONNECTED) { - if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { - Bool spaceAvailNow = FALSE; - int32 ret = 0; - - NOTIFYCALLRET(vsk, ret, pollOut, sk, 1, &spaceAvailNow); - if (ret < 0) { - mask |= POLLERR; - } else { - if (spaceAvailNow) { - /* Remove POLLWRBAND since INET sockets are not setting it.*/ - mask |= POLLOUT | POLLWRNORM; - } - } - } - } - - /* - * Simulate INET socket poll behaviors, which sets POLLOUT|POLLWRNORM when - * peer is closed and nothing to read, but local send is not shutdown. - */ - if (sk->sk_state == SS_UNCONNECTED) { - if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { - mask |= POLLOUT | POLLWRNORM; - } - } - - release_sock(sk); - } - - return mask; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciListen -- - * - * Signify that this socket is listening for connection requests. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciListen(struct socket *sock, // IN - int backlog) // IN -{ - int err; - struct sock *sk; - VSockVmciSock *vsk; - - sk = sock->sk; - - lock_sock(sk); - - if (sock->type != SOCK_STREAM) { - err = -EOPNOTSUPP; - goto out; - } - - if (sock->state != SS_UNCONNECTED) { - err = -EINVAL; - goto out; - } - - vsk = vsock_sk(sk); - - if (!VSockAddr_Bound(&vsk->localAddr)) { - err = -EINVAL; - goto out; - } - - sk->sk_max_ack_backlog = backlog; - sk->sk_state = SS_LISTEN; - - err = 0; - -out: - release_sock(sk); - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciShutdown -- - * - * Shuts down the provided socket in the provided method. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciShutdown(struct socket *sock, // IN - int mode) // IN -{ - int32 err; - struct sock *sk; - - /* - * User level uses SHUT_RD (0) and SHUT_WR (1), but the kernel uses - * RCV_SHUTDOWN (1) and SEND_SHUTDOWN (2), so we must increment mode here - * like the other address families do. Note also that the increment makes - * SHUT_RDWR (2) into RCV_SHUTDOWN | SEND_SHUTDOWN (3), which is what we - * want. - */ - mode++; - - if ((mode & ~SHUTDOWN_MASK) || !mode) { - return -EINVAL; - } - - /* - * 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. - */ - - sk = sock->sk; - if (sock->state == SS_UNCONNECTED) { - err = -ENOTCONN; - if (sk->sk_type == SOCK_STREAM) { - return err; - } - } else { - sock->state = SS_DISCONNECTING; - err = 0; - } - - /* Receive and send shutdowns are treated alike. */ - mode = mode & (RCV_SHUTDOWN | SEND_SHUTDOWN); - if (mode) { - lock_sock(sk); - sk->sk_shutdown |= mode; - sk->sk_state_change(sk); - release_sock(sk); - - if (sk->sk_type == SOCK_STREAM) { - sock_reset_flag(sk, SOCK_DONE); - VSOCK_SEND_SHUTDOWN(sk, mode); - } - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDgramSendmsg -- - * - * Sends a datagram. - * - * Results: - * Number of bytes sent on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciDgramSendmsg(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; - struct sockaddr_vm *remoteAddr; - VMCIDatagram *dg; - - if (msg->msg_flags & MSG_OOB) { - return -EOPNOTSUPP; - } - - if (len > VMCI_MAX_DG_PAYLOAD_SIZE) { - return -EMSGSIZE; - } - - /* For now, MSG_DONTWAIT is always assumed... */ - err = 0; - sk = sock->sk; - vsk = vsock_sk(sk); - - 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 the provided message contains an address, use that. Otherwise fall - * back on the socket's remote handle (if it has been connected). - */ - if (msg->msg_name && - VSockAddr_Cast(msg->msg_name, msg->msg_namelen, &remoteAddr) == 0) { - /* Ensure this address is of the right type and is a valid destination. */ - // XXXAB Temporary to handle test program - if (remoteAddr->svm_cid == VMADDR_CID_ANY) { - remoteAddr->svm_cid = vmci_get_context_id(); - } - - if (!VSockAddr_Bound(remoteAddr)) { - err = -EINVAL; - goto out; - } - } else if (sock->state == SS_CONNECTED) { - remoteAddr = &vsk->remoteAddr; - // XXXAB Temporary to handle test program - if (remoteAddr->svm_cid == VMADDR_CID_ANY) { - remoteAddr->svm_cid = vmci_get_context_id(); - } - - /* XXX Should connect() or this function ensure remoteAddr is bound? */ - if (!VSockAddr_Bound(&vsk->remoteAddr)) { - err = -EINVAL; - goto out; - } - } else { - err = -EINVAL; - goto out; - } - - /* - * Make sure that we don't allow a userlevel app to send datagrams - * to the hypervisor that modify VMCI device state. - */ - if (!VSockAddr_SocketContextDgram(remoteAddr->svm_cid, - remoteAddr->svm_port)) { - err = -EINVAL; - goto out; - } - - if (!VSockVmciAllowDgram(vsk, remoteAddr->svm_cid)) { - err = -EPERM; - goto out; - } - - /* - * Allocate a buffer for the user's message and our packet header. - */ - dg = kmalloc(len + sizeof *dg, GFP_KERNEL); - if (!dg) { - err = -ENOMEM; - goto out; - } - - memcpy_fromiovec(VMCI_DG_PAYLOAD(dg), msg->msg_iov, len); - - dg->dst = VMCI_MAKE_HANDLE(remoteAddr->svm_cid, remoteAddr->svm_port); - dg->src = VMCI_MAKE_HANDLE(vsk->localAddr.svm_cid, vsk->localAddr.svm_port); - - dg->payloadSize = len; - - err = vmci_datagram_send(dg); - kfree(dg); - if (err < 0) { - err = VSockVmci_ErrorToVSockError(err); - goto out; - } - - err -= sizeof *dg; - -out: - release_sock(sk); - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStreamSetsockopt -- - * - * Set a socket option on a stream socket - * - * Results: - * 0 on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciStreamSetsockopt(struct socket *sock, // IN/OUT - int level, // IN - int optname, // IN - char __user *optval, // IN - VSockSetsockoptLenType optlen) // IN -{ - int err; - struct sock *sk; - VSockVmciSock *vsk; - uint64 val; - - if (level != VSockVmci_GetAFValue()) { - return -ENOPROTOOPT; - } - -# define COPY_IN(_v) \ - do { \ - if (optlen < sizeof _v) { \ - err = -EINVAL; \ - goto exit; \ - } \ - if (copy_from_user(&_v, optval, sizeof _v) != 0) { \ - err = -EFAULT; \ - goto exit; \ - } \ - } while (0) - - err = 0; - sk = sock->sk; - vsk = vsock_sk(sk); - - ASSERT(vsk->queuePairMinSize <= vsk->queuePairSize && - vsk->queuePairSize <= vsk->queuePairMaxSize); - - lock_sock(sk); - - switch (optname) { - case SO_VMCI_BUFFER_SIZE: - COPY_IN(val); - if (val < vsk->queuePairMinSize) { - vsk->queuePairMinSize = val; - } - - if (val > vsk->queuePairMaxSize) { - vsk->queuePairMaxSize = val; - } - - vsk->queuePairSize = val; - break; - - case SO_VMCI_BUFFER_MAX_SIZE: - COPY_IN(val); - if (val < vsk->queuePairSize) { - vsk->queuePairSize = val; - } - vsk->queuePairMaxSize = val; - break; - - case SO_VMCI_BUFFER_MIN_SIZE: - COPY_IN(val); - if (val > vsk->queuePairSize) { - vsk->queuePairSize = val; - } - vsk->queuePairMinSize = val; - break; - - case SO_VMCI_CONNECT_TIMEOUT: { - struct timeval tv; - COPY_IN(tv); - if (tv.tv_sec >= 0 && tv.tv_usec < USEC_PER_SEC && - tv.tv_sec < (MAX_SCHEDULE_TIMEOUT/HZ - 1)) { - vsk->connectTimeout = tv.tv_sec * HZ + - CEILING(tv.tv_usec, (1000000 / HZ)); - if (vsk->connectTimeout == 0) { - vsk->connectTimeout = VSOCK_DEFAULT_CONNECT_TIMEOUT; - } - } else { - err = -ERANGE; - } - break; - } - - default: - err = -ENOPROTOOPT; - break; - } - -# undef COPY_IN - - ASSERT(vsk->queuePairMinSize <= vsk->queuePairSize && - vsk->queuePairSize <= vsk->queuePairMaxSize); -exit: - release_sock(sk); - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStreamGetsockopt -- - * - * Get a socket option for a stream socket - * - * Results: - * 0 on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciStreamGetsockopt(struct socket *sock, // IN - int level, // IN - int optname, // IN - char __user *optval, // OUT - int __user * optlen) // IN/OUT -{ - int err; - int len; - struct sock *sk; - VSockVmciSock *vsk; - - if (level != VSockVmci_GetAFValue()) { - return -ENOPROTOOPT; - } - - if ((err = get_user(len, optlen)) != 0) { - return err; - } - -# define COPY_OUT(_v) \ - do { \ - if (len < sizeof _v) { \ - return -EINVAL; \ - } \ - len = sizeof _v; \ - if (copy_to_user(optval, &_v, len) != 0) { \ - return -EFAULT; \ - } \ - } while (0) - - err = 0; - sk = sock->sk; - vsk = vsock_sk(sk); - - switch (optname) { - case SO_VMCI_BUFFER_SIZE: - COPY_OUT(vsk->queuePairSize); - break; - - case SO_VMCI_BUFFER_MAX_SIZE: - COPY_OUT(vsk->queuePairMaxSize); - break; - - case SO_VMCI_BUFFER_MIN_SIZE: - COPY_OUT(vsk->queuePairMinSize); - break; - - case SO_VMCI_CONNECT_TIMEOUT: { - struct timeval tv; - tv.tv_sec = vsk->connectTimeout / HZ; - tv.tv_usec = (vsk->connectTimeout - tv.tv_sec * HZ) * (1000000 / HZ); - COPY_OUT(tv); - break; - } - default: - return -ENOPROTOOPT; - } - - if ((err = put_user(len, optlen)) != 0) { - return -EFAULT; - } - -# undef COPY_OUT - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStreamSendmsg -- - * - * Sends a message on the socket. - * - * Results: - * Number of bytes sent on success, negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciStreamSendmsg(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 -{ - struct sock *sk; - VSockVmciSock *vsk; - ssize_t totalWritten; - long timeout; - int err; - VSockVmciSendNotifyData sendData; - - DEFINE_WAIT(wait); - - sk = sock->sk; - vsk = vsock_sk(sk); - totalWritten = 0; - err = 0; - - if (msg->msg_flags & MSG_OOB) { - return -EOPNOTSUPP; - } - - lock_sock(sk); - - /* Callers should not provide a destination with stream sockets. */ - if (msg->msg_namelen) { - err = sk->sk_state == SS_CONNECTED ? -EISCONN : -EOPNOTSUPP; - goto out; - } - - /* Send data only if both sides are not shutdown in the direction. */ - if (sk->sk_shutdown & SEND_SHUTDOWN || - vsk->peerShutdown & RCV_SHUTDOWN) { - err = -EPIPE; - goto out; - } - - if (sk->sk_state != SS_CONNECTED || - !VSockAddr_Bound(&vsk->localAddr)) { - err = -ENOTCONN; - goto out; - } - - if (!VSockAddr_Bound(&vsk->remoteAddr)) { - err = -EDESTADDRREQ; - goto out; - } - - /* - * Wait for room in the produce queue to enqueue our user's data. - */ - timeout = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); - - NOTIFYCALLRET(vsk, err, sendInit, sk, &sendData); - if (err < 0) { - goto out; - } - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - while (totalWritten < len) { - ssize_t written; - - while (VSockVmciStreamHasSpace(vsk) == 0 && - sk->sk_err == 0 && - !(sk->sk_shutdown & SEND_SHUTDOWN) && - !(vsk->peerShutdown & RCV_SHUTDOWN)) { - - /* Don't wait for non-blocking sockets. */ - if (timeout == 0) { - err = -EAGAIN; - goto outWait; - } - - NOTIFYCALLRET(vsk, err, sendPreBlock, sk, &sendData); - - if (err < 0) { - goto outWait; - } - - release_sock(sk); - timeout = schedule_timeout(timeout); - lock_sock(sk); - if (signal_pending(current)) { - err = sock_intr_errno(timeout); - goto outWait; - } else if (timeout == 0) { - err = -EAGAIN; - goto outWait; - } - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - } - - /* - * These checks occur both as part of and after the loop conditional - * since we need to check before and after sleeping. - */ - if (sk->sk_err) { - err = -sk->sk_err; - goto outWait; - } else if ((sk->sk_shutdown & SEND_SHUTDOWN) || - (vsk->peerShutdown & RCV_SHUTDOWN)) { - err = -EPIPE; - goto outWait; - } - - VSOCK_STATS_STREAM_PRODUCE_HIST(vsk); - - NOTIFYCALLRET(vsk, err, sendPreEnqueue, sk, &sendData); - if (err < 0) { - goto outWait; - } - - /* - * Note that enqueue will only write as many bytes as are free in the - * produce queue, so we don't need to ensure len is smaller than the queue - * size. It is the caller's responsibility to check how many bytes we were - * able to send. - */ - - written = vmci_qpair_enquev(vsk->qpair, msg->msg_iov, - len - totalWritten, 0); - if (written < 0) { - err = -ENOMEM; - goto outWait; - } - - totalWritten += written; - - NOTIFYCALLRET(vsk, err, sendPostEnqueue, sk, written, &sendData); - if (err < 0) { - goto outWait; - } - } - - ASSERT(totalWritten <= INT_MAX); - -outWait: - if (totalWritten > 0) { - VSOCK_STATS_STREAM_PRODUCE(totalWritten); - err = totalWritten; - } - finish_wait(sk_sleep(sk), &wait); -out: - release_sock(sk); - return err; -} - - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDgramRecvmsg -- - * - * 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 -VSockVmciDgramRecvmsg(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; - struct sock *sk; - VMCIDatagram *dg; - size_t payloadLen; - struct sk_buff *skb; - - sk = sock->sk; - noblock = flags & MSG_DONTWAIT; - - 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; - } - - if (!skb) { - return -EAGAIN; - } - - dg = (VMCIDatagram *)skb->data; - if (!dg) { - /* err is 0, meaning we read zero bytes. */ - goto out; - } - - payloadLen = dg->payloadSize; - /* Ensure the sk_buff matches the payload size claimed in the packet. */ - if (payloadLen != skb->len - sizeof *dg) { - err = -EINVAL; - goto out; - } - - if (payloadLen > len) { - payloadLen = len; - msg->msg_flags |= MSG_TRUNC; - } - - /* Place the datagram payload in the user's iovec. */ - err = skb_copy_datagram_iovec(skb, sizeof *dg, msg->msg_iov, payloadLen); - if (err) { - goto out; - } - - msg->msg_namelen = 0; - 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)); - 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. - * - * Results: - * The size of the payload on success, negative value on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciStreamRecvmsg(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 -{ - struct sock *sk; - VSockVmciSock *vsk; - int err; - size_t target; - ssize_t copied; - long timeout; - - VSockVmciRecvNotifyData recvData; - - DEFINE_WAIT(wait); - - sk = sock->sk; - vsk = vsock_sk(sk); - err = 0; - - lock_sock(sk); - - if (sk->sk_state != SS_CONNECTED) { - /* - * Recvmsg is supposed to return 0 if a peer performs an orderly shutdown. - * Differentiate between that case and when a peer has not connected or a - * local shutdown occured with the SOCK_DONE flag. - */ - if (sock_flag(sk, SOCK_DONE)) { - err = 0; - } else { - err = -ENOTCONN; - } - goto out; - } - - if (flags & MSG_OOB) { - err = -EOPNOTSUPP; - goto out; - } - - /* - * We don't check peerShutdown flag here since peer may actually shut down, - * but there can be data in the VMCI queue that local socket can receive. - */ - if (sk->sk_shutdown & RCV_SHUTDOWN) { - err = 0; - goto out; - } - - /* - * It is valid on Linux to pass in a zero-length receive buffer. This - * is not an error. We may as well bail out now. Note that if we don't, - * we will fail "ASSERT(copied >= target)" after we dequeue, because the - * minimum target is always 1 byte. - */ - if (!len) { - err = 0; - goto out; - } - - /* - * We must not copy less than target bytes into the user's buffer before - * returning successfully, so we wait for the consume queue to have that - * much data to consume before dequeueing. Note that this makes it - * impossible to handle cases where target is greater than the queue size. - */ - target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - if (target >= vsk->consumeSize) { - err = -ENOMEM; - goto out; - } - timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - copied = 0; - - NOTIFYCALLRET(vsk, err, recvInit, sk, target, &recvData); - if (err < 0) { - goto out; - } - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - while (1) { - int64 ready = VSockVmciStreamHasData(vsk); - - if (ready < 0) { - /* - * Invalid queue pair content. XXX This should be changed to - * a connection reset in a later change. - */ - - err = -ENOMEM; - goto outWait; - } else if (ready > 0) { - ssize_t read; - - VSOCK_STATS_STREAM_CONSUME_HIST(vsk); - - NOTIFYCALLRET(vsk, err, recvPreDequeue, sk, target, &recvData); - if (err < 0) { - break; - } - - if (flags & MSG_PEEK) { - read = vmci_qpair_peekv(vsk->qpair, msg->msg_iov, len - copied, 0); - } else { - read = vmci_qpair_dequev(vsk->qpair, msg->msg_iov, len - copied, 0); - } - - if (read < 0) { - err = -ENOMEM; - break; - } - - ASSERT(read <= INT_MAX); - copied += read; - - NOTIFYCALLRET(vsk, err, recvPostDequeue, sk, target, read, - !(flags & MSG_PEEK), &recvData); - if (err < 0) { - goto outWait; - } - - if (read >= target || flags & MSG_PEEK) { - break; - } - target -= read; - } else { - if (sk->sk_err != 0 || (sk->sk_shutdown & RCV_SHUTDOWN) || - (vsk->peerShutdown & SEND_SHUTDOWN)) { - break; - } - /* Don't wait for non-blocking sockets. */ - if (timeout == 0) { - err = -EAGAIN; - break; - } - - NOTIFYCALLRET(vsk, err, recvPreBlock, sk, target, &recvData); - if (err < 0) { - break; - } - - release_sock(sk); - timeout = schedule_timeout(timeout); - lock_sock(sk); - - if (signal_pending(current)) { - err = sock_intr_errno(timeout); - break; - } else if (timeout == 0) { - err = -EAGAIN; - break; - } - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - } - } - - if (sk->sk_err) { - err = -sk->sk_err; - } else if (sk->sk_shutdown & RCV_SHUTDOWN) { - err = 0; - } - - if (copied > 0) { - /* - * We only do these additional bookkeeping/notification steps if we - * actually copied something out of the queue pair instead of just peeking - * ahead. - */ - - 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. - */ - if (vsk->peerShutdown & SEND_SHUTDOWN) { - if (VSockVmciStreamHasData(vsk) <= 0) { - sk->sk_state = SS_UNCONNECTED; - sock_set_flag(sk, SOCK_DONE); - sk->sk_state_change(sk); - } - } - } - err = copied; - } - -outWait: - finish_wait(sk_sleep(sk), &wait); -out: - release_sock(sk); - return err; -} - - -/* - * Protocol operation. - */ - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciCreate -- - * - * Creates a VSocket socket. - * - * Results: - * Zero on success, negative error code on failure. - * - * Side effects: - * Socket count is incremented. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciCreate( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - struct net *net, // IN -#endif - struct socket *sock, // IN - int protocol // IN -#ifdef VMW_NETCREATE_KERNARG - , int kern // IN -#endif - ) -{ - if (!sock) { - return -EINVAL; - } - - if (protocol) { - return -EPROTONOSUPPORT; - } - - switch (sock->type) { - case SOCK_DGRAM: - sock->ops = &vsockVmciDgramOps; - break; - case SOCK_STREAM: - sock->ops = &vsockVmciStreamOps; - break; - default: - return -ESOCKTNOSUPPORT; - } - - sock->state = SS_UNCONNECTED; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - return __VSockVmciCreate(sock, NULL, GFP_KERNEL, 0) ? 0 : -ENOMEM; -#else - return __VSockVmciCreate(net, sock, NULL, GFP_KERNEL, 0) ? 0 : -ENOMEM; -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciIoctl32Handler -- - * - * Handler for 32-bit ioctl(2) on 64-bit. - * - * Results: - * Same as VsockVmciDevIoctl(). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -#ifdef VM_X86_64 -#ifndef HAVE_COMPAT_IOCTL -static int -VSockVmciIoctl32Handler(unsigned int fd, // IN - unsigned int iocmd, // IN - unsigned long ioarg, // IN/OUT - struct file * filp) // IN -{ - int ret; - ret = -ENOTTY; - if (filp && filp->f_op && filp->f_op->ioctl == VSockVmciDevIoctl) { - ret = VSockVmciDevIoctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); - } - return ret; -} -#endif /* !HAVE_COMPAT_IOCTL */ - - -/* - *---------------------------------------------------------------------------- - * - * register_ioctl32_handlers -- - * - * Registers the ioctl conversion handler. - * - * Results: - * Zero on success, error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -register_ioctl32_handlers(void) -{ -#ifndef HAVE_COMPAT_IOCTL - { - int i; - for (i = IOCTL_VMCI_SOCKETS_FIRST; i < IOCTL_VMCI_SOCKETS_LAST; i++) { - int retval = register_ioctl32_conversion(i, VSockVmciIoctl32Handler); - if (retval) { - Warning("Fail to register ioctl32 conversion for cmd %d\n", i); - return retval; - } - } - } -#endif /* !HAVE_COMPAT_IOCTL */ - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * unregister_ioctl32_handlers -- - * - * Unregisters the ioctl converstion handler. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -unregister_ioctl32_handlers(void) -{ -#ifndef HAVE_COMPAT_IOCTL - { - int i; - for (i = IOCTL_VMCI_SOCKETS_FIRST; i < IOCTL_VMCI_SOCKETS_LAST; i++) { - int retval = unregister_ioctl32_conversion(i); - if (retval) { - Warning("Fail to unregister ioctl32 conversion for cmd %d\n", i); - } - } - } -#endif /* !HAVE_COMPAT_IOCTL */ -} -#else /* VM_X86_64 */ -#define register_ioctl32_handlers() (0) -#define unregister_ioctl32_handlers() do { } while (0) -#endif /* VM_X86_64 */ - - -/* - * Device operations. - */ - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDevOpen -- - * - * Invoked when the device is opened. Simply maintains a count of open - * instances. - * - * Results: - * Zero on success, negative value otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciDevOpen(struct inode *inode, // IN - struct file *file) // IN -{ - compat_mutex_lock(®istrationMutex); - devOpenCount++; - compat_mutex_unlock(®istrationMutex); - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDevRelease -- - * - * Invoked when the device is closed. Updates the open instance count and - * unregisters the socket family if this is the last user. - * - * Results: - * Zero on success, negative value otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -VSockVmciDevRelease(struct inode *inode, // IN - struct file *file) // IN -{ - compat_mutex_lock(®istrationMutex); - devOpenCount--; - VSockVmciTestUnregister(); - compat_mutex_unlock(®istrationMutex); - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDevIoctl -- - * - * ioctl(2) handler. - * - * Results: - * Zero on success, negative error code otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciDevIoctl(struct inode *inode, // IN - struct file *filp, // IN - u_int iocmd, // IN - unsigned long ioarg) // IN/OUT -{ - int retval; - - retval = 0; - - switch (iocmd) { - case IOCTL_VMCI_SOCKETS_VERSION: { - uint16 parts[4] = { VSOCK_DRIVER_VERSION_COMMAS }; - uint32 version = VMCI_SOCKETS_MAKE_VERSION(parts); - if (copy_to_user((void*)ioarg, &version, sizeof version) != 0) { - retval = -EFAULT; - } - break; - } - - case IOCTL_VMCI_SOCKETS_GET_AF_VALUE: { - int family; - - family = VSockVmci_GetAFValue(); - if (family < 0) { - Warning("AF_VSOCK is not registered\n"); - } - if (copy_to_user((void *)ioarg, &family, sizeof family) != 0) { - retval = -EFAULT; - } - break; - } - - case IOCTL_VMCI_SOCKETS_GET_LOCAL_CID: { - VMCIId cid = vmci_get_context_id(); - if (copy_to_user((void *)ioarg, &cid, sizeof cid) != 0) { - retval = -EFAULT; - } - break; - } - - default: - Warning("Unknown ioctl %d\n", iocmd); - retval = -EINVAL; - } - - return retval; -} - - -#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL) -/* - *----------------------------------------------------------------------------- - * - * VSockVmciDevUnlockedIoctl -- - * - * Wrapper for VSockVmciDevIoctl() supporting the compat_ioctl and - * unlocked_ioctl methods that have signatures different from the - * old ioctl. Used as compat_ioctl method for 32bit apps running - * on 64bit kernel and for unlocked_ioctl on systems supporting - * those. VSockVmciDevIoctl() may safely be called without holding - * the BKL. - * - * Results: - * Same as VSockVmciDevIoctl(). - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static long -VSockVmciDevUnlockedIoctl(struct file *filp, // IN - u_int iocmd, // IN - unsigned long ioarg) // IN/OUT -{ - return VSockVmciDevIoctl(NULL, filp, iocmd, ioarg); -} -#endif - -/* - * Module operations. - */ - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInit -- - * - * Initialization routine for the VSockets module. - * - * Results: - * Zero on success, error code on failure. - * - * Side effects: - * The VSocket protocol family and socket operations are registered. - * - *---------------------------------------------------------------------------- - */ - -static int __init -VSockVmciInit(void) -{ - int err; - - DriverLog_Init("VSock"); - - request_module("vmci"); - - err = misc_register(&vsockVmciDevice); - if (err) { - return -ENOENT; - } - - err = register_ioctl32_handlers(); - if (err) { - misc_deregister(&vsockVmciDevice); - return err; - } - - err = VSockVmciRegisterWithVmci(); - if (err) { - Warning("Cannot register with VMCI device.\n"); - unregister_ioctl32_handlers(); - misc_deregister(&vsockVmciDevice); - return err; - } - - err = VSockVmciRegisterProto(); - if (err) { - Warning("Cannot register vsock protocol.\n"); - VSockVmciUnregisterWithVmci(); - unregister_ioctl32_handlers(); - misc_deregister(&vsockVmciDevice); - return err; - } - - VSockVmciInitTables(); - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSocketVmciExit -- - * - * VSockets module exit routine. - * - * Results: - * None. - * - * Side effects: - * Unregisters VSocket protocol family and socket operations. - * - *---------------------------------------------------------------------------- - */ - -static void __exit -VSockVmciExit(void) -{ - unregister_ioctl32_handlers(); - misc_deregister(&vsockVmciDevice); - compat_mutex_lock(®istrationMutex); - VSockVmciUnregisterAddressFamily(); - compat_mutex_unlock(®istrationMutex); - - VSockVmciUnregisterProto(); - VSockVmciUnregisterWithVmci(); -} - - -module_init(VSockVmciInit); -module_exit(VSockVmciExit); - -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Virtual Socket Family"); -MODULE_VERSION(VSOCK_DRIVER_VERSION_STRING); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("vmware_vsock"); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); - -#ifdef VMX86_DEVEL -/* We only support protocol negotiation overrides on devel builds. */ -module_param(PROTOCOL_OVERRIDE, int, 0444); -MODULE_PARM_DESC(PROTOCOL_OVERRIDE, "Specify a vsock protocol (auto negotiated by default"); - -int LOGLEVEL_THRESHOLD = 4; -module_param(LOGLEVEL_THRESHOLD, int, 0444); -MODULE_PARM_DESC(LOGLEVEL_THRESHOLD, "Set verbosity (0 means no log, 10 means very verbose, 4 is default)"); -#endif diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.h b/open-vm-tools/modules/linux/vsock/linux/af_vsock.h deleted file mode 100644 index 08e437d05..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.h +++ /dev/null @@ -1,187 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - - -/* - * af_vsock.h -- - * - * Definitions for Linux VSockets module. - */ - -#ifndef __AF_VSOCK_H__ -#define __AF_VSOCK_H__ - -#include "vsockCommon.h" -#include "vsockPacket.h" -#include "compat_workqueue.h" - -#include "vmciKernelAPI.h" - -#include "notify.h" - -#ifdef VMX86_DEVEL -extern int LOGLEVEL_THRESHOLD; - -#define LOG(level, args) ((void) (LOGLEVEL_THRESHOLD >= (level) ? (Log args) : 0)) -#else -#define LOG(level, args) -#endif - -# define vsock_sk(__sk) ((VSockVmciSock *)__sk) -# define sk_vsock(__vsk) (&(__vsk)->sk) - -typedef struct VSockVmciSock { - /* sk must be the first member. */ - struct sock sk; - struct sockaddr_vm localAddr; - struct sockaddr_vm remoteAddr; - /* Links for the global tables of bound and connected sockets. */ - struct list_head boundTable; - struct list_head connectedTable; - /* - * Accessed without the socket lock held. This means it can never be - * modified outsided of socket create or destruct. - */ - Bool trusted; - Bool cachedPeerAllowDgram; /* Dgram communication allowed to cached peer? */ - VMCIId cachedPeer; /* Context ID of last dgram destination check. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) - kuid_t owner; -#else - uid_t owner; -#endif - VMCIHandle dgHandle; /* For SOCK_DGRAM only. */ - /* Rest are SOCK_STREAM only. */ - VMCIHandle qpHandle; - VMCIQPair *qpair; - uint64 produceSize; - uint64 consumeSize; - uint64 queuePairSize; - uint64 queuePairMinSize; - uint64 queuePairMaxSize; - long connectTimeout; - VSockVmciNotify notify; - VSockVmciNotifyOps *notifyOps; - VMCIId attachSubId; - VMCIId detachSubId; - /* Listening socket that this came from. */ - struct sock *listener; - /* - * Used for pending list and accept queue during connection handshake. The - * listening socket is the head for both lists. Sockets created for - * connection requests are placed in the pending list until they are - * connected, at which point they are put in the accept queue list so they - * can be accepted in accept(). If accept() cannot accept the connection, - * it is marked as rejected so the cleanup function knows to clean up the - * socket. - */ - struct list_head pendingLinks; - struct list_head acceptQueue; - Bool rejected; - compat_delayed_work dwork; - uint32 peerShutdown; - Bool sentRequest; - Bool ignoreConnectingRst; -} VSockVmciSock; - -int VSockVmciSendControlPktBH(struct sockaddr_vm *src, - struct sockaddr_vm *dst, - VSockPacketType type, - uint64 size, - uint64 mode, - VSockWaitingInfo *wait, - VMCIHandle handle); -int VSockVmciReplyControlPktFast(VSockPacket *pkt, VSockPacketType type, - uint64 size, uint64 mode, - VSockWaitingInfo *wait, VMCIHandle handle); -int VSockVmciSendControlPkt(struct sock *sk, VSockPacketType type, - uint64 size, uint64 mode, - VSockWaitingInfo *wait, - VSockProtoVersion version, - VMCIHandle handle); - -int64 VSockVmciStreamHasData(VSockVmciSock *vsk); -int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk); - -#define VSOCK_SEND_RESET_BH(_dst, _src, _pkt) \ - ((_pkt)->type == VSOCK_PACKET_TYPE_RST) ? \ - 0 : \ - VSockVmciSendControlPktBH(_dst, _src, VSOCK_PACKET_TYPE_RST, 0, \ - 0, NULL, VMCI_INVALID_HANDLE) -#define VSOCK_SEND_INVALID_BH(_dst, _src) \ - VSockVmciSendControlPktBH(_dst, _src, VSOCK_PACKET_TYPE_INVALID, 0, \ - 0, NULL, VMCI_INVALID_HANDLE) -#define VSOCK_SEND_WROTE_BH(_dst, _src) \ - VSockVmciSendControlPktBH(_dst, _src, VSOCK_PACKET_TYPE_WROTE, 0, \ - 0, NULL, VMCI_INVALID_HANDLE) -#define VSOCK_SEND_READ_BH(_dst, _src) \ - VSockVmciSendControlPktBH(_dst, _src, VSOCK_PACKET_TYPE_READ, 0, \ - 0, NULL, VMCI_INVALID_HANDLE) -#define VSOCK_SEND_RESET(_sk, _pkt) \ - ((_pkt)->type == VSOCK_PACKET_TYPE_RST) ? \ - 0 : \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_RST, \ - 0, 0, NULL, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_NEGOTIATE(_sk, _size) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE, \ - _size, 0, NULL, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_NEGOTIATE2(_sk, _size, signalProto) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE2, \ - _size, 0, NULL, signalProto, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_QP_OFFER(_sk, _handle) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_OFFER, \ - 0, 0, NULL, VSOCK_PROTO_INVALID, _handle) -#define VSOCK_SEND_CONN_REQUEST(_sk, _size) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST, \ - _size, 0, NULL, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_CONN_REQUEST2(_sk, _size, signalProto) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST2, \ - _size, 0, NULL, signalProto, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_ATTACH(_sk, _handle) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_ATTACH, \ - 0, 0, NULL, VSOCK_PROTO_INVALID, _handle) -#define VSOCK_SEND_WROTE(_sk) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WROTE, \ - 0, 0, NULL, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_READ(_sk) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_READ, \ - 0, 0, NULL, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_SHUTDOWN(_sk, _mode) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_SHUTDOWN, \ - 0, _mode, NULL, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_WAITING_WRITE(_sk, _waitInfo) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_WRITE, \ - 0, 0, _waitInfo, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_SEND_WAITING_READ(_sk, _waitInfo) \ - VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_READ, \ - 0, 0, _waitInfo, VSOCK_PROTO_INVALID, \ - VMCI_INVALID_HANDLE) -#define VSOCK_REPLY_RESET(_pkt) \ - VSockVmciReplyControlPktFast(_pkt, VSOCK_PACKET_TYPE_RST, \ - 0, 0, NULL, VMCI_INVALID_HANDLE) - -#endif /* __AF_VSOCK_H__ */ diff --git a/open-vm-tools/modules/linux/vsock/linux/notify.c b/open-vm-tools/modules/linux/vsock/linux/notify.c deleted file mode 100644 index 5b1e134c6..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/notify.c +++ /dev/null @@ -1,1212 +0,0 @@ -/********************************************************* - * Copyright (C) 2009-2014 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 - * - *********************************************************/ - -/* - * notify.c -- - * - * Linux control notifications for the VMCI Stream Sockets protocol. - */ - - -#include "driver-config.h" - -#include - -#include "compat_sock.h" - -#include "notify.h" -#include "af_vsock.h" - -#define PKT_FIELD(vsk, fieldName) \ - (vsk)->notify.pkt.fieldName - -#define VSOCK_MAX_DGRAM_RESENDS 10 - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyWaitingWrite -- - * - * Determines if the conditions have been met to notify a waiting writer. - * - * Results: - * TRUE if a notification should be sent, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk) // IN -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - Bool retval; - uint64 notifyLimit; - - if (!PKT_FIELD(vsk, peerWaitingWrite)) { - return FALSE; - } - -#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL - /* - * When the sender blocks, we take that as a sign that the sender - * is faster than the receiver. To reduce the transmit rate of the - * sender, we delay the sending of the read notification by - * decreasing the writeNotifyWindow. The notification is delayed - * until the number of bytes used in the queue drops below the - * writeNotifyWindow. - */ - - if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) { - PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE; - if (PKT_FIELD(vsk, writeNotifyWindow) < PAGE_SIZE) { - PKT_FIELD(vsk, writeNotifyWindow) = - PKT_FIELD(vsk, writeNotifyMinWindow); - } else { - PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE; - if (PKT_FIELD(vsk, writeNotifyWindow) < - PKT_FIELD(vsk, writeNotifyMinWindow)) { - PKT_FIELD(vsk, writeNotifyWindow) = - PKT_FIELD(vsk, writeNotifyMinWindow); - } - } - } - notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow); -#else - notifyLimit = 0; -#endif // VSOCK_OPTIMIZATION_FLOW_CONTROL - - /* - * For now we ignore the wait information and just see if the free - * space exceeds the notify limit. Note that improving this - * function to be more intelligent will not require a protocol - * change and will retain compatibility between endpoints with - * mixed versions of this function. - * - * The notifyLimit is used to delay notifications in the case where - * flow control is enabled. Below the test is expressed in terms of - * free space in the queue: - * if freeSpace > ConsumeSize - writeNotifyWindow then notify - * An alternate way of expressing this is to rewrite the expression - * to use the data ready in the receive queue: - * if writeNotifyWindow > bufferReady then notify - * as freeSpace == ConsumeSize - bufferReady. - */ - retval = vmci_qpair_consume_free_space(vsk->qpair) > notifyLimit; -#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL - if (retval) { - /* - * Once we notify the peer, we reset the detected flag so the - * next wait will again cause a decrease in the window size. - */ - - PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; - } -#endif // VSOCK_OPTIMIZATION_FLOW_CONTROL - return retval; -#else - return TRUE; -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyWaitingRead -- - * -v * Determines if the conditions have been met to notify a waiting reader. - * - * Results: - * TRUE if a notification should be sent, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciNotifyWaitingRead(VSockVmciSock *vsk) // IN -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - if (!PKT_FIELD(vsk, peerWaitingRead)) { - return FALSE; - } - - /* - * For now we ignore the wait information and just see if there is any data - * for our peer to read. Note that improving this function to be more intelligent will - * not require a protocol change and will retain compatibility between - * endpoints with mixed versions of this function. - */ - return vmci_qpair_produce_buf_ready(vsk->qpair) > 0; -#else - return TRUE; -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleWaitingRead -- - * - * Handles an incoming waiting read message. - * - * Results: - * None. - * - * Side effects: - * May send a notification to the peer, may update socket's wait info - * structure. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleWaitingRead(struct sock *sk, // IN - VSockPacket *pkt, // IN - Bool bottomHalf, // IN - struct sockaddr_vm *dst, // IN - struct sockaddr_vm *src) // IN -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, peerWaitingRead) = TRUE; - memcpy(&PKT_FIELD(vsk, peerWaitingReadInfo), &pkt->u.wait, - sizeof PKT_FIELD(vsk, peerWaitingReadInfo)); - - if (VSockVmciNotifyWaitingRead(vsk)) { - Bool sent; - - if (bottomHalf) { - sent = VSOCK_SEND_WROTE_BH(dst, src) > 0; - } else { - sent = VSOCK_SEND_WROTE(sk) > 0; - } - - if (sent) { - PKT_FIELD(vsk, peerWaitingRead) = FALSE; - } - } -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleWaitingWrite -- - * - * Handles an incoming waiting write message. - * - * Results: - * None. - * - * Side effects: - * May send a notification to the peer, may update socket's wait info - * structure. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleWaitingWrite(struct sock *sk, // IN - VSockPacket *pkt, // IN - Bool bottomHalf, // IN - struct sockaddr_vm *dst, // IN - struct sockaddr_vm *src) // IN -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, peerWaitingWrite) = TRUE; - memcpy(&PKT_FIELD(vsk, peerWaitingWriteInfo), &pkt->u.wait, - sizeof PKT_FIELD(vsk,peerWaitingWriteInfo)); - - if (VSockVmciNotifyWaitingWrite(vsk)) { - Bool sent; - - if (bottomHalf) { - sent = VSOCK_SEND_READ_BH(dst, src) > 0; - } else { - sent = VSOCK_SEND_READ(sk) > 0; - } - - if (sent) { - PKT_FIELD(vsk, peerWaitingWrite) = FALSE; - } - } -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleRead -- - * - * Handles an incoming read message. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleRead(struct sock *sk, // IN - VSockPacket *pkt, // IN: unused - Bool bottomHalf, // IN: unused - struct sockaddr_vm *dst, // IN: unused - struct sockaddr_vm *src) // IN: unused -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - PKT_FIELD(vsk, sentWaitingWrite) = FALSE; -#endif - - sk->sk_write_space(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSendWaitingRead -- - * - * Sends a waiting read notification to this socket's peer. - * - * Results: - * TRUE if the datagram is sent successfully, FALSE otherwise. - * - * Side effects: - * Our peer will notify us when there is data to read from our consume - * queue. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciSendWaitingRead(struct sock *sk, // IN - uint64 roomNeeded) // IN -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - VSockVmciSock *vsk; - VSockWaitingInfo waitingInfo; - uint64 tail; - uint64 head; - uint64 roomLeft; - Bool ret; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - if (PKT_FIELD(vsk, sentWaitingRead)) { - return TRUE; - } - - if (PKT_FIELD(vsk, writeNotifyWindow) < vsk->consumeSize) { - PKT_FIELD(vsk, writeNotifyWindow) = - MIN(PKT_FIELD(vsk, writeNotifyWindow) + PAGE_SIZE, - vsk->consumeSize); - } - - vmci_qpair_get_consume_indexes(vsk->qpair, &tail, &head); - roomLeft = vsk->consumeSize - head; - if (roomNeeded >= roomLeft) { - waitingInfo.offset = roomNeeded - roomLeft; - waitingInfo.generation = PKT_FIELD(vsk, consumeQGeneration) + 1; - } else { - waitingInfo.offset = head + roomNeeded; - waitingInfo.generation = PKT_FIELD(vsk, consumeQGeneration); - } - - ret = VSOCK_SEND_WAITING_READ(sk, &waitingInfo) > 0; - if (ret) { - PKT_FIELD(vsk, sentWaitingRead) = TRUE; - } - return ret; -#else - return TRUE; -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSendWaitingWrite -- - * - * Sends a waiting write notification to this socket's peer. - * - * Results: - * TRUE if the datagram is sent successfully or does not need to be sent. - * FALSE otherwise. - * - * Side effects: - * Our peer will notify us when there is room to write in to our produce - * queue. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciSendWaitingWrite(struct sock *sk, // IN - uint64 roomNeeded) // IN -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - VSockVmciSock *vsk; - VSockWaitingInfo waitingInfo; - uint64 tail; - uint64 head; - uint64 roomLeft; - Bool ret; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - if (PKT_FIELD(vsk, sentWaitingWrite)) { - return TRUE; - } - - vmci_qpair_get_produce_indexes(vsk->qpair, &tail, &head); - roomLeft = vsk->produceSize - tail; - if (roomNeeded + 1 >= roomLeft) { - /* Wraps around to current generation. */ - waitingInfo.offset = roomNeeded + 1 - roomLeft; - waitingInfo.generation = PKT_FIELD(vsk, produceQGeneration); - } else { - waitingInfo.offset = tail + roomNeeded + 1; - waitingInfo.generation = PKT_FIELD(vsk, produceQGeneration) - 1; - } - - ret = VSOCK_SEND_WAITING_WRITE(sk, &waitingInfo) > 0; - if (ret) { - PKT_FIELD(vsk, sentWaitingWrite) = TRUE; - } - return ret; -#else - return TRUE; -#endif -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSendReadNotification -- - * - * Sends a read notification to this socket's peer. - * - * Results: - * >= 0 if the datagram is sent successfully, negative error value - * otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciSendReadNotification(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - Bool sentRead; - unsigned int retries; - int err; - - ASSERT(sk); - - vsk = vsock_sk(sk); - sentRead = FALSE; - retries = 0; - err = 0; - - if (VSockVmciNotifyWaitingWrite(vsk)) { - /* - * Notify the peer that we have read, retrying the send on failure up to our - * maximum value. XXX For now we just log the failure, but later we should - * schedule a work item to handle the resend until it succeeds. That would - * require keeping track of work items in the vsk and cleaning them up upon - * socket close. - */ - while (!(vsk->peerShutdown & RCV_SHUTDOWN) && - !sentRead && - retries < VSOCK_MAX_DGRAM_RESENDS) { - err = VSOCK_SEND_READ(sk); - if (err >= 0) { - sentRead = TRUE; - } - - retries++; - } - - if (retries >= VSOCK_MAX_DGRAM_RESENDS) { - Warning("unable to send read notification to peer for socket %p.\n", sk); - } else { -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - PKT_FIELD(vsk, peerWaitingWrite) = FALSE; -#endif - } - } - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleWrote -- - * - * Handles an incoming wrote message. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleWrote(struct sock *sk, // IN - VSockPacket *pkt, // IN: unused - Bool bottomHalf, // IN: unused - struct sockaddr_vm *dst, // IN: unused - struct sockaddr_vm *src) // IN: unused -{ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - PKT_FIELD(vsk, sentWaitingRead) = FALSE; -#endif - - sk->sk_data_ready(sk, 0); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSocketInit -- - * - * Function that is called after a socket is created and before any - * notify ops are used. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktSocketInit(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = PAGE_SIZE; - PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE; - PKT_FIELD(vsk, peerWaitingRead) = FALSE; - PKT_FIELD(vsk, peerWaitingWrite) = FALSE; - PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; - PKT_FIELD(vsk, sentWaitingRead) = FALSE; - PKT_FIELD(vsk, sentWaitingWrite) = FALSE; - PKT_FIELD(vsk, produceQGeneration) = 0; - PKT_FIELD(vsk, consumeQGeneration) = 0; - - memset(&PKT_FIELD(vsk, peerWaitingReadInfo), 0, - sizeof PKT_FIELD(vsk, peerWaitingReadInfo)); - memset(&PKT_FIELD(vsk, peerWaitingWriteInfo), 0, - sizeof PKT_FIELD(vsk, peerWaitingWriteInfo)); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSocketDestruct -- - * - * Function that is called when the socket is being released. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktSocketDestruct(struct sock *sk) // IN -{ - return; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktPollIn -- - * - * Called by the poll function to figure out if there is data to read - * and to setup future notifications if needed. Only called on sockets - * that aren't shutdown for recv. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktPollIn(struct sock *sk, // IN - size_t target, // IN - Bool *dataReadyNow) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(dataReadyNow); - - vsk = vsock_sk(sk); - - if (VSockVmciStreamHasData(vsk)) { - *dataReadyNow = TRUE; - } else { - /* - * We can't read right now because there is nothing in the queue. - * Ask for notifications when there is something to read. - */ - if (sk->sk_state == SS_CONNECTED) { - if (!VSockVmciSendWaitingRead(sk, 1)) { - return -1; - } - } - *dataReadyNow = FALSE; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktPollOut - * - * Called by the poll function to figure out if there is space to write - * and to setup future notifications if needed. Only called on a - * connected socket that isn't shutdown for send. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktPollOut(struct sock *sk, // IN - size_t target, // IN - Bool *spaceAvailNow) // IN -{ - int64 produceQFreeSpace; - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(spaceAvailNow); - - vsk = vsock_sk(sk); - - produceQFreeSpace = - VSockVmciStreamHasSpace(vsk); - if (produceQFreeSpace > 0) { - *spaceAvailNow = TRUE; - return 0; - } else if (produceQFreeSpace == 0) { - /* - * This is a connected socket but we can't currently send data. Notify - * the peer that we are waiting if the queue is full. - * We only send a waiting write if the queue is full because otherwise - * we end up in an infinite WAITING_WRITE, READ, WAITING_WRITE, READ, etc. - * loop. Treat failing to send the notification as a socket error, passing - * that back through the mask. - */ - if (!VSockVmciSendWaitingWrite(sk, 1)) { - return -1; - } - *spaceAvailNow = FALSE; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvInit -- - * - * Called at the start of a stream recv call with the socket lock held. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvInit(struct sock *sk, // IN - size_t target, // IN - VSockVmciRecvNotifyData *data) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - -#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY - data->consumeHead = 0; - data->produceTail = 0; -#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL - data->notifyOnBlock = FALSE; - - if (PKT_FIELD(vsk, writeNotifyMinWindow) < target + 1) { - ASSERT(target < vsk->consumeSize); - PKT_FIELD(vsk, writeNotifyMinWindow) = target + 1; - if (PKT_FIELD(vsk, writeNotifyWindow) < - PKT_FIELD(vsk, writeNotifyMinWindow)) { - /* - * If the current window is smaller than the new minimal - * window size, we need to reevaluate whether we need to - * notify the sender. If the number of ready bytes are - * smaller than the new window, we need to send a - * notification to the sender before we block. - */ - - PKT_FIELD(vsk, writeNotifyWindow) = - PKT_FIELD(vsk, writeNotifyMinWindow); - data->notifyOnBlock = TRUE; - } - } -#endif -#endif - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvPreBlock -- - * - * Called right before a socket is about to block with the socket lock - * held. The socket lock may have been released between the entry - * function and the preblock call. - * - * Note: This function may be called multiple times before the post - * block function is called. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvPreBlock(struct sock *sk, // IN - size_t target, // IN - VSockVmciRecvNotifyData *data) // IN -{ - int err; - - ASSERT(sk); - ASSERT(data); - - err = 0; - - /* Notify our peer that we are waiting for data to read. */ - if (!VSockVmciSendWaitingRead(sk, target)) { - err = -EHOSTUNREACH; - return err; - } - -#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL - if (data->notifyOnBlock) { - err = VSockVmciSendReadNotification(sk); - if (err < 0) { - return err; - } - data->notifyOnBlock = FALSE; - } -#endif - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvPreDequeue -- - * - * Called right before we dequeue / peek data from a socket. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvPreDequeue(struct sock *sk, // IN - size_t target, // IN - VSockVmciRecvNotifyData *data) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - - /* - * Now consume up to len bytes from the queue. Note that since we have the - * socket locked we should copy at least ready bytes. - */ -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - vmci_qpair_get_consume_indexes(vsk->qpair, - &data->produceTail, - &data->consumeHead); -#endif - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvPostDequeue -- - * - * Called right after we dequeue / peek data from a socket. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvPostDequeue(struct sock *sk, // IN - size_t target, // IN - ssize_t copied, // IN - Bool dataRead, // IN - VSockVmciRecvNotifyData *data) // IN -{ - VSockVmciSock *vsk; - int err; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - err = 0; - - if (dataRead) { -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - /* - * Detect a wrap-around to maintain queue generation. Note that this is - * safe since we hold the socket lock across the two queue pair - * operations. - */ - if (copied >= vsk->consumeSize - data->consumeHead) { - PKT_FIELD(vsk, consumeQGeneration)++; - } -#endif - - err = VSockVmciSendReadNotification(sk); - if (err < 0) { - return err; - } - - } - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSendInit -- - * - * Called at the start of a stream send call with the socket lock held. - * - * Results: - * 0 on success. A negative error code on failure. - * - * Side effects: - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktSendInit(struct sock *sk, // IN - VSockVmciSendNotifyData *data) // IN -{ - ASSERT(sk); - ASSERT(data); - -#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY - data->consumeHead = 0; - data->produceTail = 0; -#endif - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSendPreBlock -- - * - * Called right before a socket is about to block with the socket lock - * held. The socket lock may have been released between the entry - * function and the preblock call. - * - * Note: This function may be called multiple times before the post - * block function is called. - * - * Results. - * 0 on success. A negative error code on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktSendPreBlock(struct sock *sk, // IN - VSockVmciSendNotifyData *data) // IN -{ - ASSERT(sk); - ASSERT(data); - - /* Notify our peer that we are waiting for room to write. */ - if (!VSockVmciSendWaitingWrite(sk, 1)) { - return -EHOSTUNREACH; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifySendPreEnqueue -- - * - * Called right before we Enqueue to a socket. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktSendPreEnqueue(struct sock *sk, // IN - VSockVmciSendNotifyData *data) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - vmci_qpair_get_produce_indexes(vsk->qpair, - &data->produceTail, - &data->consumeHead); -#endif - - return 0;; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifySendPostEnqueue -- - * - * Called right after we enqueue data to a socket. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktSendPostEnqueue(struct sock *sk, // IN - ssize_t written, // IN - VSockVmciSendNotifyData *data) // IN -{ - int err = 0; - VSockVmciSock *vsk; - Bool sentWrote = FALSE; - int retries = 0; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - /* - * Detect a wrap-around to maintain queue generation. Note that this is - * safe since we hold the socket lock across the two queue pair - * operations. - */ - if (written >= vsk->produceSize - data->produceTail) { - PKT_FIELD(vsk, produceQGeneration)++; - } -#endif - - if (VSockVmciNotifyWaitingRead(vsk)) { - /* - * Notify the peer that we have written, retrying the send on failure up to - * our maximum value. See the XXX comment for the corresponding piece of - * code in StreamRecvmsg() for potential improvements. - */ - while (!(vsk->peerShutdown & RCV_SHUTDOWN) && - !sentWrote && - retries < VSOCK_MAX_DGRAM_RESENDS) { - err = VSOCK_SEND_WROTE(sk); - if (err >= 0) { - sentWrote = TRUE; - } - - retries++; - } - - if (retries >= VSOCK_MAX_DGRAM_RESENDS) { - Warning("unable to send wrote notification to peer for socket %p.\n", sk); - return err; - } else { -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) - PKT_FIELD(vsk, peerWaitingRead) = FALSE; -#endif - } - } - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktHandlePkt - * - * Called when a notify packet is recieved for a socket in the connected - * state. Note this might be called from a bottom half. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktHandlePkt(struct sock *sk, // IN - VSockPacket *pkt, // IN - Bool bottomHalf, // IN - struct sockaddr_vm *dst, // IN - struct sockaddr_vm *src, // IN - Bool *pktProcessed) // In -{ - Bool processed = FALSE; - - ASSERT(sk); - ASSERT(pkt); - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_WROTE: - VSockVmciHandleWrote(sk, pkt, bottomHalf, dst, src); - processed = TRUE; - break; - case VSOCK_PACKET_TYPE_READ: - VSockVmciHandleRead(sk, pkt, bottomHalf, dst, src); - processed = TRUE; - break; - case VSOCK_PACKET_TYPE_WAITING_WRITE: - VSockVmciHandleWaitingWrite(sk, pkt, bottomHalf, dst, src); - processed = TRUE; - break; - - case VSOCK_PACKET_TYPE_WAITING_READ: - VSockVmciHandleWaitingRead(sk, pkt, bottomHalf, dst, src); - processed = TRUE; - break; - } - - if (pktProcessed) { - *pktProcessed = processed; - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktProcessRequest - * - * Called near the end of process request. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; - if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) { - PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize; - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktProcessNegotiate - * - * Called near the end of process negotiate. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; - if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) { - PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize; - } -} - - -/* Socket control packet based operations. */ -VSockVmciNotifyOps vSockVmciNotifyPktOps = { - VSockVmciNotifyPktSocketInit, - VSockVmciNotifyPktSocketDestruct, - VSockVmciNotifyPktPollIn, - VSockVmciNotifyPktPollOut, - VSockVmciNotifyPktHandlePkt, - VSockVmciNotifyPktRecvInit, - VSockVmciNotifyPktRecvPreBlock, - VSockVmciNotifyPktRecvPreDequeue, - VSockVmciNotifyPktRecvPostDequeue, - VSockVmciNotifyPktSendInit, - VSockVmciNotifyPktSendPreBlock, - VSockVmciNotifyPktSendPreEnqueue, - VSockVmciNotifyPktSendPostEnqueue, - VSockVmciNotifyPktProcessRequest, - VSockVmciNotifyPktProcessNegotiate, -}; diff --git a/open-vm-tools/modules/linux/vsock/linux/notify.h b/open-vm-tools/modules/linux/vsock/linux/notify.h deleted file mode 100644 index 0da29b9e8..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/notify.h +++ /dev/null @@ -1,129 +0,0 @@ -/********************************************************* - * Copyright (C) 2009-2014 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 - * - *********************************************************/ - -/* - * notify.h -- - * - * Notify functions for Linux VSocket module. - */ - -#ifndef __NOTIFY_H__ -#define __NOTIFY_H__ - -#include "driver-config.h" -#include "vsockCommon.h" -#include "vsockPacket.h" - -/* Comment this out to compare with old protocol. */ -#define VSOCK_OPTIMIZATION_WAITING_NOTIFY 1 -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) -/* Comment this out to remove flow control for "new" protocol */ -# define VSOCK_OPTIMIZATION_FLOW_CONTROL 1 -#endif - -#define VSOCK_MAX_DGRAM_RESENDS 10 - -#define NOTIFYCALLRET(vsk, rv, mod_fn, args...) \ -do { \ - if (vsk->notifyOps && \ - vsk->notifyOps->mod_fn != NULL) { \ - rv = (vsk->notifyOps->mod_fn)(args); \ - } else { \ - rv = 0; \ - } \ -} while (0) - -#define NOTIFYCALL(vsk, mod_fn, args...) \ -do { \ - if (vsk->notifyOps && \ - vsk->notifyOps->mod_fn != NULL) { \ - (vsk->notifyOps->mod_fn)(args); \ - } \ -} while (0) - -typedef struct VSockVmciNotifyPkt { - uint64 writeNotifyWindow; - uint64 writeNotifyMinWindow; - Bool peerWaitingRead; - Bool peerWaitingWrite; - Bool peerWaitingWriteDetected; - Bool sentWaitingRead; - Bool sentWaitingWrite; - VSockWaitingInfo peerWaitingReadInfo; - VSockWaitingInfo peerWaitingWriteInfo; - uint64 produceQGeneration; - uint64 consumeQGeneration; -} VSockVmciNotifyPkt; - -typedef struct VSockVmciNotifyPktQState { - uint64 writeNotifyWindow; - uint64 writeNotifyMinWindow; - Bool peerWaitingWrite; - Bool peerWaitingWriteDetected; -} VSockVmciNotifyPktQState; - -typedef union VSockVmciNotify { - VSockVmciNotifyPkt pkt; - VSockVmciNotifyPktQState pktQState; -} VSockVmciNotify; - -typedef struct VSockVmciRecvNotifyData { - uint64 consumeHead; - uint64 produceTail; - Bool notifyOnBlock; -} VSockVmciRecvNotifyData; - -typedef struct VSockVmciSendNotifyData { - uint64 consumeHead; - uint64 produceTail; -} VSockVmciSendNotifyData; - -/* Socket notification callbacks. */ -typedef struct VSockVmciNotifyOps { - void (*socketInit)(struct sock *sk); - void (*socketDestruct)(struct sock *sk); - int32 (*pollIn)(struct sock *sk, size_t target, Bool *dataReadyNow); - int32 (*pollOut)(struct sock *sk, size_t target, Bool *spaceAvailNow); - void (*handleNotifyPkt)(struct sock *sk, VSockPacket *pkt, - Bool bottomHalf, struct sockaddr_vm *dst, - struct sockaddr_vm *src, Bool *pktProcessed); - int32 (*recvInit)(struct sock *sk, size_t target, - VSockVmciRecvNotifyData *data); - int32 (*recvPreBlock)(struct sock *sk, size_t target, - VSockVmciRecvNotifyData *data); - int32 (*recvPreDequeue)(struct sock *sk, size_t target, - VSockVmciRecvNotifyData *data); - int32 (*recvPostDequeue)(struct sock *sk, size_t target, ssize_t copied, - Bool dataRead, VSockVmciRecvNotifyData *data); - int32 (*sendInit)(struct sock *sk, - VSockVmciSendNotifyData *data); - int32 (*sendPreBlock)(struct sock *sk, - VSockVmciSendNotifyData *data); - int32 (*sendPreEnqueue)(struct sock *sk, - VSockVmciSendNotifyData *data); - int32 (*sendPostEnqueue)(struct sock *sk, - ssize_t written, - VSockVmciSendNotifyData *data); - void (*processRequest)(struct sock *sk); - void (*processNegotiate)(struct sock *sk); -} VSockVmciNotifyOps; - -extern VSockVmciNotifyOps vSockVmciNotifyPktOps; -extern VSockVmciNotifyOps vSockVmciNotifyPktQStateOps; - -#endif /* __NOTIFY_H__ */ diff --git a/open-vm-tools/modules/linux/vsock/linux/notifyQState.c b/open-vm-tools/modules/linux/vsock/linux/notifyQState.c deleted file mode 100644 index 7231f2662..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/notifyQState.c +++ /dev/null @@ -1,791 +0,0 @@ -/********************************************************* - * Copyright (C) 2009-2014,2017 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 - * - *********************************************************/ - -/* - * notifyQState.c -- - * - * Linux control notifications based on Queuepair state for the VMCI - * Stream Sockets protocol. - */ - - -#include "driver-config.h" - -#include - -#include "compat_sock.h" - -#include "notify.h" -#include "af_vsock.h" - -#define PKT_FIELD(vsk, fieldName) \ - (vsk)->notify.pktQState.fieldName - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyWaitingWrite -- - * - * Determines if the conditions have been met to notify a waiting writer. - * - * Results: - * TRUE if a notification should be sent, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk) // IN -{ - Bool retval; - uint64 notifyLimit; - - if (!PKT_FIELD(vsk, peerWaitingWrite)) { - return FALSE; - } - - /* - * When the sender blocks, we take that as a sign that the sender - * is faster than the receiver. To reduce the transmit rate of the - * sender, we delay the sending of the read notification by - * decreasing the writeNotifyWindow. The notification is delayed - * until the number of bytes used in the queue drops below the - * writeNotifyWindow. - */ - - if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) { - PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE; - if (PKT_FIELD(vsk, writeNotifyWindow) < PAGE_SIZE) { - PKT_FIELD(vsk, writeNotifyWindow) = - PKT_FIELD(vsk, writeNotifyMinWindow); - } else { - PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE; - if (PKT_FIELD(vsk, writeNotifyWindow) < - PKT_FIELD(vsk, writeNotifyMinWindow)) { - PKT_FIELD(vsk, writeNotifyWindow) = - PKT_FIELD(vsk, writeNotifyMinWindow); - } - } - } - notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow); - - /* - * The notifyLimit is used to delay notifications in the case where - * flow control is enabled. Below the test is expressed in terms of - * free space in the queue: - * if freeSpace > ConsumeSize - writeNotifyWindow then notify - * An alternate way of expressing this is to rewrite the expression - * to use the data ready in the receive queue: - * if writeNotifyWindow > bufferReady then notify - * as freeSpace == ConsumeSize - bufferReady. - */ - - retval = vmci_qpair_consume_free_space(vsk->qpair) > notifyLimit; - - if (retval) { - /* - * Once we notify the peer, we reset the detected flag so the - * next wait will again cause a decrease in the window size. - */ - - PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; - } - return retval; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleRead -- - * - * Handles an incoming read message. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleRead(struct sock *sk, // IN - VSockPacket *pkt, // IN: unused - Bool bottomHalf, // IN: unused - struct sockaddr_vm *dst, // IN: unused - struct sockaddr_vm *src) // IN: unused -{ - - sk->sk_write_space(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciHandleWrote -- - * - * Handles an incoming wrote message. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciHandleWrote(struct sock *sk, // IN - VSockPacket *pkt, // IN: unused - Bool bottomHalf, // IN: unused - struct sockaddr_vm *dst, // IN: unused - struct sockaddr_vm *src) // IN: unused -{ - sk->sk_data_ready(sk, 0); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciBlockUpdateWriteWindow -- - * - * Updates the write window when we are blocking for data. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciBlockUpdateWriteWindow(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - vsk = vsock_sk(sk); - - if (PKT_FIELD(vsk, writeNotifyWindow) < vsk->consumeSize) { - PKT_FIELD(vsk, writeNotifyWindow) = - MIN(PKT_FIELD(vsk, writeNotifyWindow) + PAGE_SIZE, - vsk->consumeSize); - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciSendReadNotification -- - * - * Sends a read notification to this socket's peer. - * - * Results: - * >= 0 if the datagram is sent successfully, negative error value - * otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int -VSockVmciSendReadNotification(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - Bool sentRead; - unsigned int retries; - int err; - - ASSERT(sk); - - vsk = vsock_sk(sk); - sentRead = FALSE; - retries = 0; - err = 0; - - if (VSockVmciNotifyWaitingWrite(vsk)) { - /* - * Notify the peer that we have read, retrying the send on failure up to our - * maximum value. XXX For now we just log the failure, but later we should - * schedule a work item to handle the resend until it succeeds. That would - * require keeping track of work items in the vsk and cleaning them up upon - * socket close. - */ - while (!(vsk->peerShutdown & RCV_SHUTDOWN) && - !sentRead && - retries < VSOCK_MAX_DGRAM_RESENDS) { - err = VSOCK_SEND_READ(sk); - if (err >= 0) { - sentRead = TRUE; - } - - retries++; - } - - if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentRead) { - Warning("unable to send read notification to peer for socket %p.\n", sk); - } else { - PKT_FIELD(vsk, peerWaitingWrite) = FALSE; - } - } - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSocketInit -- - * - * Function that is called after a socket is created and before any - * notify ops are used. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktSocketInit(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = PAGE_SIZE; - PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE; - PKT_FIELD(vsk, peerWaitingWrite) = FALSE; - PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSocketDestruct -- - * - * Function that is called when the socket is being released. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktSocketDestruct(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = PAGE_SIZE; - PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE; - PKT_FIELD(vsk, peerWaitingWrite) = FALSE; - PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktPollIn -- - * - * Called by the poll function to figure out if there is data to read - * and to setup future notifications if needed. Only called on sockets - * that aren't shutdown for recv. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktPollIn(struct sock *sk, // IN - size_t target, // IN - Bool *dataReadyNow) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(dataReadyNow); - - vsk = vsock_sk(sk); - - if (VSockVmciStreamHasData(vsk)) { - *dataReadyNow = TRUE; - } else { - /* - * We can't read right now because there is nothing in the queue. - * Ask for notifications when there is something to read. - */ - if (sk->sk_state == SS_CONNECTED) { - VSockVmciBlockUpdateWriteWindow(sk); - } - *dataReadyNow = FALSE; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktPollOut - * - * Called by the poll function to figure out if there is space to write - * and to setup future notifications if needed. Only called on a - * connected socket that isn't shutdown for send. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktPollOut(struct sock *sk, // IN - size_t target, // IN - Bool *spaceAvailNow) // IN -{ - int64 produceQFreeSpace; - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(spaceAvailNow); - - vsk = vsock_sk(sk); - - produceQFreeSpace = - VSockVmciStreamHasSpace(vsk); - if (produceQFreeSpace > 0) { - *spaceAvailNow = TRUE; - return 0; - } else if (produceQFreeSpace == 0) { - /* - * This is a connected socket but we can't currently send data. Nothing - * else to do. - */ - *spaceAvailNow = FALSE; - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvInit -- - * - * Called at the start of a stream recv call with the socket lock held. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvInit(struct sock *sk, // IN - size_t target, // IN - VSockVmciRecvNotifyData *data) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - - data->consumeHead = 0; - data->produceTail = 0; - data->notifyOnBlock = FALSE; - - if (PKT_FIELD(vsk, writeNotifyMinWindow) < target + 1) { - ASSERT(target < vsk->consumeSize); - PKT_FIELD(vsk, writeNotifyMinWindow) = target + 1; - if (PKT_FIELD(vsk, writeNotifyWindow) < - PKT_FIELD(vsk, writeNotifyMinWindow)) { - /* - * If the current window is smaller than the new minimal - * window size, we need to reevaluate whether we need to - * notify the sender. If the number of ready bytes are - * smaller than the new window, we need to send a - * notification to the sender before we block. - */ - - PKT_FIELD(vsk, writeNotifyWindow) = - PKT_FIELD(vsk, writeNotifyMinWindow); - data->notifyOnBlock = TRUE; - } - } - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvPreBlock -- - * - * Called right before a socket is about to block with the socket lock - * held. The socket lock may have been released between the entry - * function and the preblock call. - * - * Note: This function may be called multiple times before the post - * block function is called. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvPreBlock(struct sock *sk, // IN - size_t target, // IN - VSockVmciRecvNotifyData *data) // IN -{ - int err; - - ASSERT(sk); - ASSERT(data); - - err = 0; - - VSockVmciBlockUpdateWriteWindow(sk); - - if (data->notifyOnBlock) { - err = VSockVmciSendReadNotification(sk); - if (err < 0) { - return err; - } - data->notifyOnBlock = FALSE; - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktRecvPostDequeue -- - * - * Called right after we dequeue / peek data from a socket. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktRecvPostDequeue(struct sock *sk, // IN - size_t target, // IN - ssize_t copied, // IN - Bool dataRead, // IN - VSockVmciRecvNotifyData *data) // IN -{ - VSockVmciSock *vsk; - int err; - Bool wasFull = FALSE; - uint64 freeSpace; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - err = 0; - - if (dataRead) { - SMP_RW_BARRIER_RW(); - - freeSpace = vmci_qpair_consume_free_space(vsk->qpair); - wasFull = freeSpace == copied; - - if (wasFull) { - PKT_FIELD(vsk, peerWaitingWrite) = TRUE; - } - - err = VSockVmciSendReadNotification(sk); - if (err < 0) { - return err; - } - - /* See the comment in VSockVmciNotifyPktSendPostEnqueue */ - sk->sk_data_ready(sk, 0); - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktSendInit -- - * - * Called at the start of a stream send call with the socket lock held. - * - * Results: - * 0 on success. A negative error code on failure. - * - * Side effects: - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktSendInit(struct sock *sk, // IN - VSockVmciSendNotifyData *data) // IN -{ - ASSERT(sk); - ASSERT(data); - - data->consumeHead = 0; - data->produceTail = 0; - - return 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifySendPostEnqueue -- - * - * Called right after we enqueue data to a socket. - * - * Results: - * 0 on success. Negative error on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static int32 -VSockVmciNotifyPktSendPostEnqueue(struct sock *sk, // IN - ssize_t written, // IN - VSockVmciSendNotifyData *data) // IN -{ - int err = 0; - VSockVmciSock *vsk; - Bool sentWrote = FALSE; - Bool wasEmpty; - - int retries = 0; - - ASSERT(sk); - ASSERT(data); - - vsk = vsock_sk(sk); - - SMP_RW_BARRIER_RW(); - - wasEmpty = (vmci_qpair_produce_buf_ready(vsk->qpair) == written); - if (wasEmpty) { - while (!(vsk->peerShutdown & RCV_SHUTDOWN) && - !sentWrote && - retries < VSOCK_MAX_DGRAM_RESENDS) { - err = VSOCK_SEND_WROTE(sk); - if (err >= 0) { - sentWrote = TRUE; - } - - retries++; - } - } - - if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentWrote) { - Warning("unable to send wrote notification to peer for socket %p.\n", sk); - return err; - } - - return err; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktHandlePkt - * - * Called when a notify packet is recieved for a socket in the connected - * state. Note this might be called from a bottom half. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktHandlePkt(struct sock *sk, // IN - VSockPacket *pkt, // IN - Bool bottomHalf, // IN - struct sockaddr_vm *dst, // IN - struct sockaddr_vm *src, // IN - Bool *pktProcessed) // In -{ - Bool processed = FALSE; - - ASSERT(sk); - ASSERT(pkt); - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_WROTE: - VSockVmciHandleWrote(sk, pkt, bottomHalf, dst, src); - processed = TRUE; - break; - case VSOCK_PACKET_TYPE_READ: - VSockVmciHandleRead(sk, pkt, bottomHalf, dst, src); - processed = TRUE; - break; - } - - if (pktProcessed) { - *pktProcessed = processed; - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktProcessRequest - * - * Called near the end of process request. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; - if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) { - PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize; - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciNotifyPktProcessNegotiate - * - * Called near the end of process negotiate. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; - if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) { - PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize; - } -} - - -/* Socket always on control packet based operations. */ -VSockVmciNotifyOps vSockVmciNotifyPktQStateOps = { - VSockVmciNotifyPktSocketInit, - VSockVmciNotifyPktSocketDestruct, - VSockVmciNotifyPktPollIn, - VSockVmciNotifyPktPollOut, - VSockVmciNotifyPktHandlePkt, - VSockVmciNotifyPktRecvInit, - VSockVmciNotifyPktRecvPreBlock, - NULL, /* recvPreDequeue */ - VSockVmciNotifyPktRecvPostDequeue, - VSockVmciNotifyPktSendInit, - NULL, /* sendPreBlock */ - NULL, /* sendPreEnqueue */ - VSockVmciNotifyPktSendPostEnqueue, - VSockVmciNotifyPktProcessRequest, - VSockVmciNotifyPktProcessNegotiate, -}; diff --git a/open-vm-tools/modules/linux/vsock/linux/stats.c b/open-vm-tools/modules/linux/vsock/linux/stats.c deleted file mode 100644 index f17b4b6df..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/stats.c +++ /dev/null @@ -1,39 +0,0 @@ -/********************************************************* - * Copyright (C) 2009 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 - * - *********************************************************/ - -/* - * stats.c -- - * - * Linux stats for the VMCI Stream Sockets protocol. - */ - -#include "driver-config.h" - -#include -#include "compat_sock.h" - -#include "af_vsock.h" -#include "stats.h" - -#ifdef VSOCK_GATHER_STATISTICS -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 --git a/open-vm-tools/modules/linux/vsock/linux/stats.h b/open-vm-tools/modules/linux/vsock/linux/stats.h deleted file mode 100644 index c42f57579..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/stats.h +++ /dev/null @@ -1,263 +0,0 @@ -/********************************************************* - * Copyright (C) 2009 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 - * - *********************************************************/ - -/* - * stats.h -- - * - * Stats functions for Linux vsock module. - */ - -#ifndef __STATS_H__ -#define __STATS_H__ - -#include "driver-config.h" - -#include "vm_basic_math.h" - -#include "vsockCommon.h" -#include "vsockPacket.h" - - -/* - * Define VSOCK_GATHER_STATISTICS to turn on statistics gathering. - * 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 - -#ifdef VSOCK_GATHER_STATISTICS - -#define VSOCK_NUM_QUEUE_LEVEL_BUCKETS 10 -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)->qpair, \ - (vsk)->consumeSize, \ - VMCIQPair_ConsumeBufReady((vsk)->qpair), \ - vSockStatsConsumeQueueHist) -#define VSOCK_STATS_STREAM_PRODUCE_HIST(vsk) \ - VSockVmciStatsUpdateQueueBucketCount((vsk)->qpair, \ - (vsk)->produceSize, \ - VMCIQPair_ProduceBufReady((vsk)->qpair), \ - vSockStatsProduceQueueHist) -#define VSOCK_STATS_CTLPKT_LOG(pktType) \ - do { \ - ++vSockStatsCtlPktCount[pktType]; \ - } while (0) -#define VSOCK_STATS_STREAM_CONSUME(bytes) \ - Atomic_ReadAdd64(&vSockStatsConsumeTotal, bytes) -#define VSOCK_STATS_STREAM_PRODUCE(bytes) \ - Atomic_ReadAdd64(&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() - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStatsUpdateQueueBucketCount -- - * - * Given a queue, determine how much data is enqueued and add that to - * the specified queue level statistic bucket. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciStatsUpdateQueueBucketCount(VMCIQPair *qpair, // IN - uint64 queueSize, // IN - uint64 dataReady, // IN - uint64 queueHist[]) // IN/OUT -{ - uint64 bucket = 0; - uint32 remainder = 0; - - 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 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]; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStatsCtlPktDumpAll -- - * - * Prints all stream control packet counts out to the console using - * the appropriate platform logging. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciStatsCtlPktDumpAll(void) -{ - uint32 index; - - ASSERT_ON_COMPILE(VSOCK_PACKET_TYPE_MAX == - ARRAYSIZE(vSockStatsCtlPktCount)); - - for (index = 0; index < ARRAYSIZE(vSockStatsCtlPktCount); index++) { - Warning("Control packet count: Type = %u, Count = %"FMT64"u\n", - index, vSockStatsCtlPktCount[index]); - } -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciStatsHistDumpAll -- - * - * Prints the produce and consume queue histograms to the console. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciStatsHistDumpAll(void) -{ - uint32 index; - - #define VSOCK_DUMP_HIST(strname, name) do { \ - for (index = 0; index < ARRAYSIZE(name); index++) { \ - Warning(strname " Bucket count %u = %"FMT64"u\n", \ - index, name[index]); \ - } \ - } while (0) - - VSOCK_DUMP_HIST("Produce Queue", vSockStatsProduceQueueHist); - VSOCK_DUMP_HIST("Consume Queue", vSockStatsConsumeQueueHist); - - #undef VSOCK_DUMP_HIST -} - - -/* - *---------------------------------------------------------------------------- - * - * 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. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciStatsReset(void) -{ - uint32 index; - - #define VSOCK_RESET_ARRAY(name) do { \ - for (index = 0; index < ARRAYSIZE(name); index++) { \ - name[index] = 0; \ - } \ - } while (0) - - VSOCK_RESET_ARRAY(vSockStatsCtlPktCount); - VSOCK_RESET_ARRAY(vSockStatsProduceQueueHist); - 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 - -#endif // __STATS_H__ diff --git a/open-vm-tools/modules/linux/vsock/linux/util.c b/open-vm-tools/modules/linux/vsock/linux/util.c deleted file mode 100644 index e4321f96e..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/util.c +++ /dev/null @@ -1,849 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - - -/* - * util.c -- - * - * Utility functions for Linux VSocket module. - */ - -#include "driver-config.h" -#include -#include -#include "compat_sock.h" - -#include "af_vsock.h" -#include "util.h" - -struct list_head vsockBindTable[VSOCK_HASH_SIZE + 1]; -struct list_head vsockConnectedTable[VSOCK_HASH_SIZE]; - -DEFINE_SPINLOCK(vsockTableLock); - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciLogPkt -- - * - * Logs the provided packet. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciLogPkt(char const *function, // IN - uint32 line, // IN - VSockPacket *pkt) // IN -{ - char buf[256]; - char *cur = buf; - int left = sizeof buf; - int written = 0; - char *typeStrings[] = { - [VSOCK_PACKET_TYPE_INVALID] = "INVALID", - [VSOCK_PACKET_TYPE_REQUEST] = "REQUEST", - [VSOCK_PACKET_TYPE_NEGOTIATE] = "NEGOTIATE", - [VSOCK_PACKET_TYPE_OFFER] = "OFFER", - [VSOCK_PACKET_TYPE_ATTACH] = "ATTACH", - [VSOCK_PACKET_TYPE_WROTE] = "WROTE", - [VSOCK_PACKET_TYPE_READ] = "READ", - [VSOCK_PACKET_TYPE_RST] = "RST", - [VSOCK_PACKET_TYPE_SHUTDOWN] = "SHUTDOWN", - [VSOCK_PACKET_TYPE_WAITING_WRITE] = "WAITING_WRITE", - [VSOCK_PACKET_TYPE_WAITING_READ] = "WAITING_READ", - [VSOCK_PACKET_TYPE_REQUEST2] = "REQUEST2", - [VSOCK_PACKET_TYPE_NEGOTIATE2] = "NEGOTIATE2", - }; - - written = snprintf(cur, left, "PKT: %u:%u -> %u:%u", - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src), - pkt->srcPort, - VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst), - pkt->dstPort); - if (written >= left) { - goto error; - } - - left -= written; - cur += written; - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_REQUEST: - case VSOCK_PACKET_TYPE_NEGOTIATE: - written = snprintf(cur, left, ", %s, size = %"FMT64"u", - typeStrings[pkt->type], pkt->u.size); - break; - - case VSOCK_PACKET_TYPE_OFFER: - case VSOCK_PACKET_TYPE_ATTACH: - written = snprintf(cur, left, ", %s, handle = %u:%u", - typeStrings[pkt->type], - VMCI_HANDLE_TO_CONTEXT_ID(pkt->u.handle), - VMCI_HANDLE_TO_RESOURCE_ID(pkt->u.handle)); - break; - - case VSOCK_PACKET_TYPE_WROTE: - case VSOCK_PACKET_TYPE_READ: - case VSOCK_PACKET_TYPE_RST: - written = snprintf(cur, left, ", %s", typeStrings[pkt->type]); - break; - case VSOCK_PACKET_TYPE_SHUTDOWN: { - Bool recv; - Bool send; - - recv = pkt->u.mode & RCV_SHUTDOWN; - send = pkt->u.mode & SEND_SHUTDOWN; - written = snprintf(cur, left, ", %s, mode = %c%c", - typeStrings[pkt->type], - recv ? 'R' : ' ', - send ? 'S' : ' '); - } - break; - - case VSOCK_PACKET_TYPE_WAITING_WRITE: - case VSOCK_PACKET_TYPE_WAITING_READ: - written = snprintf(cur, left, ", %s, generation = %"FMT64"u, " - "offset = %"FMT64"u", typeStrings[pkt->type], - pkt->u.wait.generation, pkt->u.wait.offset); - - break; - - case VSOCK_PACKET_TYPE_REQUEST2: - case VSOCK_PACKET_TYPE_NEGOTIATE2: - written = snprintf(cur, left, ", %s, size = %"FMT64"u, " - "proto = %u", - typeStrings[pkt->type], pkt->u.size, - pkt->proto); - break; - - default: - written = snprintf(cur, left, ", unrecognized type"); - } - - if (written >= left) { - goto error; - } - - left -= written; - cur += written; - - written = snprintf(cur, left, " [%s:%u]\n", function, line); - if (written >= left) { - goto error; - } - - LOG(8, ("%s", buf)); - - return; - -error: - LOG(8, ("could not log packet\n")); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInitTables -- - * - * Initializes the tables used for socket lookup. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciInitTables(void) -{ - uint32 i; - - for (i = 0; i < ARRAYSIZE(vsockBindTable); i++) { - INIT_LIST_HEAD(&vsockBindTable[i]); - } - - for (i = 0; i < ARRAYSIZE(vsockConnectedTable); i++) { - INIT_LIST_HEAD(&vsockConnectedTable[i]); - } -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciInsertBound -- - * - * Inserts socket into the bound table. - * - * Note that this assumes any necessary locks are held. - * - * Results: - * None. - * - * Side effects: - * The reference count for sk is incremented. - * - *---------------------------------------------------------------------------- - */ - -void -__VSockVmciInsertBound(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->boundTable, list); -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciInsertConnected -- - * - * Inserts socket into the connected table. - * - * Note that this assumes any necessary locks are held. - * - * Results: - * None. - * - * Side effects: - * The reference count for sk is incremented. - * - *---------------------------------------------------------------------------- - */ - -void -__VSockVmciInsertConnected(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->connectedTable, list); -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciRemoveBound -- - * - * Removes socket from the bound table. - * - * Note that this assumes any necessary locks are held. - * - * Results: - * None. - * - * Side effects: - * The reference count for sk is decremented. - * - *---------------------------------------------------------------------------- - */ - -void -__VSockVmciRemoveBound(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(__VSockVmciInBoundTable(sk)); - - vsk = vsock_sk(sk); - - list_del_init(&vsk->boundTable); - sock_put(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciRemoveConnected -- - * - * Removes socket from the connected table. - * - * Note that this assumes any necessary locks are held. - * - * Results: - * None. - * - * Side effects: - * The reference count for sk is decremented. - * - *---------------------------------------------------------------------------- - */ - -void -__VSockVmciRemoveConnected(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - ASSERT(__VSockVmciInConnectedTable(sk)); - - vsk = vsock_sk(sk); - - list_del_init(&vsk->connectedTable); - sock_put(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciFindBoundSocket -- - * - * Finds the socket corresponding to the provided address in the bound - * sockets hash table. - * - * Note that this assumes any necessary locks are held. - * - * Results: - * The sock structure if found, NULL if not found. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -struct sock * -__VSockVmciFindBoundSocket(struct sockaddr_vm *addr) // IN -{ - VSockVmciSock *vsk; - struct sock *sk; - - ASSERT(addr); - - list_for_each_entry(vsk, vsockBoundSockets(addr), boundTable) { - if (addr->svm_port == vsk->localAddr.svm_port) { - sk = sk_vsock(vsk); - - /* We only store stream sockets in the bound table. */ - ASSERT(sk->sk_socket ? - sk->sk_socket->type == SOCK_STREAM : - 1); - goto found; - } - } - - sk = NULL; -found: - return sk; -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciFindConnectedSocket -- - * - * Finds the socket corresponding to the provided addresses in the connected - * sockets hash table. - * - * Note that this assumes any necessary locks are held. - * - * Results: - * The sock structure if found, NULL if not found. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -struct sock * -__VSockVmciFindConnectedSocket(struct sockaddr_vm *src, // IN - struct sockaddr_vm *dst) // IN -{ - VSockVmciSock *vsk; - struct sock *sk; - - ASSERT(src); - ASSERT(dst); - - list_for_each_entry(vsk, vsockConnectedSockets(src, dst), connectedTable) { - if (VSockAddr_EqualsAddr(src, &vsk->remoteAddr) && - dst->svm_port == vsk->localAddr.svm_port) { - sk = sk_vsock(vsk); - goto found; - } - } - - sk = NULL; -found: - return sk; -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciInBoundTable -- - * - * Determines whether the provided socket is in the bound table. - * - * Results: - * TRUE is socket is in bound table, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -__VSockVmciInBoundTable(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - return !list_empty(&vsk->boundTable); -} - - -/* - *---------------------------------------------------------------------------- - * - * __VSockVmciInConnectedTable -- - * - * Determines whether the provided socket is in the connected table. - * - * Results: - * TRUE is socket is in connected table, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -__VSockVmciInConnectedTable(struct sock *sk) // IN -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - - return !list_empty(&vsk->connectedTable); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciGetPending -- - * - * Retrieves a pending connection that matches the addresses specified in - * the provided packet. - * - * Assumes the socket lock is held for listener. - * - * Results: - * Socket of the pending connection on success, NULL if not found. - * - * Side effects: - * A reference is held on the socket until the release function is called. - * - *---------------------------------------------------------------------------- - */ - -struct sock * -VSockVmciGetPending(struct sock *listener, // IN: listening socket - VSockPacket *pkt) // IN: incoming packet -{ - VSockVmciSock *vlistener; - VSockVmciSock *vpending; - struct sock *pending; - struct sockaddr_vm src; - - ASSERT(listener); - ASSERT(pkt); - - VSockAddr_Init(&src, VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src), pkt->srcPort); - - vlistener = vsock_sk(listener); - - list_for_each_entry(vpending, &vlistener->pendingLinks, pendingLinks) { - if (VSockAddr_EqualsAddr(&src, &vpending->remoteAddr) && - pkt->dstPort == vpending->localAddr.svm_port) { - pending = sk_vsock(vpending); - sock_hold(pending); - goto found; - } - } - - pending = NULL; -found: - return pending; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciReleasePending -- - * - * Releases the reference on a socket previously obtained by a call to - * VSockVmciGetPending(). - * - * Results: - * None. - * - * Side effects: - * The socket may be freed if this was the last reference. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciReleasePending(struct sock *pending) // IN: pending connection -{ - ASSERT(pending); - - sock_put(pending); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciAddPending -- - * - * Adds a pending connection on listener's pending list. - * - * Assumes the socket lock is held for listener. - * Assumes the socket lock is held for pending. - * - * Results: - * None. - * - * Side effects: - * The reference count of the sockets is incremented. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciAddPending(struct sock *listener, // IN: listening socket - struct sock *pending) // IN: pending connection -{ - VSockVmciSock *vlistener; - VSockVmciSock *vpending; - - ASSERT(listener); - ASSERT(pending); - - vlistener = vsock_sk(listener); - vpending = vsock_sk(pending); - - sock_hold(pending); - sock_hold(listener); - list_add_tail(&vpending->pendingLinks, &vlistener->pendingLinks); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRemovePending -- - * - * Removes a pending connection from the listener's pending list. - * - * Assumes the socket lock is held for listener. - * Assumes the socket lock is held for pending. - * - * Results: - * None. - * - * Side effects: - * The reference count of the sockets is decremented. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciRemovePending(struct sock *listener, // IN: listening socket - struct sock *pending) // IN: pending connection -{ - VSockVmciSock *vpending; - - ASSERT(listener); - ASSERT(pending); - - vpending = vsock_sk(pending); - - list_del_init(&vpending->pendingLinks); - sock_put(listener); - sock_put(pending); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciEnqueueAccept -- - * - * Enqueues the connected socket on the listening socket's accepting - * queue. - * - * Assumes the socket lock is held for listener. - * Assumes the socket lock is held for connected. - * - * Results: - * None. - * - * Side effects: - * The sockets' reference counts are incremented. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciEnqueueAccept(struct sock *listener, // IN: listening socket - struct sock *connected) // IN: connected socket -{ - VSockVmciSock *vlistener; - VSockVmciSock *vconnected; - - ASSERT(listener); - ASSERT(connected); - - vlistener = vsock_sk(listener); - vconnected = vsock_sk(connected); - - sock_hold(connected); - sock_hold(listener); - list_add_tail(&vconnected->acceptQueue, &vlistener->acceptQueue); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciDequeueAccept -- - * - * Dequeues the next connected socket from the listening socket's accept - * queue. - * - * Assumes the socket lock is held for listener. - * - * Note that the caller must call sock_put() on the returned socket once it - * is done with the socket. - * - * Results: - * The next socket from the queue, or NULL if the queue is empty. - * - * Side effects: - * The reference count of the listener is decremented. - * - *---------------------------------------------------------------------------- - */ - -struct sock * -VSockVmciDequeueAccept(struct sock *listener) // IN: listening socket -{ - VSockVmciSock *vlistener; - VSockVmciSock *vconnected; - - ASSERT(listener); - - vlistener = vsock_sk(listener); - - if (list_empty(&vlistener->acceptQueue)) { - return NULL; - } - - vconnected = list_entry(vlistener->acceptQueue.next, - VSockVmciSock, acceptQueue); - ASSERT(vconnected); - - list_del_init(&vconnected->acceptQueue); - sock_put(listener); - /* - * The caller will need a reference on the connected socket so we let it - * call sock_put(). - */ - - ASSERT(sk_vsock(vconnected)); - return sk_vsock(vconnected); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRemoveAccept -- - * - * Removes a socket from the accept queue of a listening socket. - * - * Assumes the socket lock is held for listener. - * Assumes the socket lock is held for connected. - * - * Results: - * None. - * - * Side effects: - * The sockets' reference counts are decremented. - * - *---------------------------------------------------------------------------- - */ - -void -VSockVmciRemoveAccept(struct sock *listener, // IN: listening socket - struct sock *connected) // IN: connected socket -{ - VSockVmciSock *vconnected; - - ASSERT(listener); - ASSERT(connected); - - if (!VSockVmciInAcceptQueue(connected)) { - return; - } - - vconnected = vsock_sk(connected); - ASSERT(vconnected->listener == listener); - - list_del_init(&vconnected->acceptQueue); - sock_put(listener); - sock_put(connected); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInAcceptQueue -- - * - * Determines whether a socket is on an accept queue. - * - * Assumes the socket lock is held for sk. - * - * Results: - * TRUE if the socket is in an accept queue, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockVmciInAcceptQueue(struct sock *sk) // IN: socket -{ - ASSERT(sk); - - /* - * If our accept queue isn't empty, it means we're linked into some listener - * socket's accept queue. - */ - return !VSockVmciIsAcceptQueueEmpty(sk); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciIsAcceptQueueEmpty -- - * - * Determines whether the provided socket's accept queue is empty. - * - * Assumes the socket lock is held for sk. - * - * Results: - * TRUE if the socket's accept queue is empty, FALSE otherwsise. - * - * Side effects: - * None. - * - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockVmciIsAcceptQueueEmpty(struct sock *sk) // IN: socket -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - return list_empty(&vsk->acceptQueue); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciIsPending -- - * - * Determines whether a socket is pending. - * - * Assumes the socket lock is held for sk. - * - * Results: - * TRUE if the socket is pending, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockVmciIsPending(struct sock *sk) // IN: socket -{ - VSockVmciSock *vsk; - - ASSERT(sk); - - vsk = vsock_sk(sk); - return !list_empty(&vsk->pendingLinks); -} diff --git a/open-vm-tools/modules/linux/vsock/linux/util.h b/open-vm-tools/modules/linux/vsock/linux/util.h deleted file mode 100644 index 9f806059d..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/util.h +++ /dev/null @@ -1,383 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - - -/* - * util.h -- - * - * Utility functions for Linux VSocket module. - */ - -#ifndef __UTIL_H__ -#define __UTIL_H__ - -#include "driver-config.h" -#include "compat_sock.h" -#include "compat_spinlock.h" - -#include "vsockCommon.h" -#include "vsockPacket.h" - -/* - * Each bound VSocket is stored in the bind hash table and each connected - * VSocket is stored in the connected hash table. - * - * Unbound sockets are all put on the same list attached to the end of the hash - * table (vsockUnboundSockets). Bound sockets are added to the hash table in - * the bucket that their local address hashes to (vsockBoundSockets(addr) - * represents the list that addr hashes to). - * - * Specifically, we initialize the vsockBindTable array to a size of - * VSOCK_HASH_SIZE + 1 so that vsockBindTable[0] through - * 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. - */ -#define VSOCK_HASH_SIZE 251 -#define LAST_RESERVED_PORT 1023 -#define MAX_PORT_RETRIES 24 - -extern struct list_head vsockBindTable[VSOCK_HASH_SIZE + 1]; -extern struct list_head vsockConnectedTable[VSOCK_HASH_SIZE]; - -extern spinlock_t vsockTableLock; - -#define VSOCK_HASH(addr) ((addr)->svm_port % (VSOCK_HASH_SIZE - 1)) -#define vsockBoundSockets(addr) (&vsockBindTable[VSOCK_HASH(addr)]) -#define vsockUnboundSockets (&vsockBindTable[VSOCK_HASH_SIZE]) - -/* XXX This can probably be implemented in a better way. */ -#define VSOCK_CONN_HASH(src, dst) \ - (((src)->svm_cid ^ (dst)->svm_port) % (VSOCK_HASH_SIZE - 1)) -#define vsockConnectedSockets(src, dst) \ - (&vsockConnectedTable[VSOCK_CONN_HASH(src, dst)]) -#define vsockConnectedSocketsVsk(vsk) \ - vsockConnectedSockets(&(vsk)->remoteAddr, &(vsk)->localAddr) - -/* - * Prototypes. - */ - -void VSockVmciLogPkt(char const *function, uint32 line, VSockPacket *pkt); - -void VSockVmciInitTables(void); -void __VSockVmciInsertBound(struct list_head *list, struct sock *sk); -void __VSockVmciInsertConnected(struct list_head *list, struct sock *sk); -void __VSockVmciRemoveBound(struct sock *sk); -void __VSockVmciRemoveConnected(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); - -struct sock *VSockVmciGetPending(struct sock *listener, VSockPacket *pkt); -void VSockVmciReleasePending(struct sock *pending); -void VSockVmciAddPending(struct sock *listener, struct sock *pending); -void VSockVmciRemovePending(struct sock *listener, struct sock *pending); -void VSockVmciEnqueueAccept(struct sock *listener, struct sock *connected); -struct sock *VSockVmciDequeueAccept(struct sock *listener); -void VSockVmciRemoveAccept(struct sock *listener, struct sock *connected); -Bool VSockVmciInAcceptQueue(struct sock *sk); -Bool VSockVmciIsAcceptQueueEmpty(struct sock *sk); -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 VSockVmciRemoveBound(struct sock *sk); -static INLINE void VSockVmciRemoveConnected(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); - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInsertBound -- - * - * Inserts socket into the bound 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: - * vsockTableLock is acquired and released. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciInsertBound(struct list_head *list, // IN - struct sock *sk) // IN -{ - ASSERT(list); - ASSERT(sk); - - spin_lock_bh(&vsockTableLock); - __VSockVmciInsertBound(list, sk); - spin_unlock_bh(&vsockTableLock); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInsertConnected -- - * - * Inserts socket into the connected 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: - * vsockTableLock is acquired and released. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciInsertConnected(struct list_head *list, // IN - struct sock *sk) // IN -{ - ASSERT(list); - ASSERT(sk); - - spin_lock_bh(&vsockTableLock); - __VSockVmciInsertConnected(list, sk); - spin_unlock_bh(&vsockTableLock); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRemoveBound -- - * - * Removes socket from the bound 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: - * vsockTableLock is acquired and released. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciRemoveBound(struct sock *sk) // IN -{ - ASSERT(sk); - - spin_lock_bh(&vsockTableLock); - __VSockVmciRemoveBound(sk); - spin_unlock_bh(&vsockTableLock); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciRemoveConnected -- - * - * Removes socket from the connected 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: - * vsockTableLock is acquired and released. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmciRemoveConnected(struct sock *sk) // IN -{ - ASSERT(sk); - - spin_lock_bh(&vsockTableLock); - __VSockVmciRemoveConnected(sk); - spin_unlock_bh(&vsockTableLock); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciFindBoundSocket -- - * - * Finds the socket corresponding to the provided address in the bound - * sockets hash table. - * - * Note that it is important to invoke the bottom-half versions of the - * spinlock functions since these are called from tasklets. - * - * Results: - * The sock structure if found, NULL on failure. - * - * Side effects: - * vsockTableLock is acquired and released. - * The socket's reference count is increased. - * - *---------------------------------------------------------------------------- - */ - -static INLINE struct sock * -VSockVmciFindBoundSocket(struct sockaddr_vm *addr) // IN -{ - struct sock *sk; - - ASSERT(addr); - - spin_lock_bh(&vsockTableLock); - sk = __VSockVmciFindBoundSocket(addr); - if (sk) { - sock_hold(sk); - } - spin_unlock_bh(&vsockTableLock); - - return sk; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciFindConnectedSocket -- - * - * Finds the socket corresponding to the provided address in the connected - * sockets hash table. - * - * Note that it is important to invoke the bottom-half versions of the - * spinlock functions since these are called from tasklets. - * - * Results: - * The sock structure if found, NULL on failure. - * - * Side effects: - * vsockTableLock is acquired and released. - * The socket's reference count is increased. - * - *---------------------------------------------------------------------------- - */ - -static INLINE struct sock * -VSockVmciFindConnectedSocket(struct sockaddr_vm *src, // IN - struct sockaddr_vm *dst) // IN -{ - struct sock *sk; - - ASSERT(src); - ASSERT(dst); - - spin_lock_bh(&vsockTableLock); - sk = __VSockVmciFindConnectedSocket(src, dst); - if (sk) { - sock_hold(sk); - } - spin_unlock_bh(&vsockTableLock); - - return sk; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInBoundTable -- - * - * Determines whether the provided socket is in the bound 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 bound table, FALSE otherwise. - * - * Side effects: - * vsockTableLock is acquired and released. - * - *---------------------------------------------------------------------------- - */ - -static INLINE Bool -VSockVmciInBoundTable(struct sock *sk) // IN -{ - Bool ret; - - ASSERT(sk); - - spin_lock_bh(&vsockTableLock); - ret = __VSockVmciInBoundTable(sk); - spin_unlock_bh(&vsockTableLock); - - return ret; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmciInConnectedTable -- - * - * Determines whether the provided socket is in the connected 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 connected table, FALSE otherwise. - * - * Side effects: - * vsockTableLock is acquired and released. - * - *---------------------------------------------------------------------------- - */ - -static INLINE Bool -VSockVmciInConnectedTable(struct sock *sk) // IN -{ - Bool ret; - - ASSERT(sk); - - spin_lock_bh(&vsockTableLock); - ret = __VSockVmciInConnectedTable(sk); - spin_unlock_bh(&vsockTableLock); - - return ret; -} - - -#endif /* __UTIL_H__ */ diff --git a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h b/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h deleted file mode 100644 index 1c3a99e68..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h +++ /dev/null @@ -1,69 +0,0 @@ -/********************************************************* - * Copyright (C) 2009,2014 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_int.h -- - * - * vSockets private constants and types. - * - * This file is internal only, we do not ship the kernel interface yet. - * You need to include this file *before* vmci_sockets.h in your kernel - * module. - */ - -#ifndef _VMCI_SOCKETS_INT_H_ -#define _VMCI_SOCKETS_INT_H_ - -#if defined __cplusplus -extern "C" { -#endif - - -#if defined(_WIN32) -# if defined(NT_INCLUDED) -# if (_WIN32_WINNT < 0x0600) - /* - * WinSockKernel is targetted at Vista and later. We want to allow - * drivers built from W2K onwards to work with the interface, so we - * need to define some missing types before we bring in the WSK header. - */ - typedef unsigned short u_short; -# include -# include - typedef WSACMSGHDR CMSGHDR, *PCMSGHDR; -# endif // (_WIN32_WINNT < 0x0600) -# include - NTSTATUS VMCISock_WskRegister(PWSK_CLIENT_NPI wskClientNpi, - PWSK_REGISTRATION wskRegistration); - NTSTATUS VMCISock_WskDeregister(PWSK_REGISTRATION wskRegistration); - NTSTATUS VMCISock_WskCaptureProviderNPI(PWSK_REGISTRATION wskRegistration, - ULONG waitTimeout, - PWSK_PROVIDER_NPI wskProviderNpi); - NTSTATUS VMCISock_WskReleaseProviderNPI(PWSK_REGISTRATION wskRegistration); - NTSTATUS VMCISock_WskGetAFValue(PWSK_CLIENT wskClient, PIRP irp); - NTSTATUS VMCISock_WskGetLocalCID(PWSK_CLIENT wskClient, PIRP irp); -# endif // NT_INCLUDED -#endif // _WIN32 - - -#if defined __cplusplus -} // extern "C" -#endif - -#endif // _VMCI_SOCKETS_INT_H_ - diff --git a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h b/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h deleted file mode 100644 index abc42adeb..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h +++ /dev/null @@ -1,118 +0,0 @@ -/********************************************************* - * Copyright (C) 2012,2014 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 vSockets 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; - -/* - * Size assertions. - */ - -MY_ASSERTS(VSockSeqPacketAsserts, - ASSERT_ON_COMPILE(sizeof (VSockPacket) == 56); -) - -#endif // _VMCI_SOCKETS_PACKET_H_ diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c deleted file mode 100644 index 4799e2405..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c +++ /dev/null @@ -1,425 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vsockAddr.c -- - * - * VSockets address implementation. - */ - -/* - * These includes come before vsockCommon.h to ensure that VMware's ASSERT - * macro is used instead of Linux's irda.h definition. - */ -#if defined(__linux__) && !defined(VMKERNEL) -# if defined(__KERNEL__) -# include "driver-config.h" -# include -# include "compat_sock.h" -# else -# include -# include -# endif -#elif defined(VMKERNEL) -# include "vm_libc.h" -# include "return_status.h" -#elif defined(__APPLE__) -# include -#endif - -#include "vsockCommon.h" - - -/* - *----------------------------------------------------------------------------- - * - * VSockAddr_Init -- - * - * Initialize the given address with the given context id and port. This - * will clear the address, set the correct family, and add the given - * values. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VSockAddr_Init(struct sockaddr_vm *addr, // OUT - uint32 cid, // IN - uint32 port) // IN -{ - ASSERT(addr); - VSockAddr_InitNoFamily(addr, cid, port); - addr->svm_family = VMCISockGetAFValueInt(); - VSOCK_ADDR_ASSERT(addr); -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockAddr_InitNoFamily -- - * - * Initialize the given address with the given context id and port. This - * will clear the address and add the given values, but not set the - * family. Note that this is needed because in some places we don't want - * to re-register the address family in the Linux kernel and all we need - * is to check the context id and port. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VSockAddr_InitNoFamily(struct sockaddr_vm *addr, // OUT - uint32 cid, // IN - uint32 port) // IN -{ - ASSERT(addr); - - memset(addr, 0, sizeof *addr); -#if defined(__APPLE__) - addr->svm_len = sizeof *addr; -#endif - addr->svm_cid = cid; - addr->svm_port = port; - VSOCK_ADDR_NOFAMILY_ASSERT(addr); -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockAddr_Validate -- - * - * Try to validate the given address. The address must not be null and - * must have the correct address family. Any reserved fields must be - * zero. - * - * Results: - * 0 on success, EFAULT if the address is null, EAFNOSUPPORT if the - * address is of the wrong family, and EINVAL if the reserved fields are - * not zero. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int32 -VSockAddr_Validate(const struct sockaddr_vm *addr) // IN -{ - int32 err; - - if (NULL == addr) { - err = EFAULT; - goto exit; - } - - if (VMCISockGetAFValueInt() != addr->svm_family) { - err = EAFNOSUPPORT; - goto exit; - } - - if (0 != addr->svm_zero[0]) { - err = EINVAL; - goto exit; - } - - err = 0; - -exit: - return sockerr2err(err); -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockAddr_ValidateNoFamily -- - * - * Try to validate the given address. The address must not be null and - * any reserved fields must be zero, but the address family is not - * checked. Note that this is needed because in some places we don't want - * to re-register the address family with the Linux kernel. - * - * Also note that we duplicate the code from _Validate() since we want to - * retain the ordering or the error return values. - * - * Results: - * 0 on success, EFAULT if the address is null and EINVAL if the reserved - * fields are not zero. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int32 -VSockAddr_ValidateNoFamily(const struct sockaddr_vm *addr) // IN -{ - int32 err; - - if (NULL == addr) { - err = EFAULT; - goto exit; - } - - if (0 != addr->svm_zero[0]) { - err = EINVAL; - goto exit; - } - - err = 0; - -exit: - return sockerr2err(err); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockAddr_Bound -- - * - * Determines whether the provided address is bound. - * - * Results: - * TRUE if the address structure is bound, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockAddr_Bound(struct sockaddr_vm *addr) // IN: socket address to check -{ - ASSERT(addr); - return addr->svm_port != VMADDR_PORT_ANY; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockAddr_Unbind -- - * - * Unbind the given addresss. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -VSockAddr_Unbind(struct sockaddr_vm *addr) // IN -{ - VSockAddr_Init(addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockAddr_EqualsAddr -- - * - * Determine if the given addresses are equal. - * - * Results: - * TRUE if the addresses are equal, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockAddr_EqualsAddr(struct sockaddr_vm *addr, // IN - struct sockaddr_vm *other) // IN -{ - /* - * XXX We don't ASSERT on the family here since this is used on the receive - * path in Linux and we don't want to re-register the address family - * unnecessarily. - */ - VSOCK_ADDR_NOFAMILY_ASSERT(addr); - VSOCK_ADDR_NOFAMILY_ASSERT(other); - return (addr->svm_cid == other->svm_cid && - addr->svm_port == other->svm_port); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockAddr_EqualsHandlePort -- - * - * Determines if the given address matches the given handle and port. - * - * Results: - * TRUE if the address matches the handle and port, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockAddr_EqualsHandlePort(struct sockaddr_vm *addr, // IN - VMCIHandle handle, // IN - uint32 port) // IN -{ - VSOCK_ADDR_ASSERT(addr); - return (addr->svm_cid == VMCI_HANDLE_TO_CONTEXT_ID(handle) && - addr->svm_port == port); -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockAddr_Cast -- - * - * Try to cast the given generic address to a VM address. The given - * length must match that of a VM address and the address must be valid. - * The "outAddr" parameter contains the address if successful. - * - * Results: - * 0 on success, EFAULT if the length is too small. See - * VSockAddr_Validate() for other possible return codes. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int32 -VSockAddr_Cast(const struct sockaddr *addr, // IN - int32 len, // IN - struct sockaddr_vm **outAddr) // OUT -{ - int32 err; - - ASSERT(outAddr); - - if (len < sizeof **outAddr) { - err = EFAULT; - goto exit; - } - - *outAddr = (struct sockaddr_vm *) addr; - err = VSockAddr_Validate(*outAddr); - -exit: - return sockerr2err(err); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockAddr_SocketContextStream -- - * - * Determines whether the provided context id represents a context that - * contains a stream socket endpoints. - * - * Results: - * TRUE if the context does have socket endpoints, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockAddr_SocketContextStream(uint32 cid) // IN -{ - uint32 i; - VMCIId nonSocketContexts[] = { - VMCI_WELL_KNOWN_CONTEXT_ID, - }; - - ASSERT_ON_COMPILE(sizeof cid == sizeof *nonSocketContexts); - - for (i = 0; i < ARRAYSIZE(nonSocketContexts); i++) { - if (cid == nonSocketContexts[i]) { - return FALSE; - } - } - - return TRUE; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockAddr_SocketContextDgram -- - * - * Determines whether the provided represent - * a protected datagram endpoint. - * - * Results: - * TRUE if the context does have socket endpoints, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -VSockAddr_SocketContextDgram(uint32 cid, // IN - uint32 rid) // IN -{ - if (cid == VMCI_HYPERVISOR_CONTEXT_ID) { - /* - * Registrations of PBRPC Servers do not modify VMX/Hypervisor state and - * are allowed. - */ - if (rid == VMCI_UNITY_PBRPC_REGISTER) { - return TRUE; - } else { - return FALSE; - } - } - - return TRUE; -} diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h deleted file mode 100644 index a90ea31f2..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vsockAddr.h -- - * - * VSockets address constants, types and functions. - */ - - -#ifndef _VSOCK_ADDR_H_ -#define _VSOCK_ADDR_H_ - - -/* Assert that the given address is valid. */ -#define VSOCK_ADDR_ASSERT(_a) \ - ASSERT(0 == VSockAddr_Validate((_a))) -#define VSOCK_ADDR_NOFAMILY_ASSERT(_a) \ - ASSERT(0 == VSockAddr_ValidateNoFamily((_a))) - - -void VSockAddr_Init(struct sockaddr_vm *addr, uint32 cid, uint32 port); -void VSockAddr_InitNoFamily(struct sockaddr_vm *addr, uint32 cid, uint32 port); -int32 VSockAddr_Validate(const struct sockaddr_vm *addr); -int32 VSockAddr_ValidateNoFamily(const struct sockaddr_vm *addr); -Bool VSockAddr_Bound(struct sockaddr_vm *addr); -void VSockAddr_Unbind(struct sockaddr_vm *addr); -Bool VSockAddr_EqualsAddr(struct sockaddr_vm *addr, struct sockaddr_vm *other); -Bool VSockAddr_EqualsHandlePort(struct sockaddr_vm *addr, VMCIHandle handle, - uint32 port); -int32 VSockAddr_Cast(const struct sockaddr *addr, int32 len, - struct sockaddr_vm **outAddr); -Bool VSockAddr_SocketContextStream(uint32 cid); -Bool VSockAddr_SocketContextDgram(uint32 cid, uint32 rid); - -#endif // _VSOCK_ADDR_H_ - diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h b/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h deleted file mode 100644 index 0b326d4eb..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h +++ /dev/null @@ -1,241 +0,0 @@ -/********************************************************* - * Copyright (C) 2007,2014 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 - * - *********************************************************/ - -/* - * vsockCommon.h -- - * - * VSockets common constants, types and functions. - */ - - -#ifndef _VSOCK_COMMON_H_ -#define _VSOCK_COMMON_H_ - -/* - * VMCISockGetAFValueInt is defined separately from VMCISock_GetAFValue because - * it is used in several different contexts. In particular it is called from - * vsockAddr.c which gets compiled into both our kernel modules as well as - * the user level vsock library. In the linux kernel we need different behavior - * than external kernel modules using vSockets API inside the kernel. - */ - -#if defined VMX86_VMX - /* - * The VMX is a very special case because hypervisor sockets do not go - * through the host kernel and thus do not require an address family. - */ -# define VMCI_SOCKETS_AF_VALUE 0 -# define VMCISockGetAFValueInt() VMCI_SOCKETS_AF_VALUE -#elif defined _WIN32 -# define VMCI_SOCKETS_AF_VALUE 28 -# if defined WINNT_DDK -# define _WIN2K_COMPAT_SLIST_USAGE -# include -# include -# define _INC_WINDOWS - /* In the kernel we can't call into the provider. */ -# define VMCISockGetAFValueInt() VMCI_SOCKETS_AF_VALUE -# else // WINNT_DDK - /* In userland, just use the normal exported userlevel API. */ -# define VMCISockGetAFValueInt() VMCISock_GetAFValue() -# include -# endif // WINNT_DDK -#elif defined VMKERNEL -# include "uwvmkAPI.h" -# define VMCI_SOCKETS_AF_VALUE AF_VMCI /* Defined in uwvmkAPI.h. */ - /* The address family is fixed in the vmkernel. */ -# define VMCISockGetAFValueInt() VMCI_SOCKETS_AF_VALUE -#elif defined linux -# if defined __KERNEL__ - /* Include compat_page.h now so PAGE_SIZE and friends don't get redefined. */ -# include "driver-config.h" -# include "compat_page.h" - /* - * In the kernel we call back into af_vsock.c to get the address family - * being used. Otherwise an ioctl(2) is performed (see vmci_sockets.h). - */ - extern int VSockVmci_GetAFValue(void); -# define VMCISockGetAFValueInt() VSockVmci_GetAFValue() -# else // __KERNEL__ - /* In userland, just use the normal exported userlevel API. */ -# define VMCISockGetAFValueInt() VMCISock_GetAFValue() -# endif -#elif defined __APPLE__ -# if defined KERNEL -# include -# define VMCI_SOCKETS_AF_VALUE 14 -# define VMCISockGetAFValueInt() VMCI_SOCKETS_AF_VALUE -# else // KERNEL -# define VMCISockGetAFValueInt() VMCISock_GetAFValue() -# endif // KERNEL -#endif // __APPLE__ - -#include "vmware.h" -#include "vm_basic_asm.h" -#include "vmci_defs.h" -#include "vmci_call_defs.h" -#include "vmci_infrastructure.h" -#include "vmci_sockets_int.h" -#include "vmci_sockets.h" - -#if defined WINNT_DDK -# include -#endif // WINNT_DDK - -#include "vsockAddr.h" -#include "vsockSocketWrapper.h" - - -/* - * Local VSocket control packet resource ID. - * - * Stream sockets to the hypervisor were added later so VSOCK_PACKET_RID was - * already assigned to another application. VSOCK_PACKET_HYPERVISOR_RID is - * used instead. - */ -#if defined VMX86_VMX -# define VSOCK_PACKET_LOCAL_RID VSOCK_PACKET_HYPERVISOR_RID -#else -# define VSOCK_PACKET_LOCAL_RID VSOCK_PACKET_RID -#endif - - -/* Memory allocation flags. */ -#define VSOCK_MEMORY_NORMAL 0 -#define VSOCK_MEMORY_ATOMIC (1 << 0) -#define VSOCK_MEMORY_NONPAGED (1 << 1) - - -/* - *----------------------------------------------------------------------------- - * - * VSockVA64ToPtr -- - * - * Convert a VA64 to a pointer. - * - * Results: - * Virtual address. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE void * -VSockVA64ToPtr(VA64 va64) // IN -{ -#ifdef VM_64BIT - ASSERT_ON_COMPILE(sizeof (void *) == 8); -#else - ASSERT_ON_COMPILE(sizeof (void *) == 4); - // Check that nothing of value will be lost. - ASSERT(!(va64 >> 32)); -#endif - return (void *)(uintptr_t)va64; -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockPtrToVA64 -- - * - * Convert a pointer to a VA64. - * - * Results: - * Virtual address. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static INLINE VA64 -VSockPtrToVA64(void const *ptr) // IN -{ - ASSERT_ON_COMPILE(sizeof ptr <= sizeof (VA64)); - return (VA64)(uintptr_t)ptr; -} - - -#if defined(_WIN32) && !defined(WINNT_DDK) -/* VSock transport provider structures */ -__declspec(selectany) extern const WSAPROTOCOL_INFOW vsockProtocolInfos[] = { - { - (XP1_CONNECTIONLESS | /* No connection required. */ - XP1_MESSAGE_ORIENTED), /* Message. */ - 0, /* Reserved. */ - 0, /* Reserved. */ - 0, /* Reserved. */ - PFL_MATCHES_PROTOCOL_ZERO, /* Always protocol 0. */ - { 0 }, /* None. */ - 0, /* Assigned by Winsock. */ - { 1, 0 }, /* Base provider. */ - 0, /* Version 0. */ - VMCI_SOCKETS_AF_VALUE, /* vSockets protocol. */ - 16, /* Maximum address length in bytes. */ - 16, /* Minimum address length in bytes. */ - SOCK_DGRAM, /* STREAM. */ - 0, /* Protocol. */ - 0, /* Protocol max offset. */ - BIGENDIAN, /* Network byte order. */ - SECURITY_PROTOCOL_NONE, /* No security. */ - 0, /* Message size unimportant. */ - 0, /* None. */ - L"vSockets DGRAM" /* Protocol name. */ - }, - { - (XP1_GUARANTEED_DELIVERY | /* Guaranteed delivery. */ - XP1_GUARANTEED_ORDER | /* Guaranteed order. */ - XP1_GRACEFUL_CLOSE), /* Graceful close. */ - 0, /* Reserved. */ - 0, /* Reserved. */ - 0, /* Reserved. */ - PFL_MATCHES_PROTOCOL_ZERO, /* Always protocol 0. */ - { 0 }, /* None. */ - 0, /* Assigned by Winsock. */ - { 1, 0 }, /* Base provider. */ - 0, /* Version 0. */ - VMCI_SOCKETS_AF_VALUE, /* vSockets protocol. */ - 16, /* Maximum address length in bytes. */ - 16, /* Minimum address length in bytes. */ - SOCK_STREAM, /* STREAM. */ - 0, /* Protocol. */ - 0, /* Protocol max offset. */ - BIGENDIAN, /* Network byte order. */ - SECURITY_PROTOCOL_NONE, /* No security. */ - 0, /* Message size unimportant. */ - 0, /* None. */ - L"vSockets STREAM" /* Protocol name. */ - }, -}; - -__declspec(selectany) extern const -size_t numVSockProtocolInfos = ARRAYSIZE(vsockProtocolInfos); - -/* {570ADC4B-67B2-42ce-92B2-ACD33D88D842} */ -__declspec(selectany) extern const GUID vsockProviderID = { - 0x570adc4b, 0x67b2, 0x42ce, - { 0x92, 0xb2, 0xac, 0xd3, 0x3d, 0x88, 0xd8, 0x42 } -}; -#endif // _WIN32 && !WINNT_DDK - - -#endif // _VSOCK_COMMON_H_ diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h b/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h deleted file mode 100644 index a301338b8..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h +++ /dev/null @@ -1,246 +0,0 @@ -/********************************************************* - * 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 - * 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 - * - *********************************************************/ - -/* - * vsockPacket.h -- - * - * Packet constants, types and functions. - */ - -#ifndef _VSOCK_PACKET_H_ -#define _VSOCK_PACKET_H_ - -#include "vmci_sockets_packet.h" - -#if defined(_WIN32) || defined(VMKERNEL) || defined(__APPLE__) || defined(VMX86_VMX) -# include "vsockOSInt.h" -#else -# define VSockOS_ClearMemory(_dst, _sz) memset(_dst, 0, _sz) -# define VSockOS_Memcpy(_dst, _src, _sz) memcpy(_dst, _src, _sz) -#endif - -#include "vsockCommon.h" - - -/* - *----------------------------------------------------------------------------- - * - * VSockPacket_Init -- - * - * Initialize the given packet. The packet version is set and the fields - * are filled out. Reserved fields are cleared. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VSockPacket_Init(VSockPacket *pkt, // OUT - struct sockaddr_vm *src, // IN - struct sockaddr_vm *dst, // IN - uint8 type, // IN - uint64 size, // IN - uint64 mode, // IN - VSockWaitingInfo *wait, // IN - VSockProtoVersion proto, // IN - VMCIHandle handle) // IN -{ - ASSERT(pkt); - VSOCK_ADDR_NOFAMILY_ASSERT(src); - VSOCK_ADDR_NOFAMILY_ASSERT(dst); - - /* - * We register the stream control handler as an any cid handle so we - * must always send from a source address of VMADDR_CID_ANY - */ - pkt->dg.src = VMCI_MAKE_HANDLE(VMADDR_CID_ANY, VSOCK_PACKET_LOCAL_RID); - pkt->dg.dst = VMCI_MAKE_HANDLE(dst->svm_cid, - dst->svm_cid == VMCI_HYPERVISOR_CONTEXT_ID ? - VSOCK_PACKET_HYPERVISOR_RID : - VSOCK_PACKET_RID); - pkt->dg.payloadSize = sizeof *pkt - sizeof pkt->dg; - pkt->version = VSOCK_PACKET_VERSION; - pkt->type = type; - pkt->srcPort = src->svm_port; - pkt->dstPort = dst->svm_port; - VSockOS_ClearMemory(&pkt->proto, sizeof pkt->proto); - VSockOS_ClearMemory(&pkt->_reserved2, sizeof pkt->_reserved2); - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_INVALID: - pkt->u.size = 0; - break; - - case VSOCK_PACKET_TYPE_REQUEST: - case VSOCK_PACKET_TYPE_NEGOTIATE: - pkt->u.size = size; - break; - - case VSOCK_PACKET_TYPE_OFFER: - case VSOCK_PACKET_TYPE_ATTACH: - pkt->u.handle = handle; - break; - - case VSOCK_PACKET_TYPE_WROTE: - case VSOCK_PACKET_TYPE_READ: - case VSOCK_PACKET_TYPE_RST: - pkt->u.size = 0; - break; - - case VSOCK_PACKET_TYPE_SHUTDOWN: - pkt->u.mode = mode; - break; - - case VSOCK_PACKET_TYPE_WAITING_READ: - case VSOCK_PACKET_TYPE_WAITING_WRITE: - ASSERT(wait); - VSockOS_Memcpy(&pkt->u.wait, wait, sizeof pkt->u.wait); - break; - - case VSOCK_PACKET_TYPE_REQUEST2: - case VSOCK_PACKET_TYPE_NEGOTIATE2: - pkt->u.size = size; - pkt->proto = proto; - break; - } - - VSOCK_PACKET_ASSERT(pkt); -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockPacket_Validate -- - * - * Validate the given packet. - * - * Results: - * 0 on success, EFAULT if the address is invalid, EINVAL if the packet - * fields are invalid. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE int32 -VSockPacket_Validate(VSockPacket *pkt) -{ - int32 err = EINVAL; - - if (NULL == pkt) { - err = EFAULT; - goto exit; - } - - if (VMCI_HANDLE_INVALID(pkt->dg.src)) { - goto exit; - } - - if (VMCI_HANDLE_INVALID(pkt->dg.dst)) { - goto exit; - } - - if (VMCI_INVALID_ID == pkt->dstPort || VMCI_INVALID_ID == pkt->srcPort) { - goto exit; - } - - if (VSOCK_PACKET_VERSION != pkt->version) { - goto exit; - } - - /* See the comment above VSOCK_PACKET_ASSERT. */ - if (pkt->type < VSOCK_PACKET_TYPE_REQUEST2) { - if (0 != pkt->proto || 0 != pkt->_reserved2) { - goto exit; - } - } - - switch (pkt->type) { - case VSOCK_PACKET_TYPE_INVALID: - if (0 != pkt->u.size) { - goto exit; - } - break; - - case VSOCK_PACKET_TYPE_REQUEST: - case VSOCK_PACKET_TYPE_NEGOTIATE: - if (0 == pkt->u.size) { - goto exit; - } - break; - - case VSOCK_PACKET_TYPE_OFFER: - case VSOCK_PACKET_TYPE_ATTACH: - if (VMCI_HANDLE_INVALID(pkt->u.handle)) { - goto exit; - } - break; - - case VSOCK_PACKET_TYPE_WROTE: - case VSOCK_PACKET_TYPE_READ: - case VSOCK_PACKET_TYPE_RST: - if (0 != pkt->u.size) { - goto exit; - } - break; - } - - err = 0; - -exit: - return sockerr2err(err); -} - - -/* - *----------------------------------------------------------------------------- - * - * VSockPacket_GetAddresses -- - * - * Get the local and remote addresses from the given packet. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE void -VSockPacket_GetAddresses(VSockPacket *pkt, // IN - struct sockaddr_vm *local, // OUT - struct sockaddr_vm *remote) // OUT -{ - VSOCK_PACKET_ASSERT(pkt); - VSockAddr_Init(local, VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.dst), - pkt->dstPort); - VSockAddr_Init(remote, VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src), - pkt->srcPort); -} - -#endif // _VSOCK_PACKET_H_ diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockSocketWrapper.h b/open-vm-tools/modules/linux/vsock/linux/vsockSocketWrapper.h deleted file mode 100644 index f2a7f52c3..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsockSocketWrapper.h +++ /dev/null @@ -1,283 +0,0 @@ -/********************************************************* - * Copyright (C) 2007-2016 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 - * - *********************************************************/ - -/* - * vsockSocketWrapper.h -- - * - * Socket wrapper constants, types and functions. - */ - - -#ifndef _VSOCK_SOCKET_WRAPPER_H_ -#define _VSOCK_SOCKET_WRAPPER_H_ - -/* - * Socket states and flags. Note that MSG_WAITALL is only defined on 2K3, - * XP-SP2 and above. Since we currently build for 2K to maintain backwards - * compatibility, we pull the value from the newer header. Same for the - * POLLXXX flags, which are not defined before Vista. - */ -#if defined(_WIN32) -# define MSG_DONTWAIT 0 -# define MSG_NOSIGNAL 0 -# if (_WIN32_WINNT < 0x0502) -# define MSG_WAITALL 0x8 -# endif -# if (_WIN32_WINNT < 0x0600) -# define POLLRDNORM 0x0100 -# define POLLRDBAND 0x0200 -# define POLLIN (POLLRDNORM | POLLRDBAND) -# define POLLPRI 0x0400 -# define POLLWRNORM 0x0010 -# define POLLOUT (POLLWRNORM) -# define POLLWRBAND 0x0020 -# define POLLERR 0x0001 -# define POLLHUP 0x0002 -# define POLLNVAL 0x0004 -# endif -#endif - -#if defined __APPLE__ -# define MSG_NOSIGNAL 0 - -/* - * Custom options for setting socket behavious in kVsockSetOptions. - * These values fall after the common Mac OS X Socket options - * in /usr/inclue/sys/socket.h - */ -#define SO_NONBLOCKING 0x1200 -#endif // __APPLE__ - -#if defined(_WIN32) || defined(VMKERNEL) || defined(__APPLE__) || defined(VMX86_VMX) -# define SS_FREE 0 -# define SS_UNCONNECTED 1 -# define SS_CONNECTING 2 -# define SS_CONNECTED 3 -# define SS_DISCONNECTING 4 -# define SS_DISCONNECTED 5 -# define RCV_SHUTDOWN 1 -# define SEND_SHUTDOWN 2 -# define SHUTDOWN_MASK 3 -#endif // _WIN32 || VMKERNEL - -/* - * For signalling sockets. These are defined as standard on Windows. We do - * not use them on Linux. So define them here only for VMKernel. - */ -#if defined(_WIN32) -# define SOCKET_EVENT_READ FD_READ -# define SOCKET_EVENT_WRITE FD_WRITE -# define SOCKET_EVENT_ACCEPT FD_ACCEPT -# define SOCKET_EVENT_CONNECT FD_CONNECT -# define SOCKET_EVENT_CLOSE FD_CLOSE -#else -#if defined(VMKERNEL) || defined(__APPLE__) || defined(VMX86_VMX) -# define SOCKET_EVENT_READ 0x1 -# define SOCKET_EVENT_WRITE 0x2 -# define SOCKET_EVENT_ACCEPT 0x8 -# define SOCKET_EVENT_CONNECT 0x10 -# define SOCKET_EVENT_CLOSE 0x20 -#endif // VMKERNEL -#endif // _WIN32 - -/* - * Custom socket control option values. These are internal. The public ones - * are in vmci_sockets.h. As with the public options, use the address family - * as the option level. - */ -#define SO_VMCI_EVENT_ENUMERATE_SELECT 1000 - -/* - * Error codes. - */ -#if defined(_WIN32) -// Some defines are needed for the older SDK. -# if !defined(EINTR) -# define EINTR WSAEINTR -# endif -# if !defined(EACCES) -# define EACCES WSAEACCES -# endif -# if !defined(EFAULT) -# define EFAULT WSAEFAULT -# endif -# if !defined(EINVAL) -# define EINVAL WSAEINVAL -# endif -# if !defined(EPERM) -# define EPERM WSAEACCES /* WSA doesn't have EPERM */ -# endif -# if !defined(ENOSYS) -# define ENOSYS WSAEOPNOTSUPP -# endif -# if !defined(EAGAIN) -# define EAGAIN WSAEWOULDBLOCK -# endif -# if !defined(EWOULDBLOCK) -# define EWOULDBLOCK WSAEWOULDBLOCK -# define EINPROGRESS WSAEINPROGRESS -# define EALREADY WSAEALREADY -# define ENOTSOCK WSAENOTSOCK -# define EDESTADDRREQ WSAEDESTADDRREQ -# define EMSGSIZE WSAEMSGSIZE -# define EPROTOTYPE WSAEPROTOTYPE -# define ENOPROTOOPT WSAENOPROTOOPT -# define EPROTONOSUPPORT WSAEPROTONOSUPPORT -# define EOPNOTSUPP WSAEOPNOTSUPP -# define EAFNOSUPPORT WSAEAFNOSUPPORT -# define EADDRINUSE WSAEADDRINUSE -# define EADDRNOTAVAIL WSAEADDRNOTAVAIL -# define ENETDOWN WSAENETDOWN -# define ENETUNREACH WSAENETUNREACH -# define ENETRESET WSAENETRESET -# define ECONNABORTED WSAECONNABORTED -# define ECONNRESET WSAECONNRESET -# define ENOBUFS WSAENOBUFS -# define EISCONN WSAEISCONN -# define ENOTCONN WSAENOTCONN -# define ETIMEDOUT WSAETIMEDOUT -# define ECONNREFUSED WSAECONNREFUSED -# define EHOSTUNREACH WSAEHOSTUNREACH -# endif -# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT -# define EPFNOSUPPORT WSAEPFNOSUPPORT -# define ESHUTDOWN WSAESHUTDOWN -# define EHOSTDOWN WSAEHOSTDOWN -# define __ELOCALSHUTDOWN ESHUTDOWN -# define __ELOCALRCVSHUTDOWN __ELOCALSHUTDOWN -# define __EPEERSHUTDOWN ECONNABORTED -# define __ECONNINPROGRESS EWOULDBLOCK -# define __ESNDRCVTIMEDOUT ETIMEDOUT -# define ESYSNOTREADY WSASYSNOTREADY -#elif defined(VMKERNEL) -# define EINTR VMK_WAIT_INTERRUPTED -# define EPERM VMK_ACCESS_DENIED -# define EACCES VMK_NO_ACCESS -# define EFAULT VMK_INVALID_ADDRESS -# define EINVAL VMK_FAILURE -# define EWOULDBLOCK VMK_WOULD_BLOCK -# define EINPROGRESS VMK_EINPROGRESS -# define EALREADY VMK_EALREADY -# define ENOTSOCK VMK_NOT_A_SOCKET -# define EDESTADDRREQ VMK_EDESTADDRREQ - /* - * Do not change EMSGSIZE definition without changing uses of - * VMK_LIMIT_EXCEEDED in userSocketVmci.c's implementation of recvmsg(). - */ -# define EMSGSIZE VMK_LIMIT_EXCEEDED -# define EPROTOTYPE VMK_NOT_SUPPORTED -# define ENOPROTOOPT VMK_NOT_SUPPORTED -# define EPROTONOSUPPORT VMK_EPROTONOSUPPORT -# define ESOCKTNOSUPPORT VMK_NOT_SUPPORTED -# define EOPNOTSUPP VMK_EOPNOTSUPP -# define EPFNOSUPPORT VMK_ADDRFAM_UNSUPP -# define EAFNOSUPPORT VMK_ADDRFAM_UNSUPP -# define EADDRINUSE VMK_EADDRINUSE -# define EADDRNOTAVAIL VMK_EADDRNOTAVAIL -# define ENETDOWN VMK_ENETDOWN -# define ENETUNREACH VMK_ENETUNREACH -# define ENETRESET VMK_ENETRESET -# define ECONNABORTED VMK_ECONNABORTED -# define ECONNRESET VMK_ECONNRESET -# define ENOBUFS VMK_NO_MEMORY -# define ENOMEM VMK_NO_MEMORY -# define EISCONN VMK_ALREADY_CONNECTED -# define ENOTCONN VMK_ENOTCONN -# define ESHUTDOWN VMK_ESHUTDOWN -# define ETIMEDOUT VMK_TIMEOUT -# define ECONNREFUSED VMK_ECONNREFUSED -# define EHOSTDOWN VMK_EHOSTDOWN -# define EHOSTUNREACH VMK_EHOSTUNREACH -# define EPIPE VMK_BROKEN_PIPE -# define __ELOCALSHUTDOWN EPIPE -# define __ELOCALRCVSHUTDOWN 0 -# define __EPEERSHUTDOWN EPIPE -# define __ECONNINPROGRESS EINPROGRESS -# define __ESNDRCVTIMEDOUT VMK_WOULD_BLOCK -# define ESYSNOTREADY VMK_NOT_SUPPORTED -# define EAGAIN VMK_RETRY -#elif defined(__APPLE__) -# define __ELOCALSHUTDOWN ESHUTDOWN -# define __ELOCALRCVSHUTDOWN 0 -# define __EPEERSHUTDOWN ECONNABORTED -# define __ECONNINPROGRESS EINPROGRESS -# define __ESNDRCVTIMEDOUT EAGAIN -# define ESYSNOTREADY EOPNOTSUPP -#elif defined(__linux__) -# define ESYSNOTREADY EOPNOTSUPP -# define __ELOCALSHUTDOWN EPIPE -# define __ELOCALRCVSHUTDOWN 0 -# define __EPEERSHUTDOWN EPIPE -# define __ECONNINPROGRESS EINPROGRESS -# define __ESNDRCVTIMEDOUT EAGAIN -#endif // _WIN32 - - -#if defined(_WIN32) -# define sockerr() WSAGetLastError() -# define sockerr2err(_e) (((_e) < 0) ? -(_e) : (_e)) -# define sockcleanup() WSACleanup() - typedef uint32 socklen_t; - typedef uint32 in_addr_t; -#else // _WIN32 -#if defined(VMKERNEL) -# define SOCKET_ERROR (-1) -# define INVALID_SOCKET ((SOCKET) -1) -# define sockerr() errno -# define sockerr2err(_e) (_e) -# define sockcleanup() do {} while (0) -# define closesocket(_s) close((_s)) - typedef int32 SOCKET; -#else -#if defined(__linux__) || defined(__APPLE__) -# define SOCKET_ERROR (-1) -# define INVALID_SOCKET ((SOCKET) -1) -# define sockerr() errno -# define sockcleanup() do {} while (0) -#if defined(__linux__) -# define sockerr2err(_e) (((_e) > 0) ? -(_e) : (_e)) -# define closesocket(_s) close((_s)) - typedef int32 SOCKET; -#else -# define sockerr2err(_e) (_e) -# define closesocket(_s) VMCISock_close(_s) - typedef int32 SOCKET; -#endif -#endif // linux -#endif // VMKERNEL -#endif // _WIN32 - - -/* - * There is no SS_XXX state equivalent to TCP_LISTEN. Linux does have a flag - * __SO_ACCEPTCON which some of the socket implementations use, but it does - * not fit in the state field (although it is sometimes incorrectly used that - * way). So we define our own listen state here for all platforms. - */ -#define SS_LISTEN 255 - - -/* - * Initialize sockets. This is really for platforms that do not have - * on-by-default socket implementations like Windows. - */ -int sockinit(void); - - -#endif // _VSOCK_SOCKET_WRAPPER_H_ - diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockVmci.h b/open-vm-tools/modules/linux/vsock/linux/vsockVmci.h deleted file mode 100644 index 16606cc24..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsockVmci.h +++ /dev/null @@ -1,168 +0,0 @@ -/********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vsockVmci.h -- - * - * VSockets VMCI constants, types and functions. - */ - - -#ifndef _VSOCK_VMCI_H_ -#define _VSOCK_VMCI_H_ - - -extern VMCIId VMCI_GetContextID(void); - - -/* - *----------------------------------------------------------------------------- - * - * VSockVmci_IsLocal -- - * - * Determine if the given handle points to the local context. - * - * Results: - * TRUE if the given handle is for the local context, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static INLINE Bool -VSockVmci_IsLocal(VMCIHandle handle) // IN -{ - return VMCI_GetContextID() == VMCI_HANDLE_TO_CONTEXT_ID(handle); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmci_ErrorToVSockError -- - * - * Converts from a VMCI error code to a VSock error code. - * - * Results: - * Appropriate error code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE int32 -VSockVmci_ErrorToVSockError(int32 vmciError) // IN -{ - int32 err; - switch (vmciError) { - case VMCI_ERROR_NO_MEM: -#if defined(_WIN32) - err = ENOBUFS; -#else // _WIN32 - err = ENOMEM; -#endif // _WIN32 - break; - case VMCI_ERROR_DUPLICATE_ENTRY: - err = EADDRINUSE; - break; - case VMCI_ERROR_NO_ACCESS: - err = EPERM; - break; - case VMCI_ERROR_NO_RESOURCES: - err = ENOBUFS; - break; - case VMCI_ERROR_INVALID_RESOURCE: - err = EHOSTUNREACH; - break; - case VMCI_ERROR_MODULE_NOT_LOADED: - err = ESYSNOTREADY; - break; - case VMCI_ERROR_NO_HANDLE: - err = ENETUNREACH; - break; - case VMCI_ERROR_INVALID_ARGS: - default: - err = EINVAL; - } - - return sockerr2err(err); -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmci_GetVmciObjSocket -- - * - * Get a socket from a VMCI object, but only if the object is of the - * appropriate type. - * - * Results: - * A socket if the object is of the correct type, NULL otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void * -VSockVmci_GetVmciObjSocket(VMCIObj *obj) // IN -{ - ASSERT(obj); - if (NULL != obj->ptr && VMCIOBJ_SOCKET == obj->type) { - return obj->ptr; - } - return NULL; -} - - -/* - *---------------------------------------------------------------------------- - * - * VSockVmci_SetVmciObjSocket -- - * - * Set the socket in a VMCI object. This will also set the type - * accordingly. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE void -VSockVmci_SetVmciObjSocket(VMCIObj *obj, // OUT - void *s) // IN -{ - ASSERT(obj); - ASSERT(s); - obj->ptr = s; - obj->type = VMCIOBJ_SOCKET; -} - - -#endif // _VSOCK_VMCI_H_ - diff --git a/open-vm-tools/modules/linux/vsock/linux/vsock_version.h b/open-vm-tools/modules/linux/vsock/linux/vsock_version.h deleted file mode 100644 index 52502ca9a..000000000 --- a/open-vm-tools/modules/linux/vsock/linux/vsock_version.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * Copyright (C) 2011-2015 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 - * - *********************************************************/ - -/* - * vsock_version.h -- - * - * Version definitions for the Linux vsock driver. - */ - -#ifndef _VSOCK_VERSION_H_ -#define _VSOCK_VERSION_H_ - -#define VSOCK_DRIVER_VERSION 9.8.1.0 -#define VSOCK_DRIVER_VERSION_COMMAS 9,8,1,0 -#define VSOCK_DRIVER_VERSION_STRING "9.8.1.0" - -#endif /* _VSOCK_VERSION_H_ */