Remove Linux kernel modules from open-vm-tools.
[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
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
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
$(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 \
+++ /dev/null
-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"
+++ /dev/null
-#!/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
-
+++ /dev/null
-/*********************************************************
- * 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 <linux/slab.h>
-
-struct kmem_cache *kmemtest(void) {
- return kmem_cache_create("test", 12, 0, 0, NULL, NULL);
-}
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/slab.h>
-
-struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
- unsigned long,
- void (*)(void *, struct kmem_cache *, unsigned long));
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/slab.h>
-
-struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
- unsigned long,
- void (*)(struct kmem_cache *, void *));
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/dcache.h>
-#include <linux/list.h>
-
-/*
- * 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/dcache.h>
-#include <linux/list.h>
-
-/*
- * 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/dcache.h>
-
-/*
- * 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-
-static int TestFlush(struct file *file);
-{
- return 0;
-}
-
-struct file_operations testFO = {
- .flush = TestFlush,
-};
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#include <linux/types.h> /* 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#include <linux/types.h> /* loff_t */
-#include <linux/stddef.h> /* 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
+++ /dev/null
-/*********************************************************
- * 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
-
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-
-/*
- * 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#include <linux/stddef.h> /* 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/net.h>
-
-static int TestCreate(struct net *net,
- struct socket *sock, int protocol,
- int kern)
-{
- return 0;
-}
-
-struct net_proto_family testFamily = {
- .create = TestCreate,
-};
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/netdevice.h>
-
-#ifdef NETIF_F_GRO
-void test_netif_rx_complete(struct net_device *dev, struct napi_struct *napi)
-{
- netif_rx_complete(dev, napi);
-}
-#endif
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/skbuff.h>
-
-int test_skb_linearize(struct sk_buff *skb)
-{
- return skb_linearize(skb);
-}
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-
-/*
- * 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/types.h> /* 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
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-
-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
+++ /dev/null
-/*********************************************************
- * 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 <linux/autoconf.h>
-#else
-# include <generated/autoconf.h>
-#endif
-
-#endif /* __COMPAT_AUTOCONF_H__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/sched.h>
-#else
-#include <linux/cred.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/dcache.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/ethtool.h>
-
-# 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 */
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-
-/*
- * 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 <linux/pagemap.h>
-# 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/highmem.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/interrupt.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/ioport.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <asm/unistd.h>
-#include <linux/kernel.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/log2.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/mm.h>
-
-
-/* 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/module.h>
-
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/mutex.h>
-
-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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/namei.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/skbuff.h>
-#include <linux/rtnetlink.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/pci.h>
-
-/*
- * 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 <linux/if_ether.h>
-
-# 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/page-flags.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/mm.h>
-#include <asm/page.h>
-
-
-/* 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 <asm/page.h> in 2.2.18, and was moved to <asm/bug.h>
- * 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 <asm/xxx.h> and
- * <linux/xxx.h>, 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/pagemap.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/pci.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <asm/types.h>
-#include <asm/io.h>
-#include <linux/pci.h>
-
-#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
+++ /dev/null
-/*********************************************************
- * 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 <asm/paravirt.h>
-# undef paravirt_map_pt_hook
-# define paravirt_map_pt_hook(type, va, pfn) do {} while (0)
-# endif
-#endif
-#include <asm/pgtable.h>
-
-
-/* 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/sched.h>
-
-/* 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 <linux/unistd.h>
-# include <linux/kernel.h>
-
-/*
- * 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 <linux/freezer.h>
-#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 <linux/errno.h>
-#include <linux/suspend.h>
-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__ */
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <asm/semaphore.h>
-#else
-# include <linux/semaphore.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/skbuff.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/slab.h>
-#else
-# include <linux/malloc.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/stddef.h> /* for NULL */
-#include <net/sock.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/spinlock.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/vfs.h>
-
-/* 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/string.h>
-
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/interrupt.h>
-# endif
-# include <asm/softirq.h>
-
-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 <linux/delay.h>
-# define compat_msleep_interruptible(msecs) msleep_interruptible(msecs)
-# define compat_msleep(msecs) msleep(msecs)
-#else
-# include <linux/sched.h>
-/*
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <asm/uaccess.h>
-#else
-# include <asm/segment.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/version.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/kernel.h>
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)
-# include <linux/workqueue.h>
-#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__ */
-
+++ /dev/null
-/*********************************************************
- * 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 <linux/modversions.h>
-# 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 <linux/types.h>
-# define _STDINT_H 1
-#endif
-
-#ifndef __KERNEL__
-# define __KERNEL__
-#endif
-
-#endif
+++ /dev/null
-/*********************************************************
- * 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 <asm/current.h>
-
-#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);
-}
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/kernel.h>
-# include <linux/string.h>
-#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 <d3d9.h>
-# include <winddi.h>
-# include <stdio.h>
-# 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 <ntddk.h>
-# include "kernelStubsFloorFixes.h"
-# include <ndis.h>
-# elif KRNL_STUBS_DRIVER_TYPE == KRNL_STUBS_DRIVER_TYPE_WDM
-# include "vm_basic_types.h"
-# if defined(NTDDI_WINXP) && (NTDDI_VERSION >= NTDDI_WINXP)
-# include <wdm.h> /* kernel memory APIs, DbgPrintEx */
-# else
-# include <ntddk.h> /* kernel memory APIs */
-# endif
-# include <stdio.h> /* for _vsnprintf, vsprintf */
-# include <stdarg.h> /* for va_start stuff */
-# include <stdlib.h> /* 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 <sys/types.h>
-# include <sys/malloc.h>
-# include <sys/param.h>
-# include <sys/kernel.h>
-# include <machine/stdarg.h>
-# include <sys/libkern.h>
-#elif defined(__APPLE__)
-# include "vm_basic_types.h"
-# ifndef KERNEL
-# error "KERNEL is not defined"
-# endif
-# include <stdarg.h>
-# include <string.h>
-# elif defined(sun)
-# include "vm_basic_types.h"
-# include <sys/types.h>
-# include <sys/varargs.h>
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/slab.h>
-
-#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;
-}
-
-
+++ /dev/null
-/*********************************************************
- * 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 <DriverSpecs.h>
-# 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__
+++ /dev/null
-/*********************************************************
- * 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__ */
-
+++ /dev/null
-/*********************************************************
- * 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__ */
-
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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_<name> defines the filter action values
- * - VMCI_FP_<name> defines the filter protocol values
- * - VMCI_FD_<name> defines the direction values (guest or host)
- * - VMCI_FT_<name> 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_
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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 <sys/ioccom.h>
-#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 <sys/ioccom.h>
-
-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_
+++ /dev/null
-/*********************************************************
- * 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 <ntddk.h>
-#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 <linux/wait.h>
-#endif // linux
-
-#ifdef __APPLE__
-# include <IOKit/IOLib.h>
-# include <mach/task.h>
-# include <mach/semaphore.h>
-# include <sys/kauth.h>
-#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_
+++ /dev/null
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 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.
+++ /dev/null
-#!/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:
+++ /dev/null
-#!/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)))
+++ /dev/null
-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-<kernel version>/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
+++ /dev/null
-/*********************************************************
- * 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 <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/fs.h>
-
-#include <asm/uaccess.h>
-
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/module.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/pagemap.h>
-
-#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,
-};
-
+++ /dev/null
-/*********************************************************
- * 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/mount.h>
-
-#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
-
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/module.h>
-#include <linux/fs.h>
-#include <linux/time.h>
-#include <linux/namei.h>
-
-#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
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/init.h>
-#include <linux/module.h>
-#include <linux/limits.h>
-#include <linux/errno.h>
-
-#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);
+++ /dev/null
-/*********************************************************
- * 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 <linux/completion.h>
-#include <linux/limits.h>
-#include "compat_slab.h"
-#include <linux/sched.h>
-#include <asm/atomic.h>
-#include <asm/errno.h>
-#include <asm/current.h>
-
-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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/fs.h>
-#include <linux/statfs.h>
-
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/version.h>
-#include <linux/mm.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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_ */
+++ /dev/null
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 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.
+++ /dev/null
-#!/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:
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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 <linux/bitops.h> 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/$(<F)"
- $(CC) $(CC_OPTS) $(INCLUDE) -c $<
-
-$(C_TARGETS_COMMON): %.o: $(SRCROOT)/common/%.c
- $(ECHO) "Compiling common/$(<F)"
- $(CC) $(CC_OPTS) $(INCLUDE) -c $<
-
-driverLog.o: $(DRIVERLOGPATH)/driverLog.c
- $(CC) $(CC_OPTS) $(INCLUDE) -c $<
-
-clean:
- rm -rf $(DESTDIR)/
-
-$(C_TARGETS_COMMON_D): %.d: $(SRCROOT)/common/%.c
- $(ECHO) "Dependencies for $(<F)"
- $(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
-
-$(C_TARGETS_LINUX_D): %.d: $(SRCROOT)/linux/%.c
- $(ECHO) "Dependencies for $(<F)"
- $(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
-
-driverLog.d: $(DRIVERLOGPATH)/driverLog.c
- $(ECHO) "Dependencies for $(<F)"
- $(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
-
-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:
+++ /dev/null
-/*********************************************************
- * 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_ */
+++ /dev/null
-/*********************************************************
- * 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
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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;
-}
+++ /dev/null
-/*********************************************************
- * 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_
-
-
+++ /dev/null
-/*********************************************************
- * 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__
+++ /dev/null
-/*********************************************************
- * 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
+++ /dev/null
-/*********************************************************
- * 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();
-}
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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;
-}
+++ /dev/null
-/*********************************************************
- * 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__
+++ /dev/null
-/*********************************************************
- * 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);
-}
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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 */
+++ /dev/null
-/*********************************************************
- * 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 */
+++ /dev/null
-/*********************************************************
- * 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_ */
-
+++ /dev/null
-/*********************************************************
- * 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);
-}
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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 "";
-}
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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 <asm/atomic.h>
-#include <asm/io.h>
-
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
-# include <linux/ioctl32.h>
-/* 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 <linux/miscdevice.h>
-#include <linux/moduleparam.h>
-#include <linux/poll.h>
-#include <linux/smp.h>
-
-#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");
+++ /dev/null
-/*********************************************************
- * 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 <linux/mm.h> /* For vmalloc_to_page() and get_user_pages()*/
-#include <linux/pagemap.h> /* For page_cache_release() */
-#include <linux/socket.h> /* For memcpy_{to,from}iovec(). */
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-
-#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);
-}
+++ /dev/null
-/*********************************************************
- * 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_ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/highmem.h>
-
-#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__ */
+++ /dev/null
-/*********************************************************
- * 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 <sys/uio.h>
-#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_ */
-
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 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.
+++ /dev/null
-#!/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:
+++ /dev/null
-#!/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)))
+++ /dev/null
-/*********************************************************
- * 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 <linux/errno.h>
-
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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;
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/errno.h>
-#include <linux/module.h>
-#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);
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/errno.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
-#include <linux/uio.h> /* 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 <linux/aio.h>
-#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
-
-
+++ /dev/null
-/*********************************************************
- * 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 <asm/atomic.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/pagemap.h>
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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 <linux/signal.h>
-
-/* 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);
-
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/signal.h>
-#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 <linux/hash.h>
-
-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_
+++ /dev/null
-/*********************************************************
- * 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 <linux/errno.h>
-#include <linux/pagemap.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
-#include <linux/namei.h>
-#endif
-#include <linux/highmem.h>
-#include <linux/time.h> // 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;
-}
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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
- }
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/errno.h>
-#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();
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/backing-dev.h>
-#endif
-#include <asm/atomic.h>
-#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_
+++ /dev/null
-/*********************************************************
- * 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 <linux/pagemap.h>
-
-#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 <linux/writeback.h>
-
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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 <asm/atomic.h>
-#include <linux/list.h>
-#include <linux/signal.h>
-#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);
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/kref.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#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_
+++ /dev/null
-/*********************************************************
- * 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.
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/vfs.h>
-#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;
-}
+++ /dev/null
-/*********************************************************
- * 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 <linux/errno.h>
-#include <linux/list.h>
-#include "compat_mutex.h"
-#include "compat_sched.h"
-#include "compat_spinlock.h"
-#include "compat_version.h"
-
-/* Must be included after semaphore.h. */
-#include <linux/timer.h>
-/* Must be included after sched.h. */
-#include <linux/interrupt.h> /* 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__));
-}
-
-
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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_ */
+++ /dev/null
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 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.
+++ /dev/null
-#!/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:
+++ /dev/null
-#!/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)))
+++ /dev/null
-/*********************************************************
- * 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 <asm/bug.h>
-#include <asm/uaccess.h>
-#include <asm/string.h>
-#include <linux/buffer_head.h>
-#include <linux/proc_fs.h>
-
-#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);
-}
-
+++ /dev/null
-/*********************************************************
- * 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_ */
+++ /dev/null
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 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.
+++ /dev/null
-#!/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:
+++ /dev/null
-#!/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)))
+++ /dev/null
-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/<kernel-name>/net.
-
-If you have any problems or questions, send mail to support@vmware.com
+++ /dev/null
-/*********************************************************
- * 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 <linux/moduleparam.h>
-#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 <linux/etherdevice.h>
-#include "compat_ioport.h"
-#ifndef KERNEL_2_1
-#include <linux/delay.h>
-#endif
-#include "compat_interrupt.h"
-
-#include <linux/init.h>
-
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-
-#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 <net/checksum.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-
-/*
- * 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");
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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_ */
+++ /dev/null
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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.
-
- <signature of Ty Coon>, 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.
+++ /dev/null
-#!/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:
+++ /dev/null
-#!/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
+++ /dev/null
-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-<kernel version>/vsock-<kernel-version>
-
-(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
+++ /dev/null
-/*********************************************************
- * 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 <linux/kmod.h>
-#include <linux/socket.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/miscdevice.h>
-#include <linux/poll.h>
-#include <linux/smp.h>
-#include <linux/bitops.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
-# include <linux/ioctl32.h>
-/* 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
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/socket.h>
-
-#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,
-};
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <linux/socket.h>
-
-#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,
-};
+++ /dev/null
-/*********************************************************
- * 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 <linux/socket.h>
-#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
+++ /dev/null
-/*********************************************************
- * 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__
+++ /dev/null
-/*********************************************************
- * 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 <linux/list.h>
-#include <linux/socket.h>
-#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);
-}
+++ /dev/null
-/*********************************************************
- * 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__ */
+++ /dev/null
-/*********************************************************
- * 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 <windef.h>
-# include <ws2def.h>
- typedef WSACMSGHDR CMSGHDR, *PCMSGHDR;
-# endif // (_WIN32_WINNT < 0x0600)
-# include <wsk.h>
- 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_
-
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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 <linux/socket.h>
-# include "compat_sock.h"
-# else
-# include <string.h>
-# include <errno.h>
-# endif
-#elif defined(VMKERNEL)
-# include "vm_libc.h"
-# include "return_status.h"
-#elif defined(__APPLE__)
-# include <sys/errno.h>
-#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 <context id, resource id> 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;
-}
+++ /dev/null
-/*********************************************************
- * 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_
-
+++ /dev/null
-/*********************************************************
- * 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 <ntddk.h>
-# include <windef.h>
-# 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 <windows.h>
-# 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 <IOKit/system.h>
-# 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 <winsock2.h>
-#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_
+++ /dev/null
-/*********************************************************
- * 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_
+++ /dev/null
-/*********************************************************
- * 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_
-
+++ /dev/null
-/*********************************************************
- * 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_
-
+++ /dev/null
-/*********************************************************
- * 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_ */