diff options
Diffstat (limited to 'open-vm-tools/modules/linux')
69 files changed, 1753 insertions, 2167 deletions
diff --git a/open-vm-tools/modules/linux/dkms.conf b/open-vm-tools/modules/linux/dkms.conf index 908132e6..7d93e317 100644 --- a/open-vm-tools/modules/linux/dkms.conf +++ b/open-vm-tools/modules/linux/dkms.conf @@ -1,5 +1,5 @@ PACKAGE_NAME=open-vm-tools -PACKAGE_VERSION=2013.09.16 +PACKAGE_VERSION=2015.01.29 MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \ MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build" diff --git a/open-vm-tools/modules/linux/dkms.sh b/open-vm-tools/modules/linux/dkms.sh index 6626c183..c0cb59c8 100644 --- a/open-vm-tools/modules/linux/dkms.sh +++ b/open-vm-tools/modules/linux/dkms.sh @@ -1,6 +1,6 @@ #!/bin/sh ################################################################################ -### Copyright 2009 VMware, Inc. All rights reserved. +### Copyright (C) 2009-2015 VMware, Inc. All rights reserved. ### ### Script for creating a dmks-compliant source tree from an open-vm-tools ### distribution. @@ -28,12 +28,12 @@ then 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 2013.09.16." + echo "The script will create an 'open-vm-tools' module with version 2015.01.29." exit 1 fi src=$1 -dst=$2/open-vm-tools-2013.09.16 +dst=$2/open-vm-tools-2015.01.29 SHARED_HEADERS="backdoor_def.h" SHARED_HEADERS="$SHARED_HEADERS backdoor_types.h" diff --git a/open-vm-tools/modules/linux/shared/autoconf/dcount.c b/open-vm-tools/modules/linux/shared/autoconf/dcount.c new file mode 100644 index 00000000..c78968d0 --- /dev/null +++ b/open-vm-tools/modules/linux/shared/autoconf/dcount.c @@ -0,0 +1,43 @@ +/********************************************************* + * 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 diff --git a/open-vm-tools/modules/linux/shared/autoconf/file_operations_flush.c b/open-vm-tools/modules/linux/shared/autoconf/file_operations_flush.c new file mode 100644 index 00000000..818aee32 --- /dev/null +++ b/open-vm-tools/modules/linux/shared/autoconf/file_operations_flush.c @@ -0,0 +1,46 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * 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 diff --git a/open-vm-tools/modules/linux/shared/compat_cred.h b/open-vm-tools/modules/linux/shared/compat_cred.h index 8f02001a..95a7baa7 100644 --- a/open-vm-tools/modules/linux/shared/compat_cred.h +++ b/open-vm-tools/modules/linux/shared/compat_cred.h @@ -40,4 +40,8 @@ #define cap_set_full(_c) do { (_c) = CAP_FULL_SET; } while (0) #endif +#if !defined(GLOBAL_ROOT_UID) +#define GLOBAL_ROOT_UID (0) +#endif + #endif /* __COMPAT_CRED_H__ */ diff --git a/open-vm-tools/modules/linux/shared/compat_dcache.h b/open-vm-tools/modules/linux/shared/compat_dcache.h index 0450aeef..d16fd1d3 100644 --- a/open-vm-tools/modules/linux/shared/compat_dcache.h +++ b/open-vm-tools/modules/linux/shared/compat_dcache.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * 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 @@ -25,7 +25,7 @@ * 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_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) diff --git a/open-vm-tools/modules/linux/shared/compat_skbuff.h b/open-vm-tools/modules/linux/shared/compat_skbuff.h index d1a72a5e..b6468855 100644 --- a/open-vm-tools/modules/linux/shared/compat_skbuff.h +++ b/open-vm-tools/modules/linux/shared/compat_skbuff.h @@ -35,9 +35,15 @@ #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) -#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)) +#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) diff --git a/open-vm-tools/modules/linux/shared/kernelStubs.h b/open-vm-tools/modules/linux/shared/kernelStubs.h index 800a0cf8..c242fccd 100644 --- a/open-vm-tools/modules/linux/shared/kernelStubs.h +++ b/open-vm-tools/modules/linux/shared/kernelStubs.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -27,6 +27,21 @@ #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" @@ -36,12 +51,32 @@ # include <linux/kernel.h> # include <linux/string.h> #elif defined(_WIN32) -# include "vm_basic_types.h" -# include <ntddk.h> /* kernel memory APIs */ -# include <stdio.h> /* for _vsnprintf, vsprintf */ -# include <stdarg.h> /* for va_start stuff */ -# include <stdlib.h> /* for min macro. */ -# include "vm_assert.h" /* Our assert macros */ +# 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 <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 */ +# else +# error Type KRNL_STUBS_DRIVER_TYPE must be defined. +# endif #elif defined(__FreeBSD__) # include "vm_basic_types.h" # ifndef _KERNEL @@ -65,6 +100,7 @@ # include <sys/types.h> # include <sys/varargs.h> #endif +#include "kernelStubsSal.h" /* * Function Prototypes @@ -84,19 +120,41 @@ void *realloc(void *ptr, size_t newSize); #elif defined(_WIN32) /* } else if (_WIN32) { */ -#if (_WIN32_WINNT == 0x0400) -/* The following declarations are missing on NT4. */ -typedef unsigned int UINT_PTR; -typedef unsigned int SIZE_T; +_Ret_allocates_malloc_mem_opt_bytecap_(_Size) +_When_windrv_(_IRQL_requires_max_(DISPATCH_LEVEL)) +_CRTNOALIAS _CRTRESTRICT +void * __cdecl malloc( + _In_ size_t _Size); -/* No free with tag availaible on NT4 kernel! */ -#define KRNL_STUBS_FREE(P,T) ExFreePool((P)) +_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); -#else /* _WIN32_WINNT */ -#define KRNL_STUBS_FREE(P,T) ExFreePoolWithTag((P),(T)) -/* Win 2K and later useful kernel function, documented but not declared! */ -NTKERNELAPI VOID ExFreePoolWithTag(IN PVOID P, IN ULONG Tag); -#endif /* _WIN32_WINNT */ +_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) { */ @@ -127,23 +185,84 @@ __compat_malloc(unsigned long size, struct malloc_type *type, int flags) { #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 Panic(const char *fmt, ...); - -char *Str_Strcpy(char *buf, const char *src, size_t maxSize); -int Str_Vsnprintf(char *str, size_t size, const char *format, - va_list arguments); -char *Str_Vasprintf(size_t *length, const char *format, - va_list arguments); -char *Str_Asprintf(size_t *length, const char *Format, ...); +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(const char *fmt, ...); +EXTERN void Debug( + _In_z_ _Printf_format_string_ const char *fmt, + ...) PRINTF_DECL(1, 2); +#endif // KRNL_STUBS_DRIVER_TYPE != KRNL_STUBS_DRIVER_TYPE_GDI + +#ifdef _WIN32 +#pragma warning(pop) +#endif #endif /* __KERNELSTUBS_H__ */ diff --git a/open-vm-tools/modules/linux/shared/kernelStubsLinux.c b/open-vm-tools/modules/linux/shared/kernelStubsLinux.c index 221f88a6..b8579fca 100644 --- a/open-vm-tools/modules/linux/shared/kernelStubsLinux.c +++ b/open-vm-tools/modules/linux/shared/kernelStubsLinux.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * 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 @@ -91,13 +91,15 @@ Str_Strcpy(char *buf, // OUT const char *src, // IN size_t maxSize) // IN { - unsigned int *stack = (unsigned int *)&buf; size_t len; len = strlen(src); if (len >= maxSize) { - Panic("%s:%d Buffer too small 0x%x\n", __FILE__,__LINE__, - stack[-1]); +#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); } diff --git a/open-vm-tools/modules/linux/shared/kernelStubsSal.h b/open-vm-tools/modules/linux/shared/kernelStubsSal.h new file mode 100644 index 00000000..6938aed5 --- /dev/null +++ b/open-vm-tools/modules/linux/shared/kernelStubsSal.h @@ -0,0 +1,134 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * 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). We target multiple versions of + * Driver Kits, so we have to map 2.0 to 1.0. + * 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) +#define _In_ +#define _In_z_ +#define _In_opt_ +#define _In_opt_z_ +#define _Out_ +#define _Out_opt_ +#define _Out_z_cap_(e) +#define _Inout_ +#define _Inout_z_cap_(e) +#define _Post_z_count_(e) +#define _Ret_writes_z_(e) +#define _Ret_writes_maybenull_z_(e) +#define _Ret_maybenull_z_ +#define _Success_(expr) +#define _Check_return_ +#define _Must_inspect_result_ +#define _Group_(annos) +#define _When_(expr, annos) +#define _Printf_format_string_ +#define _Use_decl_annotations_ +#elif _SAL_VERSION == 10 +// Microsoft didn't create a header mapping SAL 2.0 to 1.0. We do that here. +#define _In_ __in +#define _In_z_ __in_z +#define _In_opt_ __in_opt +#define _In_opt_z_ __in_z_opt +#define _Out_ __out +#define _Out_opt_ __out_opt +#define _Out_z_cap_(expr) __out_ecount_z(expr) +#define _Inout_ __inout +#define _Inout_z_cap_(expr) __inout_ecount_z(expr) +#define _Post_z_count_(expr) +#define _Ret_writes_z_(expr) __out_ecount_z(expr) +#define _Ret_writes_maybenull_z_(expr) __out_ecount_z_opt(expr) +#define _Ret_maybenull_z_ __out_z +#define _Check_return_ __checkReturn +#define _Must_inspect_result_ __checkReturn +#define _Success_(annos) __success(annos) +#define _Printf_format_string_ __format_string +#define _Use_decl_annotations_ + +// DriverSpecs.h was pretty much empty until the DDK that defined +// NTDDK_WIN6SP1 appeared. +#if defined(NTDDI_WIN6SP1) +#define _Group_(annos) __$drv_group(annos) +#define _When_(expr, annos) __drv_when(expr, annos) +#define _IRQL_requires_max_(irql) __drv_maxIRQL(irql) +#else +#define _Group_(annos) +#define _When_(expr, annos) +#define _IRQL_requires_max_(irql) +#define __drv_allocatesMem(kind) +#define __drv_freesMem(kind) +#endif + +#else +// Sal 2.0 path - everything is already defined. +#endif // _SAL_VERSION + +// Now define our own annotations +#if !defined(_SAL_VERSION) +#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_ +#elif _SAL_VERSION == 10 +#define _When_windrv_(annos) annos +#define _Ret_allocates_malloc_mem_opt_bytecap_(_Cap) __drv_allocatesMem("Memory") __checkReturn __post __byte_writableTo(_Cap) __exceptthat __maybenull +#define _Ret_allocates_malloc_mem_opt_bytecount_(_Count) __drv_allocatesMem("Memory") __checkReturn __post __byte_readableTo(_Count) __exceptthat __maybenull +#define _Ret_allocates_malloc_mem_opt_bytecap_post_bytecount_(_Cap,_Count) __drv_allocatesMem("Memory") __checkReturn __post __byte_writableTo(_Cap) __byte_readableTo(_Count) __exceptthat __maybenull +#define _Ret_allocates_malloc_mem_opt_z_bytecount_(_Count) __drv_allocatesMem("Memory") __checkReturn __post __byte_readableTo(_Count) __valid __nullterminated __exceptthat __maybenull +#define _Ret_allocates_malloc_mem_opt_z_ __drv_allocatesMem("Memory") __checkReturn __post __valid __nullterminated __exceptthat __maybenull +#define _In_frees_malloc_mem_opt_ __drv_freesMem("Memory") __in_opt __post __notvalid +#else +#define _When_windrv_(annos) annos +#define _Ret_allocates_malloc_mem_opt_bytecap_(_Cap) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_bytecap_(_Cap) +#define _Ret_allocates_malloc_mem_opt_bytecount_(_Count) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_bytecount_(_Count) +#define _Ret_allocates_malloc_mem_opt_bytecap_post_bytecount_(_Cap,_Count) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_bytecap_(_Cap) _Ret_opt_bytecount_(_Count) +#define _Ret_allocates_malloc_mem_opt_z_bytecount_(_Count) __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_z_bytecount_(_Count) +#define _Ret_allocates_malloc_mem_opt_z_ __drv_allocatesMem("Memory") _Must_inspect_result_ _Ret_opt_z_ +#define _In_frees_malloc_mem_opt_ __drv_freesMem("Memory") _Pre_maybenull_ _Post_invalid_ +#endif // _SAL_VERSION + +// Best we can do for reallocate with simple annotations: assume old size was fully initialized. +#define _Ret_reallocates_malloc_mem_opt_newbytecap_oldbytecap_(_NewSize, _OldSize) _Ret_allocates_malloc_mem_opt_bytecap_post_bytecount_(_NewSize, _OldSize <= _NewSize ? _OldSize : _NewSize) +#define _Ret_reallocates_malloc_mem_opt_newbytecap_(_NewSize) _Ret_allocates_malloc_mem_opt_z_bytecount_(_NewSize) +#define _In_reallocates_malloc_mem_opt_oldptr_ _In_frees_malloc_mem_opt_ + +#endif // __KERNELSTUBSSAL_H__ diff --git a/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h b/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h index 10ce7912..dc528180 100644 --- a/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h +++ b/open-vm-tools/modules/linux/shared/vmciKernelAPI1.h @@ -91,7 +91,11 @@ 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); @@ -140,9 +144,9 @@ 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 (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ - (defined(__linux__) && defined(__KERNEL__)) || \ - (defined(_WIN32) && defined(WINNT_DDK)) +#if (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ + (defined(__linux__) && defined(__KERNEL__)) || \ + (defined(_WIN32) && defined(WINNT_DDK)) /* * Environments that support struct iovec */ diff --git a/open-vm-tools/modules/linux/shared/vmci_defs.h b/open-vm-tools/modules/linux/shared/vmci_defs.h index c0843359..74d314ff 100644 --- a/open-vm-tools/modules/linux/shared/vmci_defs.h +++ b/open-vm-tools/modules/linux/shared/vmci_defs.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2005-2012 VMware, Inc. All rights reserved. + * Copyright (C) 2005-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 @@ -30,6 +30,7 @@ #include "includeCheck.h" #include "vm_basic_types.h" +#include "vm_basic_defs.h" #include "vm_atomic.h" #include "vm_assert.h" diff --git a/open-vm-tools/modules/linux/shared/vmci_infrastructure.h b/open-vm-tools/modules/linux/shared/vmci_infrastructure.h index 73e37c3c..099b5268 100644 --- a/open-vm-tools/modules/linux/shared/vmci_infrastructure.h +++ b/open-vm-tools/modules/linux/shared/vmci_infrastructure.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * 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 @@ -65,12 +65,14 @@ typedef struct VMCIDoorbellCptState { } 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_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 diff --git a/open-vm-tools/modules/linux/shared/vmci_iocontrols.h b/open-vm-tools/modules/linux/shared/vmci_iocontrols.h index e1355ec3..ce99894a 100644 --- a/open-vm-tools/modules/linux/shared/vmci_iocontrols.h +++ b/open-vm-tools/modules/linux/shared/vmci_iocontrols.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. + * Copyright (C) 2007-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 @@ -154,7 +154,7 @@ VMCIPtrToVA64(void const *ptr) // IN #define VMCI_SOCKETS_MAKE_VERSION(_p) \ ((((_p)[0] & 0xFF) << 24) | (((_p)[1] & 0xFF) << 16) | ((_p)[2])) -#if defined(__linux__) || defined(SOLARIS) || defined(VMKERNEL) +#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 @@ -317,12 +317,12 @@ enum IOCTLCmd_VMCI { * The size of this must match the size of VSockIoctlPrivSyms in * modules/vsock/common/vsockIoctl.h. */ -#include "vmware_pack_begin.h" +#pragma pack(push, 1) struct IOCTLCmd_VMCIMacOS_PrivSyms { char data[344]; -} -#include "vmware_pack_end.h" -; +}; +#pragma pack(pop) + enum IOCTLCmd_VMCIMacOS { IOCTLCMD_I(SOCKETS_SET_SYMBOLS, struct IOCTLCmd_VMCIMacOS_PrivSyms), IOCTLCMD_O(SOCKETS_VERSION, unsigned int), diff --git a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h index 29c609df..ef8a5520 100644 --- a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h +++ b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h @@ -28,7 +28,7 @@ #define _VMCI_KERNEL_IF_H_ #if !defined(linux) && !defined(_WIN32) && !defined(__APPLE__) && \ - !defined(VMKERNEL) && !defined(SOLARIS) + !defined(VMKERNEL) # error "Platform not supported." #endif @@ -55,21 +55,12 @@ #ifdef VMKERNEL # include "splock.h" +# include "splock_customRanks.h" # include "semaphore_ext.h" # include "vmkapi.h" # include "world_dist.h" #endif -#ifdef SOLARIS -# include <sys/ddi.h> -# include <sys/kmem.h> -# include <sys/mutex.h> -# include <sys/poll.h> -# include <sys/semaphore.h> -# include <sys/sunddi.h> -# include <sys/types.h> -#endif - #include "vm_basic_types.h" #include "vmci_defs.h" @@ -110,7 +101,11 @@ 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; @@ -132,14 +127,6 @@ typedef PMDL VMCIPpnList; /* MDL to map the produce/consume queue. */ typedef PSID VMCIHostUser; typedef VA64 *VMCIQPGuestMem; -#elif defined(SOLARIS) - typedef kmutex_t VMCILock; - typedef unsigned long VMCILockFlags; - typedef ksema_t VMCIEvent; - typedef kmutex_t VMCIMutex; - typedef PPN *VMCIPpnList; /* List of PPNs in produce/consume queue. */ - typedef uid_t VMCIHostUser; - typedef VA64 VMCIQPGuestMem; #endif // VMKERNEL /* Callback needed for correctly waiting on events. */ @@ -205,11 +192,6 @@ typedef struct VMCIHost { KEVENT *callEvent; /* Ptr to userlevel event used when signalling * new pending guestcalls in kernel. */ -#elif defined(SOLARIS) - struct pollhead pollhead; /* Per datagram handle pollhead structure to - * be treated as a black-box. None of its - * fields should be referenced. - */ #endif } VMCIHost; @@ -223,9 +205,6 @@ typedef struct VMCIHost { #elif defined(_WIN32) typedef PUCHAR VMCIIoPort; typedef int VMCIIoHandle; -#elif defined(SOLARIS) - typedef uint8_t * VMCIIoPort; - typedef ddi_acc_handle_t VMCIIoHandle; #elif defined(__APPLE__) typedef unsigned short int VMCIIoPort; typedef void *VMCIIoHandle; @@ -260,6 +239,8 @@ 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) @@ -296,7 +277,7 @@ Bool VMCI_WaitOnEventInterruptible(VMCIEvent *event, #endif #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \ - defined(__APPLE__) || defined(SOLARIS)) + defined(__APPLE__)) int VMCI_CopyFromUser(void *dst, VA64 src, size_t len); #endif @@ -309,16 +290,16 @@ void VMCIMutex_Destroy(VMCIMutex *mutex); void VMCIMutex_Acquire(VMCIMutex *mutex); void VMCIMutex_Release(VMCIMutex *mutex); -#if defined(SOLARIS) || defined(_WIN32) || defined(__APPLE__) +#if defined(_WIN32) || defined(__APPLE__) int VMCIKernelIf_Init(void); void VMCIKernelIf_Exit(void); #if defined(_WIN32) void VMCIKernelIf_DrainDelayedWork(void); #endif // _WIN32 -#endif // SOLARIS || _WIN32 || __APPLE__ +#endif // _WIN32 || __APPLE__ -#if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \ - defined(SOLARIS) || defined(__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 { @@ -393,12 +374,12 @@ typedef uint32 VMCIGuestMemID; void VMCI_LockQueueHeader(struct VMCIQueue *queue); void VMCI_UnlockQueueHeader(struct VMCIQueue *queue); #else -# define VMCI_LockQueueHeader(_q) ASSERT_NOT_IMPLEMENTED(FALSE) -# define VMCI_UnlockQueueHeader(_q) ASSERT_NOT_IMPLEMENTED(FALSE) +# define VMCI_LockQueueHeader(_q) NOT_IMPLEMENTED() +# define VMCI_UnlockQueueHeader(_q) NOT_IMPLEMENTED() #endif #if (!defined(VMKERNEL) && defined(__linux__)) || defined(_WIN32) || \ - defined(__APPLE__) || defined(SOLARIS) + defined(__APPLE__) int VMCIHost_GetUserMemory(VA64 produceUVA, VA64 consumeUVA, struct VMCIQueue *produceQ, struct VMCIQueue *consumeQ); @@ -406,7 +387,7 @@ typedef uint32 VMCIGuestMemID; struct VMCIQueue *consumeQ); #else # define VMCIHost_GetUserMemory(_puva, _cuva, _pq, _cq) VMCI_ERROR_UNAVAILABLE -# define VMCIHost_ReleaseUserMemory(_pq, _cq) ASSERT_NOT_IMPLEMENTED(FALSE) +# define VMCIHost_ReleaseUserMemory(_pq, _cq) NOT_IMPLEMENTED() #endif #if defined(_WIN32) diff --git a/open-vm-tools/modules/linux/vmblock/Makefile b/open-vm-tools/modules/linux/vmblock/Makefile index 36529cd6..21e5dc16 100644 --- a/open-vm-tools/modules/linux/vmblock/Makefile +++ b/open-vm-tools/modules/linux/vmblock/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 diff --git a/open-vm-tools/modules/linux/vmci/Makefile b/open-vm-tools/modules/linux/vmci/Makefile index 3ff28c4b..05aa915c 100644 --- a/open-vm-tools/modules/linux/vmci/Makefile +++ b/open-vm-tools/modules/linux/vmci/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 diff --git a/open-vm-tools/modules/linux/vmci/Makefile.kernel b/open-vm-tools/modules/linux/vmci/Makefile.kernel index ba343eea..8e6e7d0b 100644 --- a/open-vm-tools/modules/linux/vmci/Makefile.kernel +++ b/open-vm-tools/modules/linux/vmci/Makefile.kernel @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 2007 VMware, Inc. All rights reserved. +# 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 @@ -55,7 +55,7 @@ endif # # If this build generated a Module.symvers, copy it to a public place where -# the VMCI Sockets build will be able to find it. +# the vSockets build will be able to find it. # postbuild:: ifeq ($(call vm_check_file,$(SRCROOT)/Module.symvers), yes) diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.c b/open-vm-tools/modules/linux/vmci/common/vmciContext.c index 513e93d4..5ebd28ab 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciContext.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2012 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -577,8 +577,9 @@ VMCIContext_PendingDatagrams(VMCIId cid, // IN */ int -VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM - VMCIDatagram *dg) // IN: +VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM + VMCIDatagram *dg, // IN: + Bool notify) // IN: { DatagramQueueEntry *dqEntry; VMCIContext *context; @@ -648,8 +649,12 @@ VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM VMCIList_Insert(&dqEntry->listItem, &context->datagramQueue); context->pendingDatagrams++; context->datagramQueueSize += vmciDgSize; - VMCIContextSignalNotify(context); - VMCIHost_SignalCall(&context->hostContext); + + if (notify) { + VMCIContextSignalNotify(context); + VMCIHost_SignalCall(&context->hostContext); + } + VMCI_ReleaseLock(&context->lock, flags); VMCIContext_Release(context); @@ -809,7 +814,7 @@ VMCIContext_Release(VMCIContext *context) // IN { uint32 refCount; ASSERT(context); - refCount = Atomic_FetchAndDec(&context->refCount); + refCount = Atomic_ReadDec32(&context->refCount); if (refCount == 1) { VMCIContextFreeContext(context); } @@ -1489,6 +1494,143 @@ VMCIContextFireNotification(VMCIId contextID, // IN 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; + + *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_NORMAL); + if (p == NULL) { + return VMCI_ERROR_NO_MEM; + } + + *cptBufPtr = 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; +} + /* *---------------------------------------------------------------------- @@ -1546,6 +1688,12 @@ VMCIContext_GetCheckpointState(VMCIId contextID, // IN: 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; @@ -1589,10 +1737,9 @@ VMCIContext_GetCheckpointState(VMCIId contextID, // IN: } result = VMCI_SUCCESS; - release: +release: VMCI_ReleaseLock(&context->lock, flags); VMCIContext_Release(context); - return result; } @@ -2081,7 +2228,7 @@ VMCIContext_SignalPendingDoorbells(VMCIId contextID) VMCI_ReleaseLock(&context->lock, flags); if (pending) { - VMCIHost_SignalBitmap(&context->hostContext); + VMCIHost_SignalBitmapAlways(&context->hostContext); } VMCIContext_Release(context); @@ -2125,7 +2272,7 @@ VMCIContext_SignalPendingDatagrams(VMCIId contextID) VMCI_ReleaseLock(&context->lock, flags); if (pending) { - VMCIHost_SignalCall(&context->hostContext); + VMCIHost_SignalCallAlways(&context->hostContext); } VMCIContext_Release(context); @@ -2207,7 +2354,7 @@ VMCI_EXPORT_SYMBOL(vmci_is_context_owner) #if defined(linux) && !defined(VMKERNEL) int vmci_is_context_owner(VMCIId contextID, // IN - uid_t uid) // IN + VMCIHostUser uid) // IN { int isOwner = 0; @@ -2215,7 +2362,7 @@ vmci_is_context_owner(VMCIId contextID, // IN VMCIContext *context = VMCIContext_Get(contextID); if (context) { if (context->validUser) { - if (VMCIHost_CompareUser((VMCIHostUser *)&uid, + if (VMCIHost_CompareUser(&uid, &context->user) == VMCI_SUCCESS) { isOwner = 1; } diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.h b/open-vm-tools/modules/linux/vmci/common/vmciContext.h index de0201ef..07fc3658 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.h +++ b/open-vm-tools/modules/linux/vmci/common/vmciContext.h @@ -68,7 +68,7 @@ void VMCIContext_SetId(VMCIContext *context, VMCIId cid); #endif Bool VMCIContext_SupportsHostQP(VMCIContext *context); void VMCIContext_ReleaseContext(VMCIContext *context); -int VMCIContext_EnqueueDatagram(VMCIId cid, VMCIDatagram *dg); +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); diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c b/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c index 2f17a182..7fd7674a 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciDatagram.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * 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 @@ -622,7 +622,7 @@ VMCIDatagramDispatchAsHost(VMCIId contextID, // IN: VMCI_CanScheduleDelayedWork())) { VMCIDelayedDatagramInfo *dgInfo; - if (Atomic_FetchAndAdd(&delayedDGHostQueueSize, 1) == + if (Atomic_ReadInc32(&delayedDGHostQueueSize) == VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) { Atomic_Dec(&delayedDGHostQueueSize); VMCIResource_Release(resource); @@ -692,7 +692,7 @@ VMCIDatagramDispatchAsHost(VMCIId contextID, // IN: return VMCI_ERROR_NO_MEM; } memcpy(newDG, dg, dgSize); - retval = VMCIContext_EnqueueDatagram(dg->dst.context, newDG); + retval = VMCIContext_EnqueueDatagram(dg->dst.context, newDG, TRUE); if (retval < VMCI_SUCCESS) { VMCI_FreeKernelMem(newDG, dgSize); VMCI_DEBUG_LOG(4, (LGPFX"Enqueue failed\n")); @@ -844,6 +844,12 @@ VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN 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", diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c b/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c index 74053e15..5a3fbfd5 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciDoorbell.c @@ -41,7 +41,7 @@ #define LGPFX "VMCIDoorbell: " -#if !defined(SOLARIS) && !defined(__APPLE__) +#if !defined(__APPLE__) #define VMCI_DOORBELL_INDEX_TABLE_SIZE 64 #define VMCI_DOORBELL_HASH(_idx) \ @@ -1160,7 +1160,7 @@ VMCI_ScanNotificationBitmap(uint8 *bitmap) } -#else // SOLARIS) || __APPLE__ +#else // __APPLE__ /* *----------------------------------------------------------------------------- @@ -1238,4 +1238,4 @@ VMCIDoorbell_Exit(void) { } -#endif // SOLARIS) || __APPLE__ +#endif // __APPLE__ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciDriver.c b/open-vm-tools/modules/linux/vmci/common/vmciDriver.c index bd0b4964..4a379585 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciDriver.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciDriver.c @@ -124,7 +124,7 @@ VMCI_HostCleanup(void) } -#if defined(__APPLE__) || defined(SOLARIS) || defined(VMKERNEL) +#if defined(__APPLE__) || defined(VMKERNEL) /* Windows has its own implementation of this, and Linux doesn't need one. */ /* *---------------------------------------------------------------------- @@ -189,7 +189,7 @@ void vmci_device_release(void *deviceRegistration) // UNUSED { } -#endif // __APPLE__ || SOLARIS || VMKERNEL +#endif // __APPLE__ || VMKERNEL /* diff --git a/open-vm-tools/modules/linux/vmci/common/vmciQPair.c b/open-vm-tools/modules/linux/vmci/common/vmciQPair.c index dbc64922..7a021278 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciQPair.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciQPair.c @@ -1234,9 +1234,9 @@ vmci_qpair_peek(VMCIQPair *qpair, // IN } -#if defined (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ - (defined(__linux__) && defined(__KERNEL__)) || \ - (defined(_WIN32) && defined(WINNT_DDK)) +#if (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ + (defined(__linux__) && defined(__KERNEL__)) || \ + (defined(_WIN32) && defined(WINNT_DDK)) /* *----------------------------------------------------------------------------- diff --git a/open-vm-tools/modules/linux/vmci/common/vmciRoute.c b/open-vm-tools/modules/linux/vmci/common/vmciRoute.c index b73d3867..cc98b93c 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciRoute.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciRoute.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2011-2012 VMware, Inc. All rights reserved. + * 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 @@ -114,17 +114,6 @@ VMCI_Route(VMCIHandle *src, // IN/OUT return VMCI_ERROR_INVALID_ARGS; } - /* - * If the client passed the ANON source handle then respect it (both - * context and resource are invalid). However, if they passed only - * an invalid context, then they probably mean ANY, in which case we - * should set the real context here before passing it down. - */ - - if (VMCI_INVALID_ID == src->context && VMCI_INVALID_ID != src->resource) { - src->context = vmci_get_context_id(); - } - /* Send from local client down to the hypervisor. */ *route = VMCI_ROUTE_AS_GUEST; return VMCI_SUCCESS; diff --git a/open-vm-tools/modules/linux/vmci/linux/driver.c b/open-vm-tools/modules/linux/vmci/linux/driver.c index c9519ca2..58e23c2a 100644 --- a/open-vm-tools/modules/linux/vmci/linux/driver.c +++ b/open-vm-tools/modules/linux/vmci/linux/driver.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2011 VMware, Inc. All rights reserved. + * 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 @@ -1801,8 +1801,9 @@ vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device */ if (capabilities & VMCI_CAPS_NOTIFICATIONS) { capabilities = VMCI_CAPS_DATAGRAM; - notification_bitmap = pci_alloc_consistent(pdev, PAGE_SIZE, - ¬ification_base); + 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 { @@ -1948,8 +1949,8 @@ vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device compat_mutex_unlock(&vmci_dev.lock); release: if (notification_bitmap) { - pci_free_consistent(pdev, PAGE_SIZE, notification_bitmap, - notification_base); + dma_free_coherent(&pdev->dev, PAGE_SIZE, notification_bitmap, + notification_base); notification_bitmap = NULL; } release_region(ioaddr, ioaddr_size); diff --git a/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c b/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c index 4e72c33f..8b1788fa 100644 --- a/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c +++ b/open-vm-tools/modules/linux/vmci/linux/vmciKernelIf.c @@ -428,11 +428,13 @@ int VMCIHost_CompareUser(VMCIHostUser *user1, return VMCI_ERROR_INVALID_ARGS; } - if (*user1 == *user2) { - return VMCI_SUCCESS; - } else { - return VMCI_ERROR_GENERIC; - } +#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; } @@ -930,8 +932,8 @@ VMCI_AllocQueue(uint64 size, // IN: size of queue (not including header) for (i = 0; i < numPages; i++) { queue->kernelIf->u.g.vas[i] = - pci_alloc_consistent(vmci_pdev, PAGE_SIZE, - &queue->kernelIf->u.g.pas[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; @@ -973,9 +975,9 @@ VMCI_FreeQueue(void *q, // IN: /* Given size does not include header, so add in a page here. */ for (i = 0; i < CEILING(size, PAGE_SIZE) + 1; i++) { - pci_free_consistent(vmci_pdev, PAGE_SIZE, - queue->kernelIf->u.g.vas[i], - queue->kernelIf->u.g.pas[i]); + dma_free_coherent(&vmci_pdev->dev, PAGE_SIZE, + queue->kernelIf->u.g.vas[i], + queue->kernelIf->u.g.pas[i]); } vfree(queue); } diff --git a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h index 497a9175..ee56876d 100644 --- a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h +++ b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007-2013 VMware, Inc. All rights reserved. + * 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 @@ -25,8 +25,8 @@ #ifndef _VMCI_VERSION_H_ #define _VMCI_VERSION_H_ -#define VMCI_DRIVER_VERSION 9.6.0.0 -#define VMCI_DRIVER_VERSION_COMMAS 9,6,0,0 -#define VMCI_DRIVER_VERSION_STRING "9.6.0.0" +#define VMCI_DRIVER_VERSION 9.7.1.0 +#define VMCI_DRIVER_VERSION_COMMAS 9,7,1,0 +#define VMCI_DRIVER_VERSION_STRING "9.7.1.0" #endif /* _VMCI_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vmci/shared/pgtbl.h b/open-vm-tools/modules/linux/vmci/shared/pgtbl.h index 461ef483..ed1ae8a1 100644 --- a/open-vm-tools/modules/linux/vmci/shared/pgtbl.h +++ b/open-vm-tools/modules/linux/vmci/shared/pgtbl.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2002 VMware, Inc. All rights reserved. + * 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 @@ -37,8 +37,8 @@ * holding a spinlock --hpreg * * Results: - * INVALID_MPN64 on failure - * mpn on success + * INVALID_MPN on failure + * mpn on success * * Side effects: * None @@ -51,11 +51,11 @@ PgtblPte2MPN(pte_t *pte) // IN { MPN64 mpn; if (pte_present(*pte) == 0) { - return INVALID_MPN64; + return INVALID_MPN; } mpn = pte_pfn(*pte); - if (mpn >= INVALID_MPN64) { - return INVALID_MPN64; + if (mpn >= INVALID_MPN) { + return INVALID_MPN; } return mpn; } @@ -176,8 +176,8 @@ PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process * must be held, so this function is not allowed to schedule() --hpreg * * Results: - * INVALID_MPN64 on failure - * mpn on success + * INVALID_MPN on failure + * mpn on success * * Side effects: * None @@ -197,7 +197,7 @@ PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process pte_unmap(pte); return mpn; } - return INVALID_MPN64; + return INVALID_MPN; } @@ -213,8 +213,8 @@ PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process * must be held, so this function is not allowed to schedule() --hpreg * * Results: - * INVALID_MPN64 on failure - * mpn on success + * INVALID_MPN on failure + * mpn on success * * Side effects: * None @@ -234,7 +234,7 @@ PgtblKVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a caller pte_unmap(pte); return mpn; } - return INVALID_MPN64; + return INVALID_MPN; } #endif diff --git a/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h b/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h index 11225e7c..000784f6 100644 --- a/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h +++ b/open-vm-tools/modules/linux/vmci/shared/vmciQueue.h @@ -33,7 +33,7 @@ #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" -#if defined(SOLARIS) || defined(__APPLE__) +#if defined(__APPLE__) # include <sys/uio.h> #endif @@ -150,10 +150,10 @@ int VMCIMemcpyFromQueueLocal(void *dest, size_t destOffset, const VMCIQueue *que uint64 queueOffset, size_t size, BUF_TYPE bufType, Bool canBlock); -#if defined VMKERNEL || defined (SOLARIS) || \ +#if defined VMKERNEL || \ (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ (defined(__linux__) && defined(__KERNEL__)) || \ - (defined(_WIN32) && defined(WINNT_DDK)) + (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); diff --git a/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h b/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h index b31ab823..13a46f5d 100644 --- a/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h +++ b/open-vm-tools/modules/linux/vmci/shared/vmci_handle_array.h @@ -40,13 +40,6 @@ #include "vm_libc.h" #endif // VMKERNEL -#ifdef SOLARIS -#include <sys/ddi.h> -#include <sys/kmem.h> -#include <sys/types.h> -#include <sys/systm.h> -#endif - #define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4 typedef struct VMCIHandleArray { diff --git a/open-vm-tools/modules/linux/vmci/shared/vmci_page_channel.h b/open-vm-tools/modules/linux/vmci/shared/vmci_page_channel.h deleted file mode 100644 index 22e94069..00000000 --- a/open-vm-tools/modules/linux/vmci/shared/vmci_page_channel.h +++ /dev/null @@ -1,733 +0,0 @@ -/********************************************************* - * Copyright (C) 2011-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public 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_page_channel.h - * - * vPageChannel structure and functions. - */ - -#ifndef _VMCI_PAGE_CHANNEL_H_ -#define _VMCI_PAGE_CHANNEL_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" - -/** \cond PRIVATE */ -#define VPAGECHANNEL_MAX_TX_BUF_SIZE (1 << 14) -#define VPAGECHANNEL_MAX_PAGES_PER_TX_BUFFER \ - (VPAGECHANNEL_MAX_TX_BUF_SIZE / PAGE_SIZE + 1) -/** \endcond */ - -/** - * \brief Get a pointer to the elements in a packet. - * - * Returns a pointer to the elements at the end of a page channel packet. - * - * \see VPageChannelElem - * \see VPageChannelPacket - */ - -#define VPAGECHANNEL_PACKET_ELEMS(packet) \ - (VPageChannelElem *)((char *)(packet) + \ - sizeof(VPageChannelPacket) + \ - packet->msgLen) - -/** - * \brief Get a pointer to the message in a packet. - * - * Returns a pointer to the message embedded in a page channel packet. - * - * \see VPageChannelPacket - */ - -#define VPAGECHANNEL_PACKET_MESSAGE(packet) \ - (char *)((char *)(packet) + sizeof(VPageChannelPacket)) - -/** - * \brief Notify client directly, and do not read packets. - * - * This flag indicates that the channel should invoke the client's receive - * callback directly when any packets are available. If not specified, then - * when a notification is received, packets are read from the channel and the - * callback invoked for each one separately. - * - * \note Not applicable to VMKernel. - * - * \see VPageChannel_CreateInVM() - */ - -#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY 0x1 - -/** - * \brief Invoke client's receive callback in delayed context. - * - * This flag indicates that all callbacks run in a delayed context, and the - * caller and callback are allowed to block. If not specified, then callbacks - * run in interrupt context and the channel will not block, and the caller - * is not allowed to block. - * - * \note Not applicable to VMKernel. - * - * \see VPageChannel_CreateInVM() - */ - -#define VPAGECHANNEL_FLAGS_RECV_DELAYED 0x2 - -/** - * \brief Send from an atomic context. - * - * This flag indicates that the client wishes to call Send() from an atomic - * context and that the channel should not block. If the channel is not - * allowed to block, then the channel's pages are permanently mapped and - * pinned. Note that this will limit the total size of the channel to - * VMCI_MAX_PINNED_QP_MEMORY. - * - * \note Not applicable to VMKernel. - * - * \see VPageChannel_CreateInVM() - */ - -#define VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC 0x4 - -/** - * \brief An element describing a data range. - * - * Describes a data range, starting at a base address and for a given - * length, i.e., an element of a scatter-gather list. Indicates physical - * address for the guest and machine address for hypervisor. Can be passed - * via packets or buffers. - * - * \note Structure is packed. - * - * \see VPageChannelPacket - * \see VPageChanelBuffer - */ - -typedef -#include "vmware_pack_begin.h" -struct VPageChannelElem { - union { - /** \brief Physical address for guest. */ - uint64 pa; - - /** \brief Machine address for hypervisor. */ - uint64 ma; - }; - - /** \brief Length of range. */ - uint32 le; -} -#include "vmware_pack_end.h" -VPageChannelElem; - -/** - * \brief Page channel page types. - * - * The various types of page channel packets. - * - * \see VPageChannelPacket - */ -typedef enum { - /** \brief Data packet. */ - VPCPacket_Data = 1, - - /** \brief Completion notification, from hypervisor to guest. */ - VPCPacket_Completion_Notify, - - /** \cond PRIVATE */ - /** \brief Connect to hypervisor, internal. */ - VPCPacket_GuestConnect, - - /** \brief Complete connection handshake, internal. */ - VPCPacket_HyperConnect, - - /** \brief Request buffers, internal. */ - VPCPacket_RequestBuffer, - - /** \brief Set buffers, internal. */ - VPCPacket_SetRecvBuffer, - - /** \brief Hypervisor channel disconnect, internal. */ - VPCPacket_HyperDisconnect, - - /** \brief Guest channel ACK hypervisor disconnect, internal. */ - VPCPacket_GuestDisconnect, - /** \endcond */ -} VPageChannelPacketType; - -/** - * \brief Page channel packet structure. - * - * A packet structure for passing control/data between guest and hypervisor. - * Can optionally contain a message and also a number of elements. - * - * \note Structure is packed. - * - * \see VPageChannelPacketType - */ -typedef -#include "vmware_pack_begin.h" -struct VPageChannelPacket { - /** \brief Type of packet. */ - VPageChannelPacketType type; - - /** \brief Length of optional message. */ - uint32 msgLen; - - /** \brief Number of optional elements in packet. */ - uint32 numElems; - - /** \brief Followed by msgLen of message and numElems VPageChannelElem. */ -} -#include "vmware_pack_end.h" -VPageChannelPacket; - -/** - * \brief Page channel buffer structure. - * - * A buffer of elements (a scatter-gather list). - * - * \note Structure is packed. - * - * \see VPageChannelElem - */ - -typedef -#include "vmware_pack_begin.h" -struct VPageChannelBuffer { - /** \brief Number of elements. */ - uint32 numElems; - - /** \brief First element. */ - VPageChannelElem elems[1]; - - /** \brief Followed by numElems - 1 of VPageChannelElem. */ -} -#include "vmware_pack_end.h" -VPageChannelBuffer; - -/** \cond PRIVATE */ -typedef -#include "vmware_pack_begin.h" -struct VPageChannelGuestConnectMessage { - - /** \brief Guest channel's datagram handle for control channel. */ - VMCIHandle dgHandle; - - /** \brief Guest channel's queuepair handle. */ - VMCIHandle qpHandle; - - /** \brief Size of producer queue in queuepair in bytes. */ - uint64 produceQSize; - - /** \brief Size of consumer queue in queuepair in bytes. */ - uint64 consumeQSize; - - /** \brief Guest channel's doorbell handle. */ - VMCIHandle doorbellHandle; -} -#include "vmware_pack_end.h" -VPageChannelGuestConnectMessage; - -typedef -#include "vmware_pack_begin.h" -struct VPageChannelHyperConnectMessage { - /** \brief Hypervisor's doorbell handle. */ - VMCIHandle doorbellHandle; -} -#include "vmware_pack_end.h" -VPageChannelHyperConnectMessage; -/** \endcond PRIVATE */ - -/** \cond PRIVATE */ -typedef enum VPageChannelState { - VPCState_Free = 0, - VPCState_Unconnected, - VPCState_Connecting, - VPCState_Connected, - VPCState_Disconnecting, - VPCState_Disconnected, -} VPageChannelState; -/** \endcond PRIVATE */ - -/** - * \brief Opaque page channel type. - */ - -struct VPageChannel; -typedef struct VPageChannel VPageChannel; - -/** - * \brief Client receive callback type. - * - * Type of receive callback, invoked when there are data packets in the - * channel. The client provides a callback with this type to - * VPageChannel_CreateInVM(). If VPAGECHANNEL_FLAGS_NOTIFY_ONLY is specified - * in the channel creation flags, then \c packet is \c NULL; otherwise, - * \c packet points to a channel packet. - * - * \see VPageChannel_CreateInVM() - * \see VPageChannelPacket - */ - -typedef void (*VPageChannelRecvCB)(void *clientData, - VPageChannelPacket *packet); - - -#if !defined(VMKERNEL) - -/** - * \brief Client element allocation callback type. - * - * Type of element allocation callback, invoked when the channel needs - * elements. The client provides a callback of this type to - * VPageChannel_CreateInVM(). - * - * \see VPageChannel_CreateInVM() - * \see VPageChannelElem - * \see VPageChannelFreeElemFn - */ - -typedef int (*VPageChannelAllocElemFn)(void *clientData, - VPageChannelElem *elems, - int numElems); - -/** - * \brief Client element release callback type. - * - * Type of element release callback, invoked when the channel releases - * elements. The client provides a callback of this type to - * VPageChannel_CreateInVM(). - * - * \see VPageChannel_CreateInVM() - * \see VPageChannelElem - * \see VPageChannelAllocElemFn - */ - -typedef void (*VPageChannelFreeElemFn)(void *clientData, - VPageChannelElem *elems, - int numElems); - -/* - ************************************************************************ - * VPageChannel_CreateInVM */ /** - * - * \brief Create guest page channel. - * - * Creates a page channel in the guest. The channel should be released - * with VPageChannel_Destroy(). - * - * \note Only applicable in the guest. - * - * \see VPageChannel_CreateInVMK() - * \see VPageChannel_Destroy() - * - * \param[out] channel Pointer to a newly constructed page - * channel if successful. - * \param[in] resourceId Resource ID on which the channel should - * register its control channel. - * \param[in] peerResourceId Resource ID of peer's control channel. - * \param[in] produceQSize Size of producer queue in queuepair in - * bytes. - * \param[in] consumeQSize Size of consumer queue in queuepair in - * bytes. - * \param[in] flags Channel flags. - * \param[in] recvCB Client's receive callback. - * \param[in] clientRecvData Client data for client's receive - * callback. - * \param[in] elemAlloc Element allocation callback for - * allocating page ranges (scatter-gather - * elements). - * \param[in] allocClientData Client data for element allocation - * callback. - * \param[in] elemFree Element release callback for elements. - * \param[in] freeClientData Client data for element release - * callback. - * \param[in] defRecvBufs Default number of elements sent to - * hypervisor channel. - * \param[in] maxRecvBufs Maximum number of elements that can be - * sent to the hypervisor channel. - * - * \retval VMCI_SUCCESS Creation succeeded, \c *channel contains - * a pointer to a valid channel. - * \retval other Failure. - * - ************************************************************************ - */ - -int VPageChannel_CreateInVM(VPageChannel **channel, - VMCIId resourceId, - VMCIId peerResourceId, - uint64 produceQSize, - uint64 consumeQSize, - uint32 flags, - VPageChannelRecvCB recvCB, - void *clientRecvData, - VPageChannelAllocElemFn elemAlloc, - void *allocClientData, - VPageChannelFreeElemFn elemFree, - void *freeClientData, - int defRecvBufs, - int maxRecvBufs); - -#else // VMKERNEL - -/** - * \brief Type of VM memory access off callback. - * - * This callback is invoked when the memory of the VM containing the peer - * endpoint becomes inaccessible, for example due to a crash. When this - * occurs, the client should unmap any guest pages and cleanup any state. - * This callback runs in a blockable context. The client is not allowed to - * call VPageChannel_Destroy() from inside the callback, or it will deadlock, - * since that function will wait for the callback to complete. - * - * \note Only applicable on VMKernel. - * - * \see VPageChannel_CreateInVMK() - */ - -typedef void (*VPageChannelMemAccessOffCB)(void *clientData); - -/* - ************************************************************************ - * VPageChannel_CreateInVMK */ /** - * - * \brief Create a page channel in VMKernel. - * - * Creates a page channel. The channel should be released with - * VPageChannel_Destroy(). - * - * \note Only applicable on VMKernel. - * - * \see VPageChannel_CreateInVM() - * \see VPageChannel_Destroy() - * - * \param[out] channel Pointer to a newly constructed page - * channel if successful. - * \param[in] resourceId Resource ID on which to register - * control channel. - * \param[in] recvCB Client's receive callback. - * \param[in] clientRecvData Client data for receive callback. - * \param[in] memAccessOffCB Client's mem access off callback. - * \param[in] memAccessOffData Client data for mem access off. - * - * \retval VMCI_SUCCESS Creation succeeded, \c *channel - * contains a pointer to a valid channel. - * \retval other Failure. - * - *********************************************************************** - */ - -int VPageChannel_CreateInVMK(VPageChannel **channel, - VMCIId resourceId, - VPageChannelRecvCB recvCB, - void *clientRecvData, - VPageChannelMemAccessOffCB memAccessOffCB, - void *memAccessOffData); - -/* - ************************************************************************ - * VPageChannel_ReserveBuffers */ /** - * - * \brief Reserve guest elements. - * - * Reserve sufficient guest elements to cover the given length. The - * buffers can then be posted to the guest. This allocates both the - * buffer and the elements within the buffer. - * - * \note Only applicable on VMKernel. - * - * \see VPageChannel_ReleaseBuffers() - * - * \param[in] channel Page channel. - * \param[in] dataLen Length to reserve in bytes. - * \param[out] buffer Pointer to a buffer containing elements to cover - * the given length if successful. - * - * \retval VMCI_SUCCESS Reservation succeeded, \c *buffer contains - * a pointer to a valid buffer. - * \retval other Failure. - * - ************************************************************************ - */ - -int VPageChannel_ReserveBuffers(VPageChannel *channel, - size_t dataLen, - VPageChannelBuffer **buffer); - -/* - ************************************************************************ - * VPageChannel_ReleaseBuffers */ /** - * - * \brief Release guest elements. - * - * \note Only applicable on VMKernel. - * - * \see VPageChannel_ReserveBuffers() - * - * Release guest elements previous reserved with - * VPageChannel_ReserveBuffers(). If the buffers were sent to the guest, - * then only the buffer itself should be released, i.e., - * \c returnToFreePool should be \c FALSE; the guest will release the - * buffers on completion. Otherwise, if for some reason they are not - * sent after reserving them, then \c returnToFreePool should be set to - * \c TRUE. - * - * \param[in] channel Page channel. - * \param[in] buffer Buffer to be released. - * \param[in] returnToFreePool If \c TRUE, then release the elements - * of the buffer along with the buffer - * itself. If \c FALSE, then release only - * the buffer pointer itself. - * - ************************************************************************ - */ - -void VPageChannel_ReleaseBuffers(VPageChannel *channel, - VPageChannelBuffer *buffer, - Bool returnToFreePool); - -/* - ************************************************************************ - * VPageChannel_CompletionNotify */ /** - * - * \brief Notify channel of completion. - * - * This function is called when the client is finished using the elements - * (scatter-gather list) of a packet. This will generated a notification - * to the guest to pass ownership of the buffers back to the guest. This - * can also be used to read back the data from the hypervisor and send - * it to the guest. - * - * \note Only applicable on VMKernel. - * - * \see VPageChannel_ReserveBuffers - * - * \param[in] channel Channel on which I/O is complete. - * \param[in] message Optional message to send to guest. - * \param[in] len Length of optional message. - * \param[in] buffer Buffer used for I/O. - * - ************************************************************************ - */ - -int VPageChannel_CompletionNotify(VPageChannel *channel, - char *message, - int len, - VPageChannelBuffer *buffer); - -/* - ************************************************************************ - * VPageChannel_MapToMa */ /** - * - * \brief Map guest PA in an element to a list of MAs. - * - * Map a guest physical address to a list of hypervisor machine - * addresses. - * - * \note Only applicable on VMKernel. - * - * \param[in] channel Channel on which to map. - * \param[in] paElem Guest's physical address. - * \param[out] maElems Hypervisor machine addresses. - * \param[in] numElems Max number of hypervisor elements. - * - * \retval elems Number of mapped elements. - * - ************************************************************************ - */ - -int VPageChannel_MapToMa(VPageChannel *channel, - VPageChannelElem paElem, - VPageChannelElem *maElems, - uint32 numElems); - -/* - ************************************************************************ - * VPageChannel_UnmapMa */ /** - * - * \brief Unmap MA for a buffer. - * - * Unmap hypervisor machine addresses referring to a guest physical - * addresses. - * - * \note Only applicable on VMKernel. - * - * \see VPageChannel_MapToMa - * - * \param[in] channel Channel for which to unmap. - * \param[in] buffer Buffer containing elements to unmap. - * \param[in] numElems Number of elements to unmap. - * - * \retval 0 Unmap successful. - * \retval -1 World not found for channel. - * - ************************************************************************ - */ - -int VPageChannel_UnmapMa(VPageChannel *channel, - VPageChannelBuffer *buffer, - int numElems); - -#endif // VMKERNEL - -/* - ************************************************************************ - * VPageChannel_Destroy */ /** - * - * \brief Destroy the given channel. - * - * Destroy the given channel. This will disconnect from the peer - * channel (if connected) and release all resources. - * - * \see VPageChannel_CreateInVMK - * \see VPageChannel_CreateInVM - * - * \param[in] channel The channel to be destroyed. - * - ************************************************************************ - */ - -void VPageChannel_Destroy(VPageChannel *channel); - -/* - ************************************************************************ - * VPageChannel_Send */ /** - * - * \brief Send a packet to the channel's peer. - * - * Send a packet to the channel's peer. A message and a number of - * elements may optionally be sent. If the send is successful, the - * elements are owned by the peer and only the buffer itself should - * be released, but not the elements within. If the send fails, the - * client should release the buffer and the elements. - * - * \see VPageChannel_SendPacket - * - * \param[in] channel Channel on which to send. - * \param[in] type Type of packet to send. - * \param[in] message Optional message to send. - * \param[in] len Length of optional message. - * \param[in] buffer Buffer (of elements) to send. - * - * \retval VMCI_SUCCESS Packet successfully sent, buffer elements - * owned by peer. - * \retval other Failure to send, client should release - * elements. - * - ************************************************************************ - */ - -int VPageChannel_Send(VPageChannel *channel, - VPageChannelPacketType type, - char *message, - int len, - VPageChannelBuffer *buffer); - -/* - ************************************************************************ - * VPageChannel_SendPacket */ /** - * - * \brief Send the given packet to the channel's peer. - * - * Send a client-constructed packet to the channel's peer. If the - * send is successful, any elements in the packet are owned by the - * peer. Otherwise, the client retains ownership. - * - * \see VPageChannel_Send - * - * \param[in] channel Channel on which to send. - * \param[in] packet Packet to be sent. - * - * \retval VMCI_SUCCESS Packet successfully sent, buffer elements - * owned by peer. - * \retval other Failure to send, client should release - * elements. - * - ************************************************************************ - */ - -int VPageChannel_SendPacket(VPageChannel *channel, - VPageChannelPacket *packet); - -/* - ************************************************************************ - * VPageChannel_PollRecvQ */ /** - * - * \brief Poll the channel's receive queue for packets. - * - * Poll the channel's receive queue for packets from the peer. If any - * packets are available, the channel's receive callback will be invoked. - * - * \param[in] channel Channel to poll. - * - ************************************************************************ - */ - -void VPageChannel_PollRecvQ(VPageChannel *channel); - -/* - ************************************************************************ - * VPageChannel_BufferLen */ /** - * - * \brief Determine the length of a packet. - * - * Determine the length of the given packet in bytes. - * - * \param[in] packet Packet for which length is to be determined. - * - * \retval bytes Size of the packet in bytes. - * - ************************************************************************ - */ - -static INLINE size_t -VPageChannelPacket_BufferLen(VPageChannelPacket *packet) // IN -{ - size_t len, i; - VPageChannelElem *elems; - - ASSERT(packet); - - len = 0; - elems = VPAGECHANNEL_PACKET_ELEMS(packet); - for (i = 0; i < packet->numElems; i++) { - len += elems[i].le; - } - - return len; -} - -/** \cond PRIVATE */ -#if defined(linux) && !defined(VMKERNEL) -#include "compat_pci.h" -#define vmci_pci_map_page(_pg, _off, _sz, _dir) \ - pci_map_page(NULL, (_pg), (_off), (_sz), (_dir)) -#define vmci_pci_unmap_page(_dma, _sz, _dir) \ - pci_unmap_page(NULL, (_dma), (_sz), (_dir)) -#endif // linux && !VMKERNEL -/** \endcond PRIVATE */ - -#endif // _VMCI_PACKET_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/Makefile b/open-vm-tools/modules/linux/vmhgfs/Makefile index e7e3eaf4..648dab58 100644 --- a/open-vm-tools/modules/linux/vmhgfs/Makefile +++ b/open-vm-tools/modules/linux/vmhgfs/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel b/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel index a8a2caab..c68a8087 100644 --- a/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel +++ b/open-vm-tools/modules/linux/vmhgfs/Makefile.kernel @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 @@ -28,11 +28,13 @@ 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) MODPOST_VMCI_SYMVERS := $(wildcard $(MODULEBUILDDIR)/VMwareVMCIModule.symvers) diff --git a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c index 5bcac3f5..b891019e 100644 --- a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c +++ b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/dentry.c b/open-vm-tools/modules/linux/vmhgfs/dentry.c index 873ef103..2da16dcc 100644 --- a/open-vm-tools/modules/linux/vmhgfs/dentry.c +++ b/open-vm-tools/modules/linux/vmhgfs/dentry.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/dir.c b/open-vm-tools/modules/linux/vmhgfs/dir.c index e4e82b48..809611a1 100644 --- a/open-vm-tools/modules/linux/vmhgfs/dir.c +++ b/open-vm-tools/modules/linux/vmhgfs/dir.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -1157,7 +1157,8 @@ 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 *entryPos) // IN/OUT: entry position + 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; @@ -1179,7 +1180,7 @@ HgfsDoReaddir(struct file *file, // IN: __func__, file->f_dentry->d_name.name, file->f_dentry->d_inode->i_ino, - *entryPos)); + *currentPos)); /* * Refresh entries if required. See rm -rf 6.10+ breaking issue. @@ -1189,7 +1190,6 @@ HgfsDoReaddir(struct file *file, // IN: return result; } - /* * Some day when we're out of things to do we can move this to a slab * allocator. @@ -1207,7 +1207,7 @@ HgfsDoReaddir(struct file *file, // IN: uint32 entryType = DT_UNKNOWN; result = HgfsReaddirNextEntry(file, - *entryPos, + *currentPos, dotAndDotDotIgnore, entryNameBufLen, entryName, @@ -1228,20 +1228,20 @@ HgfsDoReaddir(struct file *file, // IN: } if (entryIgnore) { - *entryPos += 1; + *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, %Lu)\n", - __func__, entryName, entryNameLength, *entryPos)); + 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 */ - *entryPos, /* entry position */ + *fillPos, /* fill entry position */ entryIno, /* inode number (0 makes it not show) */ entryType)) { /* type of dirent */ /* @@ -1254,7 +1254,8 @@ HgfsDoReaddir(struct file *file, // IN: result = 0; break; } - *entryPos += 1; + *currentPos += 1; + *fillPos += 1; } LOG(6, (KERN_DEBUG "VMware hgfs: %s: return\n",__func__)); @@ -1284,6 +1285,12 @@ 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", @@ -1292,7 +1299,7 @@ HgfsReaddir(struct file *file, // IN: } /* It is sufficient to pass the context as it contains the filler function. */ - return HgfsDoReaddir(file, TRUE, NULL, ctx, &ctx->pos); + return HgfsDoReaddir(file, TRUE, NULL, ctx, &ctx->pos, &fInfo->direntPos); } @@ -1367,7 +1374,13 @@ HgfsReaddir(struct file *file, // IN: Directory to read from void *dirent, // OUT: Buffer to copy dentries into filldir_t filldir) // IN: Filler function { - return HgfsDoReaddir(file, FALSE, filldir, dirent, &file->f_pos); + 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); } diff --git a/open-vm-tools/modules/linux/vmhgfs/file.c b/open-vm-tools/modules/linux/vmhgfs/file.c index 3ddbfefd..bbde3f4b 100644 --- a/open-vm-tools/modules/linux/vmhgfs/file.c +++ b/open-vm-tools/modules/linux/vmhgfs/file.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -47,6 +47,31 @@ #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, @@ -61,14 +86,21 @@ static int HgfsUnpackOpenReply(HgfsReq *req, static int HgfsOpen(struct inode *inode, struct file *file); #if defined VMW_USE_AIO -static ssize_t HgfsAioRead(struct kiocb *iocb, - const struct iovec *iov, - unsigned long numSegs, - loff_t offset); -static ssize_t HgfsAioWrite(struct kiocb *iocb, +#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, @@ -83,6 +115,15 @@ static ssize_t HgfsWrite(struct file *file, 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 @@ -125,9 +166,19 @@ struct file_operations HgfsFileFileOperations = { .owner = THIS_MODULE, .open = HgfsOpen, .llseek = HgfsSeek, + .flush = HgfsFlush, #if defined VMW_USE_AIO - .aio_read = HgfsAioRead, - .aio_write = HgfsAioWrite, +#if 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, @@ -642,7 +693,51 @@ out: /* *---------------------------------------------------------------------- * - * HgfsAioRead -- + * 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 @@ -658,35 +753,90 @@ out: *---------------------------------------------------------------------- */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static ssize_t -HgfsAioRead(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 +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) { - int result; + 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, %lu@%lu)\n", + LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", __func__, readDentry->d_parent->d_name.name, - readDentry->d_name.name, - (unsigned long) iov_length(iov, numSegs), (unsigned long) offset)); + readDentry->d_name.name)); result = HgfsRevalidate(readDentry); if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsAioRead: invalid dentry\n")); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); goto out; } - result = generic_file_aio_read(iocb, iov, numSegs, offset); - 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; } @@ -694,7 +844,7 @@ HgfsAioRead(struct kiocb *iocb, // IN: I/O control block /* *---------------------------------------------------------------------- * - * HgfsAioWrite -- + * HgfsFileWrite -- * * Called when the kernel initiates an asynchronous write to a file in * our filesystem. Our function is just a thin wrapper around @@ -713,34 +863,60 @@ HgfsAioRead(struct kiocb *iocb, // IN: I/O control block *---------------------------------------------------------------------- */ +#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 -HgfsAioWrite(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 read +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) { - int result; + ssize_t result; struct dentry *writeDentry; + 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; - LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s, %lu@%Ld)\n", + LOG(4, (KERN_DEBUG "VMware hgfs: %s(%s/%s)\n", __func__, writeDentry->d_parent->d_name.name, - writeDentry->d_name.name, - (unsigned long) iov_length(iov, numSegs), (long long) offset)); + writeDentry->d_name.name)); result = HgfsRevalidate(writeDentry); if (result) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsAioWrite: invalid dentry\n")); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: invalid dentry\n", __func__)); goto out; } - result = generic_file_aio_write(iocb, iov, numSegs, offset); + 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: return result; } @@ -896,6 +1072,101 @@ HgfsSeek(struct file *file, // IN: File to seek } +#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; +} + + /* *---------------------------------------------------------------------- * @@ -903,21 +1174,13 @@ HgfsSeek(struct file *file, // IN: File to seek * * Called when user process calls fsync() on hgfs file. * - * The hgfs protocol doesn't support fsync yet, so for now, we punt - * and just return success. This is a little less sketchy than it - * might sound, because hgfs skips the buffer cache in the guest - * anyway (we always write to the host immediately). - * - * In the future we might want to try harder though, since - * presumably the intent of an app calling fsync() is to get the + * 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. * - * Note that do_fsync will call filemap_fdatawrite() before us and - * filemap_fdatawait() after us, so there's no need to do anything - * here w.r.t. writing out dirty pages. - * * Results: * Returns zero on success. (Currently always succeeds). * @@ -937,18 +1200,37 @@ HgfsFsync(struct file *file, // IN: File we operate on #endif int datasync) // IN: fdatasync or fsync { - LOG(6, (KERN_DEBUG "VMware hgfs: %s(%s/%s, %lld, %lld, %d)\n", + 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 - start, end, + ret = filemap_write_and_wait_range(inode->i_mapping, startRange, endRange); #else - (loff_t)0, (loff_t)0, + ret = HgfsDoFsync(inode); #endif - datasync)); - return 0; + LOG(4, (KERN_DEBUG "VMware hgfs: %s: written pages %lld, %lld returns %d)\n", + __func__, startRange, endRange, ret)); + return ret; } diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.c b/open-vm-tools/modules/linux/vmhgfs/filesystem.c index f101ca7a..33c4c56f 100644 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.c +++ b/open-vm-tools/modules/linux/vmhgfs/filesystem.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -83,7 +83,6 @@ HgfsOp hgfsVersionCreateSymlink; static inline unsigned long HgfsComputeBlockBits(unsigned long blockSize); static compat_kmem_cache_ctor HgfsInodeCacheCtor; static HgfsSuperInfo *HgfsInitSuperInfo(HgfsMountInfo *mountInfo); -static int HgfsGetRootDentry(struct super_block *sb, struct dentry **rootDentry); static int HgfsReadSuper(struct super_block *sb, void *rawData, int flags); @@ -123,8 +122,6 @@ static struct file_system_type hgfsType = { .kill_sb = kill_anon_super, }; -extern int USE_VMCI; - /* * Private functions implementations. */ @@ -228,16 +225,23 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user * or gid given to us by the server. */ si->uidSet = mountInfo->uidSet; + si->uid = current_uid(); if (si->uidSet) { - si->uid = mountInfo->uid; - } else { - si->uid = current_uid(); + kuid_t mntUid = make_kuid(current_user_ns(), mountInfo->uid); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + if (uid_valid(mntUid)) +#endif + si->uid = mntUid; } + si->gidSet = mountInfo->gidSet; + si->gid = current_gid(); if (si->gidSet) { - si->gid = mountInfo->gid; - } else { - si->gid = current_gid(); + kgid_t mntGid = make_kgid(current_user_ns(), mountInfo->gid); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + if (gid_valid(mntGid)) +#endif + si->gid = mntGid; } si->fmask = mountInfo->fmask; si->dmask = mountInfo->dmask; @@ -327,103 +331,6 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user /* - *---------------------------------------------------------------------------- - * - * HgfsGetRootDentry -- - * - * 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. - * - *---------------------------------------------------------------------------- - */ - -static int -HgfsGetRootDentry(struct super_block *sb, // IN: Super block object - struct dentry **rootDentry) // OUT: Root dentry -{ - int result = -ENOMEM; - struct inode *rootInode; - struct dentry *tempRootDentry = NULL; - struct HgfsAttrInfo rootDentryAttr; - HgfsInodeInfo *iinfo; - - ASSERT(sb); - ASSERT(rootDentry); - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: entered\n", __func__)); - - rootInode = HgfsGetInode(sb, HGFS_ROOT_INO); - if (rootInode == NULL) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: Could not get the root inode\n", - __func__)); - goto exit; - } - - /* - * On an allocation failure in read_super, the inode will have been - * marked "bad". If it was, we certainly don't want to start playing with - * the HgfsInodeInfo. So quietly put the inode back and fail. - */ - if (is_bad_inode(rootInode)) { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: encountered bad inode\n", - __func__)); - goto exit; - } - - tempRootDentry = d_make_root(rootInode); - /* - * d_make_root() does iput() on failure; if d_make_root() completes - * successfully then subsequent dput() will do iput() for us, so we - * should just ignore root inode from now on. - */ - rootInode = NULL; - - if (tempRootDentry == NULL) { - LOG(4, (KERN_WARNING "VMware hgfs: %s: Could not get " - "root dentry\n", __func__)); - goto exit; - } - - result = HgfsPrivateGetattr(tempRootDentry, &rootDentryAttr, NULL); - if (result) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsReadSuper: Could not" - "instantiate the root dentry\n")); - goto exit; - } - - iinfo = INODE_GET_II_P(tempRootDentry->d_inode); - iinfo->isFakeInodeNumber = FALSE; - iinfo->isReferencedInode = TRUE; - - if (rootDentryAttr.mask & HGFS_ATTR_VALID_FILEID) { - iinfo->hostFileId = rootDentryAttr.hostFileId; - } - - HgfsChangeFileAttributes(tempRootDentry->d_inode, &rootDentryAttr); - HgfsDentryAgeReset(tempRootDentry); - tempRootDentry->d_op = &HgfsDentryOperations; - - *rootDentry = tempRootDentry; - result = 0; - - LOG(6, (KERN_DEBUG "VMware hgfs: %s: finished\n", __func__)); -exit: - if (result) { - iput(rootInode); - dput(tempRootDentry); - *rootDentry = NULL; - } - return result; -} - - -/* *----------------------------------------------------------------------------- * * HgfsReadSuper -- @@ -503,7 +410,10 @@ HgfsReadSuper(struct super_block *sb, // OUT: Superblock object sb->s_blocksize_bits = HgfsComputeBlockBits(HGFS_BLOCKSIZE); sb->s_blocksize = 1 << sb->s_blocksize_bits; - result = HgfsGetRootDentry(sb, &rootDentry); + /* + * 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")); @@ -646,12 +556,6 @@ HgfsResetOps(void) hgfsVersionRename = HGFS_OP_RENAME_V3; hgfsVersionQueryVolumeInfo = HGFS_OP_QUERY_VOLUME_INFO_V3; hgfsVersionCreateSymlink = HGFS_OP_CREATE_SYMLINK_V3; - - if (USE_VMCI) { - hgfsVersionRead = HGFS_OP_READ_FAST_V4; - hgfsVersionWrite = HGFS_OP_WRITE_FAST_V4; - } - } diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.h b/open-vm-tools/modules/linux/vmhgfs/filesystem.h index b04c415b..b0bcb5b4 100644 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.h +++ b/open-vm-tools/modules/linux/vmhgfs/filesystem.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.c b/open-vm-tools/modules/linux/vmhgfs/fsutil.c index 2b1bcff5..50233242 100644 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.c +++ b/open-vm-tools/modules/linux/vmhgfs/fsutil.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -53,10 +53,13 @@ static int HgfsUnpackGetattrReply(HgfsReq *req, HgfsAttrInfo *attr, char **fileName); static int HgfsPackGetattrRequest(HgfsReq *req, - struct dentry *dentry, + HgfsOp opUsed, Bool allowHandleReuse, - HgfsOp opUsed, + struct dentry *dentry, HgfsAttrInfo *attr); +static int HgfsBuildRootPath(char *buffer, + size_t bufferLen, + HgfsSuperInfo *si); /* * Private function implementations. @@ -236,13 +239,17 @@ HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet /* *---------------------------------------------------------------------- * - * HgfsPackGetattrRequest -- + * HgfsPackCommonattr -- * - * Setup the getattr request, depending on the op version. When possible, - * we will issue the getattr using an existing open HGFS handle. + * 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: - * Returns zero on success, or negative error on failure. + * Zero on success, non-zero otherwise. * * Side effects: * None @@ -251,22 +258,18 @@ HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet */ static int -HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer - struct dentry *dentry, // IN: Dentry containing name - Bool allowHandleReuse, // IN: Can we use a handle? - HgfsOp opUsed, // IN: Op to be used - HgfsAttrInfo *attr) // OUT: Attrs to update +HgfsPackCommonattr(HgfsReq *req, // IN/OUT: request buffer + HgfsOp opUsed, // IN: Op to be used + Bool allowHandleReuse, // IN: Can we use a handle? + struct inode *fileInode, // IN: file inode + 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 { - size_t reqBufferSize; - size_t reqSize; - int result = 0; HgfsHandle handle; - char *fileName = NULL; - uint32 *fileNameLength = NULL; - - ASSERT(attr); - ASSERT(dentry); - ASSERT(req); + int result = 0; attr->requestType = opUsed; @@ -289,24 +292,25 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer * by name. */ requestV3->hints = 0; - if (allowHandleReuse && HgfsGetHandle(dentry->d_inode, + if (allowHandleReuse && HgfsGetHandle(fileInode, 0, &handle) == 0) { 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; + *fileName = NULL; + *fileNameLength = NULL; } else { - fileName = requestV3->fileName.name; - fileNameLength = &requestV3->fileName.length; + *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); + *reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3); + *reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, *reqSize); break; } @@ -323,19 +327,20 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer * correct regardless. If we don't find a handle, fall back on getattr * by name. */ - if (allowHandleReuse && HgfsGetHandle(dentry->d_inode, + if (allowHandleReuse && HgfsGetHandle(fileInode, 0, &handle) == 0) { requestV2->hints = HGFS_ATTR_HINT_USE_FILE_DESC; requestV2->file = handle; - fileName = NULL; + *fileName = NULL; + *fileNameLength = NULL; } else { requestV2->hints = 0; - fileName = requestV2->fileName.name; - fileNameLength = &requestV2->fileName.length; + *fileName = requestV2->fileName.name; + *fileNameLength = &requestV2->fileName.length; } - reqSize = sizeof *requestV2; - reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2); + *reqSize = sizeof *requestV2; + *reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2); break; } @@ -346,17 +351,67 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer 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); + *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: HgfsPackGetattrRequest: unexpected " - "OP type encountered\n")); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: unexpected OP type encountered\n", __func__)); result = -EPROTO; + break; + } + + return result; +} + + +/* + *---------------------------------------------------------------------- + * + * HgfsPackGetattrRequest -- + * + * 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 +HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer + HgfsOp opUsed, // IN: Op to be used + Bool allowHandleReuse, // IN: Can we use a handle? + struct dentry *dentry, // IN: Dentry containing name + HgfsAttrInfo *attr) // OUT: Attrs to update +{ + size_t reqBufferSize; + size_t reqSize; + char *fileName = NULL; + uint32 *fileNameLength = NULL; + int result = 0; + + ASSERT(attr); + ASSERT(dentry); + ASSERT(req); + + result = HgfsPackCommonattr(req, + opUsed, + allowHandleReuse, + dentry->d_inode, + &reqSize, + &reqBufferSize, + &fileName, + &fileNameLength, + attr); + if (0 > result) { goto out; } @@ -366,29 +421,112 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer /* Build full name to send to server. */ if (HgfsBuildPath(fileName, reqBufferSize, dentry) < 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackGetattrRequest: build path " - "failed\n")); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: build path failed\n", __func__)); result = -EINVAL; goto out; } - LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPackGetattrRequest: getting attrs " - "for \"%s\"\n", fileName)); + 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: HgfsPackGetattrRequest: CP " - "conversion failed\n")); + 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; +} + + +/* + *---------------------------------------------------------------------- + * + * HgfsPackGetattrRootRequest -- + * + * Setup the getattr request for the root of the HGFS file system. + * + * 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 +HgfsPackGetattrRootRequest(HgfsReq *req, // IN/OUT: Request buffer + HgfsOp opUsed, // IN: Op to be used + struct super_block *sb, // IN: Super block entry + HgfsAttrInfo *attr) // OUT: Attrs to update +{ + size_t reqBufferSize; + size_t reqSize; + char *fileName = NULL; + uint32 *fileNameLength = NULL; + int result = 0; + + ASSERT(attr); + ASSERT(sb); + ASSERT(req); + + result = HgfsPackCommonattr(req, + opUsed, + FALSE, + NULL, + &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) { + HgfsSuperInfo *si = HGFS_SB_TO_COMMON(sb); + + /* Build full name to send to server. */ + if (HgfsBuildRootPath(fileName, + reqBufferSize, + si) < 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; } @@ -548,7 +686,7 @@ HgfsUnpackCommonAttr(HgfsReq *req, // IN: Reply packet /* *---------------------------------------------------------------------- * - * HgfsChangeFileAttributes -- + * HgfsCalcBlockSize -- * * Calculate the number of 512 byte blocks used. * @@ -565,6 +703,7 @@ HgfsUnpackCommonAttr(HgfsReq *req, // IN: Reply packet * *---------------------------------------------------------------------- */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) static inline blkcnt_t HgfsCalcBlockSize(uint64 tsize) @@ -585,6 +724,69 @@ HgfsCalcBlockSize(uint64 tsize) /* *---------------------------------------------------------------------- * + * 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->uidSet || (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->gidSet || (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))); + } +} + + +/* + *---------------------------------------------------------------------- + * * HgfsChangeFileAttributes -- * * Update an inode's attributes to match those of the HgfsAttr. May @@ -674,20 +876,7 @@ HgfsChangeFileAttributes(struct inode *inode, // IN/OUT: Inode */ set_nlink(inode, 1); - /* - * 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->uidSet || (attr->mask & HGFS_ATTR_VALID_USERID) == 0) { - inode->i_uid = si->uid; - } else { - inode->i_uid = attr->userId; - } - if (si->gidSet || (attr->mask & HGFS_ATTR_VALID_GROUPID) == 0) { - inode->i_gid = si->gid; - } else { - inode->i_gid = attr->groupId; - } + HgfsSetInodeUidGid(inode, si, attr); inode->i_rdev = 0; /* Device nodes are not supported */ #if !defined VMW_INODE_2618 @@ -768,17 +957,14 @@ HgfsChangeFileAttributes(struct inode *inode, // IN/OUT: Inode /* *---------------------------------------------------------------------- * - * HgfsPrivateGetattr -- + * HgfsCanRetryGetattrRequest -- * - * 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. + * Checks the getattr request version and downgrades the global getattr + * version if we can. * * Results: - * Returns zero on success, or a negative error on failure. + * Returns TRUE on success and downgrades the global getattr protocol version, + * or FALSE if no retry is possible. * * Side effects: * None @@ -786,42 +972,60 @@ HgfsChangeFileAttributes(struct inode *inode, // IN/OUT: Inode *---------------------------------------------------------------------- */ -int -HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name - HgfsAttrInfo *attr, // OUT: Attr to copy into - char **fileName) // OUT: pointer to allocated file name +static Bool +HgfsCanRetryGetattrRequest(HgfsOp getattrOp) // IN: getattrOp version used { - HgfsReq *req; - HgfsStatus replyStatus; - HgfsOp opUsed; - int result = 0; - Bool allowHandleReuse = TRUE; + 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; +} - ASSERT(dentry); - ASSERT(dentry->d_sb); - ASSERT(attr); - req = HgfsGetNewRequest(); - if (!req) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: out of memory " - "while getting new request\n")); - result = -ENOMEM; - goto out; - } +/* + *---------------------------------------------------------------------- + * + * HgfsSendGetattrRequest -- + * + * Send the getattr request and handle the reply. + * + * Results: + * Returns zero on success, or a negative error on failure. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ - retry: +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; - opUsed = hgfsVersionGetattr; - result = HgfsPackGetattrRequest(req, dentry, allowHandleReuse, opUsed, attr); - if (result != 0) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: no attrs\n")); - goto out; - } + *doRetry = FALSE; result = HgfsSendRequest(req); if (result == 0) { - replyStatus = HgfsReplyStatus(req); + HgfsStatus replyStatus = HgfsReplyStatus(req); + result = HgfsStatusConvertToLinux(replyStatus); + LOG(6, (KERN_DEBUG "VMware hgfs: %s: reply status %d -> %d\n", __func__, replyStatus, result)); @@ -843,7 +1047,7 @@ HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name * 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:Server returned EIO on unknown file\n")); + 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; @@ -860,9 +1064,9 @@ HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name * "goto retry" would cause an infinite loop. Instead, let's retry * with a getattr by name. */ - if (allowHandleReuse) { - allowHandleReuse = FALSE; - goto retry; + if (*allowHandleReuse) { + *allowHandleReuse = FALSE; + *doRetry = TRUE; } /* @@ -874,30 +1078,143 @@ HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name case -EPROTO: /* Retry with older version(s). Set globally. */ - if (attr->requestType == HGFS_OP_GETATTR_V3) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: Version 3 " - "not supported. Falling back to version 2.\n")); - hgfsVersionGetattr = HGFS_OP_GETATTR_V2; - goto retry; - } else if (attr->requestType == HGFS_OP_GETATTR_V2) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: Version 2 " - "not supported. Falling back to version 1.\n")); - hgfsVersionGetattr = HGFS_OP_GETATTR; - goto retry; + if (HgfsCanRetryGetattrRequest(attr->requestType)) { + *doRetry = TRUE; } + break; - /* Fallthrough. */ default: break; } } else if (result == -EIO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: timed out\n")); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: timed out\n", __func__)); } else if (result == -EPROTO) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: server " - "returned error: %d\n", result)); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: protocol error: %d\n", + __func__, result)); } else { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPrivateGetattr: unknown error: " - "%d\n", result)); + LOG(4, (KERN_DEBUG "VMware hgfs: %s: unknown error: %d\n", + __func__, result)); + } + + 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 +{ + HgfsReq *req; + HgfsOp opUsed; + int result = 0; + Bool doRetry; + Bool allowHandleReuse = FALSE; + + ASSERT(sb); + ASSERT(attr); + + 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 = HgfsPackGetattrRootRequest(req, opUsed, sb, attr); + if (result != 0) { + LOG(4, (KERN_DEBUG "VMware hgfs: %s: no attrs\n", __func__)); + goto out; + } + + result = HgfsSendGetattrRequest(req, &doRetry, &allowHandleReuse, attr, NULL); + if (0 != result && doRetry) { + goto retry; + } + +out: + HgfsFreeRequest(req); + return result; +} + + +/* + *---------------------------------------------------------------------- + * + * 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 +{ + HgfsReq *req; + HgfsOp opUsed; + int result = 0; + Bool doRetry; + Bool allowHandleReuse = TRUE; + + ASSERT(dentry); + ASSERT(dentry->d_sb); + ASSERT(attr); + + 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 = HgfsPackGetattrRequest(req, opUsed, allowHandleReuse, 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: @@ -1053,6 +1370,108 @@ HgfsIget(struct super_block *sb, // IN: Superblock of this fs /* *----------------------------------------------------------------------------- * + * 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 = -ENOMEM; + struct inode *rootInode; + struct dentry *tempRootDentry = NULL; + struct HgfsAttrInfo rootDentryAttr; + HgfsInodeInfo *iinfo; + + ASSERT(sb); + ASSERT(rootDentry); + + LOG(6, (KERN_DEBUG "VMware hgfs: %s: entered\n", __func__)); + + rootInode = HgfsGetInode(sb, HGFS_ROOT_INO); + if (rootInode == NULL) { + LOG(6, (KERN_DEBUG "VMware hgfs: %s: Could not get the root inode\n", + __func__)); + goto exit; + } + + /* + * On an allocation failure in read_super, the inode will have been + * marked "bad". If it was, we certainly don't want to start playing with + * the HgfsInodeInfo. So quietly put the inode back and fail. + */ + if (is_bad_inode(rootInode)) { + LOG(6, (KERN_DEBUG "VMware hgfs: %s: encountered bad inode\n", + __func__)); + goto exit; + } + + LOG(8, (KERN_DEBUG "VMware hgfs: %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; + } + + iinfo = INODE_GET_II_P(rootInode); + iinfo->isFakeInodeNumber = FALSE; + iinfo->isReferencedInode = TRUE; + + if (rootDentryAttr.mask & HGFS_ATTR_VALID_FILEID) { + iinfo->hostFileId = rootDentryAttr.hostFileId; + } + + HgfsChangeFileAttributes(rootInode, &rootDentryAttr); + + /* + * Now the initialization of the inode is complete we can create + * the root dentry which has flags initialized from the inode itself. + */ + tempRootDentry = d_make_root(rootInode); + /* + * d_make_root() does iput() on failure; if d_make_root() completes + * successfully then subsequent dput() will do iput() for us, so we + * should just ignore root inode from now on. + */ + rootInode = NULL; + + if (tempRootDentry == NULL) { + LOG(4, (KERN_WARNING "VMware hgfs: %s: Could not get " + "root dentry\n", __func__)); + goto exit; + } + + HgfsDentryAgeReset(tempRootDentry); + tempRootDentry->d_op = &HgfsDentryOperations; + + *rootDentry = tempRootDentry; + result = 0; + + LOG(6, (KERN_DEBUG "VMware hgfs: %s: finished\n", __func__)); +exit: + if (result) { + iput(rootInode); + dput(tempRootDentry); + *rootDentry = NULL; + } + return result; +} + + +/* + *----------------------------------------------------------------------------- + * * HgfsInstantiate -- * * Tie a dentry to a looked up or created inode. Callers may choose to @@ -1117,6 +1536,45 @@ HgfsInstantiate(struct dentry *dentry, // IN: Dentry to use /* *----------------------------------------------------------------------------- * + * 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 + * + *----------------------------------------------------------------------------- + */ + +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 @@ -1138,7 +1596,7 @@ 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 = 0; + int retval; size_t shortestNameLength; HgfsSuperInfo *si; @@ -1148,26 +1606,23 @@ HgfsBuildPath(char *buffer, // IN/OUT: Buffer to write into si = HGFS_SB_TO_COMMON(dentry->d_sb); - /* - * 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; + retval = HgfsBuildRootPath(buffer, bufferLen, si); + if (0 > retval) { + return retval; } - memcpy(buffer, si->shareName, shortestNameLength); /* 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 shortestNameLength; + 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 @@ -1499,6 +1954,7 @@ HgfsCreateFileInfo(struct file *file, // IN: File pointer to attach to /* 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 @@ -1747,11 +2203,13 @@ HgfsStatusConvertToLinux(HgfsStatus hgfsStatus) // IN: Status code to convert void HgfsSetUidGid(struct inode *parent, // IN: parent inode struct dentry *dentry, // IN: dentry of file to update - uid_t uid, // IN: uid to set - gid_t gid) // IN: gid to set + 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; @@ -1775,6 +2233,8 @@ HgfsSetUidGid(struct inode *parent, // IN: parent inode HgfsDentryAgeForce(dentry); HgfsSetattr(dentry, &setUidGid); HgfsRevalidate(dentry); + + LOG(6, (KERN_DEBUG "VMware hgfs: %s: returns\n", __func__)); } diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.h b/open-vm-tools/modules/linux/vmhgfs/fsutil.h index f332fb6d..ff15b15f 100644 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.h +++ b/open-vm-tools/modules/linux/vmhgfs/fsutil.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -32,6 +32,7 @@ #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" @@ -73,6 +74,8 @@ int HgfsPrivateGetattr(struct dentry *dentry, 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); @@ -92,8 +95,8 @@ int HgfsGetHandle(struct inode *inode, int HgfsStatusConvertToLinux(HgfsStatus hgfsStatus); void HgfsSetUidGid(struct inode *parent, struct dentry *dentry, - uid_t uid, - gid_t gid); + kuid_t uid, + kgid_t gid); struct inode *HgfsGetInode(struct super_block *sb, ino_t ino); void HgfsDoReadInode(struct inode *inode); diff --git a/open-vm-tools/modules/linux/vmhgfs/inode.c b/open-vm-tools/modules/linux/vmhgfs/inode.c index 2999b940..77b16691 100644 --- a/open-vm-tools/modules/linux/vmhgfs/inode.c +++ b/open-vm-tools/modules/linux/vmhgfs/inode.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -33,6 +33,7 @@ #include <linux/highmem.h> #include "compat_cred.h" +#include "compat_dcache.h" #include "compat_fs.h" #include "compat_kernel.h" #include "compat_mm.h" @@ -50,6 +51,23 @@ #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 + /* Private functions. */ static int HgfsDelete(struct inode *dir, struct dentry *dentry, @@ -429,6 +447,8 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from size_t reqBufferSize; size_t reqSize; int result = 0; + uid_t attrUid = -1; + gid_t attrGid = -1; ASSERT(iattr); ASSERT(dentry); @@ -437,6 +457,14 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from 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; @@ -513,13 +541,13 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from if (valid & ATTR_UID) { attrV2->mask |= HGFS_ATTR_VALID_USERID; - attrV2->userId = iattr->ia_uid; + attrV2->userId = attrUid; *changed = TRUE; } if (valid & ATTR_GID) { attrV2->mask |= HGFS_ATTR_VALID_GROUPID; - attrV2->groupId = iattr->ia_gid; + attrV2->groupId = attrGid; *changed = TRUE; } @@ -616,13 +644,13 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from if (valid & ATTR_UID) { attrV2->mask |= HGFS_ATTR_VALID_USERID; - attrV2->userId = iattr->ia_uid; + attrV2->userId = attrUid; *changed = TRUE; } if (valid & ATTR_GID) { attrV2->mask |= HGFS_ATTR_VALID_GROUPID; - attrV2->groupId = iattr->ia_gid; + attrV2->groupId = attrGid; *changed = TRUE; } @@ -1890,7 +1918,7 @@ HgfsPermission(struct inode *inode, #endif &inode->i_dentry, d_alias) { - int dcount = dentry->d_count; + 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)); @@ -1943,11 +1971,7 @@ HgfsPermission(struct inode *inode, list_for_each(pos, &inode->i_dentry) { int dcount; struct dentry *dentry = list_entry(pos, struct dentry, d_alias); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) - dcount = atomic_read(&dentry->d_count); -#else - dcount = dentry->d_count; -#endif + 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)); diff --git a/open-vm-tools/modules/linux/vmhgfs/inode.h b/open-vm-tools/modules/linux/vmhgfs/inode.h index e5f758bb..c86f848d 100644 --- a/open-vm-tools/modules/linux/vmhgfs/inode.h +++ b/open-vm-tools/modules/linux/vmhgfs/inode.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/link.c b/open-vm-tools/modules/linux/vmhgfs/link.c index 65d8a237..06f693b9 100644 --- a/open-vm-tools/modules/linux/vmhgfs/link.c +++ b/open-vm-tools/modules/linux/vmhgfs/link.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -136,6 +136,13 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link #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 /* *---------------------------------------------------------------------- @@ -185,7 +192,7 @@ HgfsReadlink(struct dentry *dentry, // IN: Dentry containing link } else { LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling vfs_readlink %s\n", __func__, fileName)); - error = vfs_readlink(dentry, buffer, buflen, fileName); + error = HGFS_DO_READLINK(dentry, buffer, buflen, fileName); LOG(6, (KERN_DEBUG "VMware hgfs: %s: vfs_readlink %s ret %dn", __func__, fileName, error)); } diff --git a/open-vm-tools/modules/linux/vmhgfs/module.c b/open-vm-tools/modules/linux/vmhgfs/module.c index 4bce943f..aa961283 100644 --- a/open-vm-tools/modules/linux/vmhgfs/module.c +++ b/open-vm-tools/modules/linux/vmhgfs/module.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/module.h b/open-vm-tools/modules/linux/vmhgfs/module.h index 911ba8b7..9c123323 100644 --- a/open-vm-tools/modules/linux/vmhgfs/module.h +++ b/open-vm-tools/modules/linux/vmhgfs/module.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 @@ -74,6 +74,17 @@ extern int LOGLEVEL_THRESHOLD; * 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 + + #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) @@ -110,9 +121,9 @@ extern int LOGLEVEL_THRESHOLD; /* Data kept in each superblock in sb->u. */ typedef struct HgfsSuperInfo { - uid_t uid; /* UID of user who mounted this fs. */ + kuid_t uid; /* UID of user who mounted this fs. */ + kgid_t gid; /* GID of user who mounted this fs. */ Bool uidSet; /* Was the UID specified at mount-time? */ - gid_t gid; /* GID of user who mounted this fs. */ Bool gidSet; /* Was the GID specified at mount-time? */ mode_t fmask; /* File permission mask. */ mode_t dmask; /* Directory permission mask. */ @@ -167,6 +178,9 @@ typedef struct HgfsFileInfo { */ Bool isStale; + /* Directory read position for tracking. */ + loff_t direntPos; + } HgfsFileInfo; diff --git a/open-vm-tools/modules/linux/vmhgfs/page.c b/open-vm-tools/modules/linux/vmhgfs/page.c index 387bc02f..56f98621 100644 --- a/open-vm-tools/modules/linux/vmhgfs/page.c +++ b/open-vm-tools/modules/linux/vmhgfs/page.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/request.c b/open-vm-tools/modules/linux/vmhgfs/request.c index 71758371..dccf481e 100644 --- a/open-vm-tools/modules/linux/vmhgfs/request.c +++ b/open-vm-tools/modules/linux/vmhgfs/request.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/request.h b/open-vm-tools/modules/linux/vmhgfs/request.h index 055f857d..4303924b 100644 --- a/open-vm-tools/modules/linux/vmhgfs/request.h +++ b/open-vm-tools/modules/linux/vmhgfs/request.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/stubs.c b/open-vm-tools/modules/linux/vmhgfs/stubs.c index f79b7656..029d833c 100644 --- a/open-vm-tools/modules/linux/vmhgfs/stubs.c +++ b/open-vm-tools/modules/linux/vmhgfs/stubs.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/super.c b/open-vm-tools/modules/linux/vmhgfs/super.c index 1502513b..04a21920 100644 --- a/open-vm-tools/modules/linux/vmhgfs/super.c +++ b/open-vm-tools/modules/linux/vmhgfs/super.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006 VMware, Inc. All rights reserved. + * Copyright (C) 2006-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 diff --git a/open-vm-tools/modules/linux/vmhgfs/transport.c b/open-vm-tools/modules/linux/vmhgfs/transport.c index a45e3e77..760ae7bf 100644 --- a/open-vm-tools/modules/linux/vmhgfs/transport.c +++ b/open-vm-tools/modules/linux/vmhgfs/transport.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2009 VMware, Inc. All rights reserved. + * Copyright (C) 2009-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 @@ -52,8 +52,6 @@ #include "transport.h" #include "vm_assert.h" -extern int USE_VMCI; - static HgfsTransportChannel *hgfsChannel; /* Current active channel. */ static compat_mutex_t hgfsChannelLock; /* Lock to protect hgfsChannel. */ static struct list_head hgfsRepPending; /* Reply pending queue. */ @@ -156,17 +154,6 @@ HgfsTransportSetupNewChannel(void) { HgfsTransportChannel *newChannel; - newChannel = HgfsGetVmciChannel(); - if (newChannel != NULL) { - if (HgfsTransportOpenChannel(newChannel)) { - hgfsChannel = newChannel; - LOG(10, ("CHANNEL: Vmci channel\n")); - return TRUE; - } - } - - USE_VMCI = 0; - newChannel = HgfsGetBdChannel(); LOG(10, ("CHANNEL: Bd channel\n")); ASSERT(newChannel); diff --git a/open-vm-tools/modules/linux/vmhgfs/transport.h b/open-vm-tools/modules/linux/vmhgfs/transport.h index 7caac3e8..0c0c9542 100644 --- a/open-vm-tools/modules/linux/vmhgfs/transport.h +++ b/open-vm-tools/modules/linux/vmhgfs/transport.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2009 VMware, Inc. All rights reserved. + * Copyright (C) 2009-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 @@ -66,7 +66,6 @@ void HgfsTransportFinishRequest(HgfsReq *req, Bool success, Bool do_put); void HgfsTransportFlushRequests(void); void HgfsTransportMarkDead(void); -HgfsTransportChannel* HgfsGetVmciChannel(void); HgfsTransportChannel *HgfsGetBdChannel(void); #endif // _HGFS_DRIVER_TRANSPORT_H_ diff --git a/open-vm-tools/modules/linux/vmhgfs/vmci.c b/open-vm-tools/modules/linux/vmhgfs/vmci.c deleted file mode 100644 index 027fec77..00000000 --- a/open-vm-tools/modules/linux/vmhgfs/vmci.c +++ /dev/null @@ -1,815 +0,0 @@ -/********************************************************* - * Copyright (C) 2010 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *********************************************************/ - -/* - * vmci.c -- - * - * Provides VMCI transport channel to the HGFS client. - */ - -/* Must come before any kernel header file. */ -#include "driver-config.h" - -#include <linux/errno.h> -#include <linux/moduleparam.h> -#include <linux/interrupt.h> /* for spin_lock_bh */ -#include <asm/io.h> - -#include "compat_mm.h" -#include "hgfsProto.h" -#include "hgfsTransport.h" -#include "module.h" -#include "request.h" -#include "transport.h" -#include "vm_assert.h" -#include "vmci_call_defs.h" -#include "vmci_defs.h" -#include "vmciKernelAPI1.h" - -static Bool HgfsVmciChannelOpen(HgfsTransportChannel *channel); -static void HgfsVmciChannelClose(HgfsTransportChannel *channel); -static HgfsReq * HgfsVmciChannelAllocate(size_t payloadSize); -void HgfsVmciChannelFree(HgfsReq *req); -static int HgfsVmciChannelSend(HgfsTransportChannel *channel, HgfsReq *req); -static void HgfsRequestAsyncDispatch(char *payload, uint32 size); - -int USE_VMCI = 0; -module_param(USE_VMCI, int, 0444); - -static HgfsTransportChannel channel = { - .name = "vmci", - .ops.open = HgfsVmciChannelOpen, - .ops.close = HgfsVmciChannelClose, - .ops.allocate = HgfsVmciChannelAllocate, - .ops.free = HgfsVmciChannelFree, - .ops.send = HgfsVmciChannelSend, - .priv = NULL, - .status = HGFS_CHANNEL_NOTCONNECTED -}; - -static spinlock_t vmciRequestProcessLock; - -typedef struct HgfsShmemPage { - uint64 va; - uint64 pa; - Bool free; -} HgfsShmemPage; - -typedef struct HgfsShmemPages { - HgfsShmemPage *list; - uint32 totalPageCount; - uint32 freePageCount; -} HgfsShmemPages; - -HgfsShmemPages gHgfsShmemPages; -#define HGFS_VMCI_SHMEM_PAGES (16) - - -/* - *---------------------------------------------------------------------- - * - * HgfsRequestAsyncDispatch -- - * - * XXX Main dispatcher function. Currently just a stub. Needs to run - * in atomic context. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsRequestAsyncDispatch(char *payload, // IN: request header - uint32 size) // IN: size of payload -{ - HgfsRequest *reqHeader = (HgfsRequest *)payload; - - LOG(4, (KERN_WARNING "Size in Dispatch %u\n", size)); - - switch (reqHeader->op) { - case HGFS_OP_NOTIFY_V4: { - LOG(4, (KERN_WARNING "Calling HGFS_OP_NOTIFY_V4 dispatch function\n")); - break; - } - default: - LOG(4, (KERN_WARNING "%s: Unknown opcode = %d", __func__, reqHeader->op)); - } -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsRequestAsyncShmemDispatch -- - * - * Shared memory dispatcher. It extracts packets from the shared - * memory and dispatches to the main hgfs dispatcher function. When - * the buffer is larger than 4K, we may fail do deliver notifications. - * Main dispatcher function should run in atomic context. - * - * Results: - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static void -HgfsRequestAsyncShmemDispatch(HgfsAsyncIov *iov, // IN: request vectors - uint32 count) // IN: number of iovs -{ - uint32 i; - char *buf = NULL; - uint32 size = 0; - Bool chainStarted = FALSE; - uint32 offset = 0; - uint32 copySize; - uint64 prevIndex = -1; - uint64 currIndex; - size_t va; - - LOG(10, (KERN_WARNING "%s count = %u\n",__FUNCTION__, count)); - - /* - * When requests cross 4K boundary we have to chain pages together - * since guest passes 4k pages to the host. Here is how chaining works - * - * - All the vectors except the last one in the chain sets iov[].chain - * to TRUE. - * - Every iov[].len field indicates remaining bytes. So the first - * vector will contain total size of the request while the last vector - * will contain only size of data present in last vector. - */ - - for (i = 0; i < count; i++) { - va = (size_t)iov[i].va; - currIndex = iov[i].index; - - if (LIKELY(!iov[i].chain)) { - /* When the chain ends we dispatch the datagram.*/ - if (!chainStarted) { - buf = (char *)va; - LOG(8, (KERN_WARNING " Chain wasn't started...\n")); - size = iov[i].len; - } else { - memcpy(buf + offset, (char *)va, iov[i].len); - } - ASSERT(buf && size); - HgfsRequestAsyncDispatch(buf, size); - if (chainStarted) { - /* Well chain just ended, we shall free the buffer. */ - chainStarted = FALSE; - kfree(buf); - } - } else { - if (!chainStarted) { - LOG(8, (KERN_WARNING "Started chain ...\n")); - size = iov[i].len; - buf = kmalloc(size, GFP_ATOMIC); - ASSERT_DEVEL(buf); - if (!buf) { - /* Skip this notification, move onto next. */ - i += (size - 1) / PAGE_SIZE; - continue; - } - chainStarted = TRUE; - offset = 0; - } - copySize = MIN(iov[i].len, PAGE_SIZE); - memcpy(buf + offset, (char *)va, copySize); - offset += copySize; - } - - if (currIndex != prevIndex) { - /* This is new page. Mark is as free. */ - gHgfsShmemPages.list[currIndex].free = TRUE; - gHgfsShmemPages.freePageCount++; - } - prevIndex = currIndex; - } - - ASSERT(gHgfsShmemPages.freePageCount <= gHgfsShmemPages.totalPageCount); - LOG(8, (KERN_WARNING "Page count %u %u ...\n", gHgfsShmemPages.freePageCount, - gHgfsShmemPages.totalPageCount)); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelPassGuestPages -- - * - * Passes down free pages to the hgfs Server. HgfsServer will use this pages - * for sending change notification, oplock breaks etc. - * - * XXX It seems safe to call vmci_datagram_send in atomic context. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static Bool -HgfsVmciChannelPassGuestPages(HgfsTransportChannel *channel) // IN: -{ - Bool retVal = TRUE; - int ret; - int i; - int j = 0; - size_t transportHeaderSize; - HgfsVmciTransportHeader *transportHeader = NULL; - HgfsVmciHeaderNode *headerNode; - VMCIDatagram *dg; - - if (!gHgfsShmemPages.freePageCount) { - return TRUE; - } - - transportHeaderSize = sizeof (HgfsVmciTransportHeader) + - (gHgfsShmemPages.freePageCount - 1) * sizeof (HgfsAsyncIov); - - dg = kmalloc(sizeof *dg + transportHeaderSize, GFP_ATOMIC); - if (!dg) { - LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__)); - retVal = FALSE; - goto exit; - } - - transportHeader = VMCI_DG_PAYLOAD(dg); - headerNode = &transportHeader->node; - - for (i = 0; i < gHgfsShmemPages.totalPageCount; i++) { - if (gHgfsShmemPages.list[i].free) { - transportHeader->asyncIov[j].index = i; - transportHeader->asyncIov[j].va = gHgfsShmemPages.list[i].va; - transportHeader->asyncIov[j].pa = gHgfsShmemPages.list[i].pa; - transportHeader->asyncIov[j].len = PAGE_SIZE; - j++; - } - } - - dg->src = *(VMCIHandle *)channel->priv; - dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT); - dg->payloadSize = transportHeaderSize; - - headerNode->version = HGFS_VMCI_VERSION_1; - headerNode->pktType = HGFS_TH_REP_GET_PAGES; - - ASSERT(gHgfsShmemPages.freePageCount == j); - transportHeader->iovCount = j; - - LOG(10, (KERN_WARNING "Sending %d Guest pages \n", i)); - if ((ret = vmci_datagram_send(dg)) < VMCI_SUCCESS) { - if (ret == HGFS_VMCI_TRANSPORT_ERROR) { - LOG(0, (KERN_WARNING "HGFS Transport error occured. Don't blame VMCI\n")); - } - retVal = FALSE; - } - -exit: - if (retVal) { - /* We successfully sent pages the the host. Mark all pages as allocated */ - for (i = 0; i < gHgfsShmemPages.totalPageCount; i++) { - gHgfsShmemPages.list[i].free = FALSE; - } - gHgfsShmemPages.freePageCount = 0; - } - kfree(dg); - return retVal; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelCompleteRequest -- - * - * Completes the request that was serviced asynchronously by the server. - * - * Results: - * None - * - * Side effects: - * Request may be removed from the queue and sleeping thread is woken up. - * - *----------------------------------------------------------------------------- - */ - -void -HgfsVmciChannelCompleteRequest(uint64 id) // IN: Request ID -{ - HgfsVmciTransportStatus *transportStatus; - HgfsReq *req; - - spin_lock_bh(&vmciRequestProcessLock); - - /* Reference is taken here */ - req = HgfsTransportGetPendingRequest(id); - if (!req) { - LOG(0, (KERN_WARNING "No request with id %"FMT64"u \n", id)); - goto exit; - } - - transportStatus = (HgfsVmciTransportStatus *)req->buffer; - if (transportStatus->status != HGFS_TS_IO_COMPLETE) { - LOG(0, (KERN_WARNING "Request not completed with id %"FMT64"u \n", id)); - goto exit; - } - - /* Request is completed (yay!), let's remove it from the list */ - HgfsTransportRemovePendingRequest(req); - - req->payloadSize = transportStatus->size; - HgfsCompleteReq(req); - -exit: - if (req) { - /* Drop the reference taken in *GetPendingRequest */ - HgfsRequestPutRef(req); - } - spin_unlock_bh(&vmciRequestProcessLock); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelCallback -- - * - * Called when VMCI datagram is received. Note: This function runs inside - * tasklet. It means that this function cannot run concurrently with - * itself, thus it is safe to manipulate gHgfsShmemPages without locks. If this - * ever changes, please consider using appropriate locks. - * - * Results: - * 0 on Success, < 0 on Failure. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int HgfsVmciChannelCallback(void *data, // IN: unused - VMCIDatagram *dg) // IN: datagram -{ - HgfsVmciAsyncReply *reply = (HgfsVmciAsyncReply *)VMCI_DG_PAYLOAD(dg); - HgfsVmciHeaderNode *replyNode = &reply->node; - HgfsTransportChannel *channel; - - LOG(10, (KERN_WARNING "Received VMCI channel Callback \n")); - - if (replyNode->version != HGFS_VMCI_VERSION_1) { - return HGFS_VMCI_VERSION_MISMATCH; - } - - switch (replyNode->pktType) { - - case HGFS_ASYNC_IOREP: - LOG(10, (KERN_WARNING "Received ID%"FMT64"x \n", reply->response.id)); - HgfsVmciChannelCompleteRequest(reply->response.id); - break; - - case HGFS_ASYNC_IOREQ_SHMEM: - HgfsRequestAsyncShmemDispatch(reply->shmem.iov, reply->shmem.count); - break; - - case HGFS_ASYNC_IOREQ_GET_PAGES: - channel = HgfsGetVmciChannel(); - LOG(10, (KERN_WARNING "Should send pages to the host\n")); - HgfsVmciChannelPassGuestPages(channel); - break; - - default: - ASSERT(0); - return HGFS_VMCI_TRANSPORT_ERROR; - } - - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelOpen -- - * - * Opens VMCI channel and passes guest pages to the host. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static Bool -HgfsVmciChannelOpen(HgfsTransportChannel *channel) // IN: Channel -{ - int ret; - int i; - - ASSERT(channel->status == HGFS_CHANNEL_NOTCONNECTED); - ASSERT(channel->priv == NULL); - memset(&gHgfsShmemPages, 0, sizeof gHgfsShmemPages); - - if (USE_VMCI == 0) { - goto error; - } - - spin_lock_init(&vmciRequestProcessLock); - - channel->priv = kmalloc(sizeof(VMCIHandle), GFP_KERNEL); - if (!channel->priv) { - goto error; - } - - ret = vmci_datagram_create_handle( - VMCI_INVALID_ID, /* Resource ID */ - VMCI_FLAG_DG_NONE, /* Flags */ - HgfsVmciChannelCallback,/* Datagram Recv Callback */ - NULL, /* Callback data */ - channel->priv); /* VMCI outhandle */ - if (ret != VMCI_SUCCESS) { - LOG(1, (KERN_WARNING "Failed to create VMCI handle %d\n", ret)); - goto error; - } - - gHgfsShmemPages.list = kmalloc(sizeof *gHgfsShmemPages.list * HGFS_VMCI_SHMEM_PAGES, - GFP_KERNEL); - if (!gHgfsShmemPages.list) { - goto error; - } - - memset(gHgfsShmemPages.list, 0, sizeof *gHgfsShmemPages.list * HGFS_VMCI_SHMEM_PAGES); - - for (i = 0; i < HGFS_VMCI_SHMEM_PAGES; i++) { - gHgfsShmemPages.list[i].va = __get_free_page(GFP_KERNEL); - if (!gHgfsShmemPages.list[i].va) { - LOG(1, (KERN_WARNING "__get_free_page returned error \n")); - if (i == 0) { - /* Ouch. We failed on first call to __get_free_page */ - goto error; - } - /* It's ok. We can still send few pages to the host */ - break; - } - gHgfsShmemPages.list[i].pa = virt_to_phys((void *)(size_t)gHgfsShmemPages.list[i].va); - gHgfsShmemPages.list[i].free = TRUE; - } - - gHgfsShmemPages.totalPageCount = i; - gHgfsShmemPages.freePageCount = i; - - ret = HgfsVmciChannelPassGuestPages(channel); - if (!ret) { - for (i = 0; i < gHgfsShmemPages.totalPageCount; i++) { - LOG(1, (KERN_WARNING "Freeing pages\n")); - free_page(gHgfsShmemPages.list[i].va); - } - LOG(1, (KERN_WARNING "Failed to pass pages to the guest %d\n", ret)); - goto error; - } - - return TRUE; - -error: - kfree(gHgfsShmemPages.list); - kfree(channel->priv); - return FALSE; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelTerminateSession -- - * - * Terminate session with the server. - * - * Results: - * 0 on success and < 0 on error. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static int -HgfsVmciChannelTerminateSession(HgfsTransportChannel *channel) { - - int ret = 0; - VMCIDatagram *dg; - HgfsVmciTransportHeader *transportHeader; - HgfsVmciHeaderNode *headerNode; - - dg = kmalloc(sizeof *dg + sizeof *transportHeader, GFP_KERNEL); - if (NULL == dg) { - LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__)); - return -ENOMEM; - } - - /* Initialize datagram */ - dg->src = *(VMCIHandle *)channel->priv; - dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT); - dg->payloadSize = sizeof *transportHeader; - - transportHeader = VMCI_DG_PAYLOAD(dg); - headerNode = &transportHeader->node; - - headerNode->pktType = HGFS_TH_TERMINATE_SESSION; - headerNode->version = HGFS_VMCI_VERSION_1; - - transportHeader->iovCount = 0; - - LOG(1, (KERN_WARNING "Terminating session with host \n")); - if ((ret = vmci_datagram_send(dg)) < VMCI_SUCCESS) { - if (ret == HGFS_VMCI_TRANSPORT_ERROR) { - LOG(0, (KERN_WARNING "HGFS Transport error occured. Don't blame VMCI\n")); - } - LOG(0, (KERN_WARNING "Cannot communicate with Server.\n")); - } else { - int i; - for (i = 0; i < gHgfsShmemPages.totalPageCount; i++) { - free_page(gHgfsShmemPages.list[i].va); - } - } - - kfree(dg); - return ret; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelClose -- - * - * Destroy vmci handle. - * - * Results: - * None - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static void -HgfsVmciChannelClose(HgfsTransportChannel *channel) // IN: Channel -{ - ASSERT(channel->priv != NULL); - HgfsVmciChannelTerminateSession(channel); - vmci_datagram_destroy_handle(*(VMCIHandle *)channel->priv); - kfree(channel->priv); - kfree(gHgfsShmemPages.list); - channel->priv = NULL; - - LOG(8, ("VMware hgfs: %s: vmci closed.\n", __func__)); -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelAllocate -- - * - * Allocate request in the way that is suitable for sending through - * vmci. Today, we just allocate a page for the request and we ignore - * payloadSize. We need this to support variable sized requests in future. - * - * Results: - * NULL on failure; otherwise address of the new request. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static HgfsReq * -HgfsVmciChannelAllocate(size_t payloadSize) // IN: Ignored -{ - HgfsReq *req = NULL; - const size_t size = PAGE_SIZE; - - req = kmalloc(size, GFP_KERNEL); - if (likely(req)) { - req->payload = req->buffer + sizeof (HgfsVmciTransportStatus); - req->bufferSize = size - sizeof (HgfsVmciTransportStatus) - sizeof *req; - } - - LOG(10, (KERN_WARNING "%s: Allocated Request\n", __func__)); - return req; -} - - -/* - *----------------------------------------------------------------------------- - * - * HgfsVmciChannelFree -- - * - * Free previously allocated request. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -HgfsVmciChannelFree(HgfsReq *req) -{ - ASSERT(req); - kfree(req); -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsVmciChannelSend -- - * - * Send a request via vmci. - * - * Results: - * 0 on success, negative error on failure. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -static int -HgfsVmciChannelSend(HgfsTransportChannel *channel, // IN: Channel - HgfsReq *req) // IN: request to send -{ - int ret; - int iovCount = 0; - VMCIDatagram *dg; - HgfsVmciTransportHeader *transportHeader; - HgfsVmciHeaderNode *headerNode; - HgfsVmciTransportStatus *transportStatus; - size_t transportHeaderSize; - size_t bufferSize; - size_t total; - uint64 pa; - uint64 len; - uint64 id; - int j; - - ASSERT(req); - ASSERT(req->buffer); - ASSERT(req->state == HGFS_REQ_STATE_UNSENT || req->state == HGFS_REQ_STATE_ALLOCATED); - ASSERT(req->payloadSize <= req->bufferSize); - - /* Note that req->bufferSize does not include chunk used by the transport. */ - total = req->bufferSize + sizeof (HgfsVmciTransportStatus); - - /* Calculate number of entries for metaPacket */ - iovCount = (total + (size_t)req->buffer % PAGE_SIZE - 1)/ PAGE_SIZE + 1; - ASSERT(total + (size_t)req->buffer % PAGE_SIZE <= PAGE_SIZE); - - transportHeaderSize = sizeof *transportHeader + - (iovCount + req->numEntries - 1) * sizeof (HgfsIov); - dg = kmalloc(sizeof *dg + transportHeaderSize, GFP_KERNEL); - if (NULL == dg) { - LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__)); - return -ENOMEM; - } - - /* Initialize datagram */ - dg->src = *(VMCIHandle *)channel->priv; - dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT); - dg->payloadSize = transportHeaderSize; - - transportHeader = VMCI_DG_PAYLOAD(dg); - headerNode = &transportHeader->node; - - headerNode->version = HGFS_VMCI_VERSION_1; - headerNode->pktType = HGFS_TH_REQUEST; - - total = req->bufferSize + sizeof (HgfsVmciTransportStatus); - bufferSize = 0; - for (iovCount = 0; bufferSize < req->bufferSize; iovCount++) { - /* - * req->buffer should have been allocated by kmalloc()/ __get_free_pages(). - * Specifically, it cannot be a buffer that is mapped from high memory. - * virt_to_phys() does not work for those. - */ - pa = virt_to_phys(req->buffer + bufferSize); - len = total < (PAGE_SIZE - pa % PAGE_SIZE) ? total : (PAGE_SIZE - pa % PAGE_SIZE); - bufferSize += len; - total -= len; - transportHeader->iov[iovCount].pa = pa; - transportHeader->iov[iovCount].len = len; - LOG(8, ("iovCount = %u PA = %"FMT64"x len=%u\n", iovCount, - transportHeader->iov[iovCount].pa, transportHeader->iov[iovCount].len)); - } - - /* Right now we do not expect discontigous request packet */ - ASSERT(iovCount == 1); - ASSERT(total == 0); - ASSERT(bufferSize == req->bufferSize + sizeof (HgfsVmciTransportStatus)); - - LOG(0, (KERN_WARNING "Size of request is %Zu\n", req->payloadSize)); - - for (j = 0; j < req->numEntries; j++, iovCount++) { - /* I will have to probably do page table walk here, haven't figured it out yet */ - ASSERT(req->dataPacket); - transportHeader->iov[iovCount].pa = page_to_phys(req->dataPacket[j].page); - transportHeader->iov[iovCount].pa += req->dataPacket[j].offset; - transportHeader->iov[iovCount].len = req->dataPacket[j].len; - LOG(8, ("iovCount = %u PA = %"FMT64"x len=%u\n", iovCount, - transportHeader->iov[iovCount].pa, - transportHeader->iov[iovCount].len)); - } - - transportHeader->iovCount = iovCount; - - /* Initialize transport Status */ - transportStatus = (HgfsVmciTransportStatus *)req->buffer; - transportStatus->status = HGFS_TS_IO_PENDING; - transportStatus->size = req->bufferSize + sizeof (HgfsVmciTransportStatus); - - /* - * Don't try to set req->state after vmci_datagram_send(). - * It may be too late then. We could have received a datagram by then and - * datagram handler expects request's state to be submitted. - */ - req->state = HGFS_REQ_STATE_SUBMITTED; - id = req->id; - - if ((ret = vmci_datagram_send(dg)) < VMCI_SUCCESS) { - if (ret == HGFS_VMCI_TRANSPORT_ERROR) { - LOG(0, (KERN_WARNING "HGFS Transport error occured. Don't blame VMCI\n")); - } else if (ret == HGFS_VMCI_VERSION_MISMATCH) { - LOG(0, (KERN_WARNING "Version mismatch\n")); - } - req->state = HGFS_REQ_STATE_UNSENT; - kfree(dg); - return -EIO; - } - - LOG(0, (KERN_WARNING "Hgfs Received response\n")); - HgfsVmciChannelCompleteRequest(id); - - kfree(dg); - return 0; -} - - -/* - *---------------------------------------------------------------------- - * - * HgfsGetVmciChannel -- - * - * Initialize Vmci channel. - * - * Results: - * Always return pointer to Vmci channel. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -HgfsTransportChannel* -HgfsGetVmciChannel(void) -{ - return &channel; -} diff --git a/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h b/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h index 1ed35935..c5f19dcc 100644 --- a/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h +++ b/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. + * 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 diff --git a/open-vm-tools/modules/linux/vmsync/Makefile b/open-vm-tools/modules/linux/vmsync/Makefile index 4d81760c..3c681a36 100644 --- a/open-vm-tools/modules/linux/vmsync/Makefile +++ b/open-vm-tools/modules/linux/vmsync/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 diff --git a/open-vm-tools/modules/linux/vmxnet/Makefile b/open-vm-tools/modules/linux/vmxnet/Makefile index 4264b475..1c1bfd80 100644 --- a/open-vm-tools/modules/linux/vmxnet/Makefile +++ b/open-vm-tools/modules/linux/vmxnet/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 diff --git a/open-vm-tools/modules/linux/vmxnet/vmxnet.c b/open-vm-tools/modules/linux/vmxnet/vmxnet.c index 54b4590c..33afb9b9 100644 --- a/open-vm-tools/modules/linux/vmxnet/vmxnet.c +++ b/open-vm-tools/modules/linux/vmxnet/vmxnet.c @@ -80,10 +80,6 @@ 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 LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) -static int vmxnet_set_features(struct net_device *netdev, compat_netdev_features_t - features); -#endif #if defined(HAVE_CHANGE_MTU) || defined(HAVE_NET_DEVICE_OPS) static int vmxnet_change_mtu(struct net_device *dev, int new_mtu); #endif @@ -992,14 +988,18 @@ 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 LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) - .ndo_set_features = vmxnet_set_features, -#endif #if COMPAT_LINUX_VERSION_CHECK_LT(3, 2, 0) .ndo_set_multicast_list = &vmxnet_set_multicast_list, #else @@ -1315,6 +1315,11 @@ vmxnet_probe_features(struct net_device *dev, // IN: } #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){ @@ -1362,6 +1367,10 @@ vmxnet_probe_features(struct net_device *dev, // IN: #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 */ @@ -3119,20 +3128,6 @@ vmxnet_get_stats(struct net_device *dev) return &lp->stats; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) -static int -vmxnet_set_features(struct net_device *netdev, compat_netdev_features_t features) -{ - compat_netdev_features_t changed = features ^ netdev->features; - - if (changed & (NETIF_F_RXCSUM)) { - if (features & NETIF_F_RXCSUM) - return 0; - } - return -1; -} -#endif - module_init(vmxnet_init); module_exit(vmxnet_exit); MODULE_DEVICE_TABLE(pci, vmxnet_chips); diff --git a/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h b/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h index a58bb408..fe2ad538 100644 --- a/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h +++ b/open-vm-tools/modules/linux/vmxnet/vmxnet_version.h @@ -25,8 +25,8 @@ #ifndef _VMXNET_VERSION_H_ #define _VMXNET_VERSION_H_ -#define VMXNET_DRIVER_VERSION 2.0.15.0 -#define VMXNET_DRIVER_VERSION_COMMAS 2,0,15,0 -#define VMXNET_DRIVER_VERSION_STRING "2.0.15.0" +#define VMXNET_DRIVER_VERSION 2.1.0.0 +#define VMXNET_DRIVER_VERSION_COMMAS 2,1,0,0 +#define VMXNET_DRIVER_VERSION_STRING "2.1.0.0" #endif /* _VMXNET_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vsock/Makefile b/open-vm-tools/modules/linux/vsock/Makefile index 852c9345..7549fa50 100644 --- a/open-vm-tools/modules/linux/vsock/Makefile +++ b/open-vm-tools/modules/linux/vsock/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 1998 VMware, Inc. All rights reserved. +# Copyright (C) 1998-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 diff --git a/open-vm-tools/modules/linux/vsock/Makefile.kernel b/open-vm-tools/modules/linux/vsock/Makefile.kernel index b4629eee..5218df2f 100644 --- a/open-vm-tools/modules/linux/vsock/Makefile.kernel +++ b/open-vm-tools/modules/linux/vsock/Makefile.kernel @@ -1,6 +1,6 @@ #!/usr/bin/make -f ########################################################## -# Copyright (C) 2007 VMware, Inc. All rights reserved. +# 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 @@ -64,9 +64,9 @@ clean: prebuild:: ifneq ($(MODULEBUILDDIR),) ifeq ($(MODPOST_VMCI_SYMVERS),) - $(shell echo >&2 "Building VMCI Sockets without VMCI module symbols.") + $(shell echo >&2 "Building vSockets without VMCI module symbols.") else - $(shell echo >&2 "Building VMCI Sockets with VMCI module symbols.") + $(shell echo >&2 "Building vSockets with VMCI module symbols.") cp -f $(MODPOST_VMCI_SYMVERS) $(SRCROOT)/Module.symvers endif endif diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c index e278e152..bde14970 100644 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c +++ b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007-2011 VMware, Inc. All rights reserved. + * 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 @@ -19,7 +19,7 @@ /* * af_vsock.c -- * - * Linux socket module for the VMCI Sockets protocol family. + * Linux socket module for the vSockets protocol family. */ @@ -591,7 +591,7 @@ VSockVmciAllowDgram(VSockVmciSock *vsock, // IN: Local socket * VMCISock_GetAFValue -- * * Kernel interface that allows external kernel modules to get the current - * VMCI Sockets address family. + * vSockets address family. * This version of the function is exported to kernel clients and should not * change. * @@ -613,7 +613,7 @@ VMCISock_GetAFValue(void) /* * Kernel clients are required to explicitly register themselves before they - * can use VMCI Sockets. + * can use vSockets. */ if (vsockVmciKernClientCount <= 0) { afvalue = -1; @@ -657,7 +657,7 @@ VMCISock_GetLocalCID(void) /* * Kernel clients are required to explicitly register themselves before they - * can use VMCI Sockets. + * can use vSockets. */ if (vsockVmciKernClientCount <= 0) { cid = -1; @@ -678,7 +678,7 @@ EXPORT_SYMBOL(VMCISock_GetLocalCID); * * VMCISock_KernelRegister -- * - * Allows a kernel client to register with VMCI Sockets. Must be called + * 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. @@ -707,7 +707,7 @@ EXPORT_SYMBOL(VMCISock_KernelRegister); * * VMCISock_KernelDeregister -- * - * Allows a kernel client to unregister with VMCI Sockets. Every call + * Allows a kernel client to unregister with vSockets. Every call * to VMCISock_KernRegister must be matched with a call to * VMCISock_KernUnregister. * @@ -3080,7 +3080,7 @@ VSockVmciQueueRcvSkb(struct sock *sk, // IN * * VSockVmciRegisterProto -- * - * Registers the vmci sockets protocol family. + * Registers the vSockets protocol family. * * Results: * Zero on success, error code on failure. @@ -3124,7 +3124,7 @@ VSockVmciRegisterProto(void) * * VSockVmciUnregisterProto -- * - * Unregisters the vmci sockets protocol family. + * Unregisters the vSockets protocol family. * * Results: * None. diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.h b/open-vm-tools/modules/linux/vsock/linux/af_vsock.h index 30600ae5..08e437d0 100644 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.h +++ b/open-vm-tools/modules/linux/vsock/linux/af_vsock.h @@ -60,7 +60,11 @@ typedef struct VSockVmciSock { 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; diff --git a/open-vm-tools/modules/linux/vsock/linux/stats.h b/open-vm-tools/modules/linux/vsock/linux/stats.h index b47b3552..c42f5757 100644 --- a/open-vm-tools/modules/linux/vsock/linux/stats.h +++ b/open-vm-tools/modules/linux/vsock/linux/stats.h @@ -68,9 +68,9 @@ extern Atomic_uint64 vSockStatsProduceTotal; ++vSockStatsCtlPktCount[pktType]; \ } while (0) #define VSOCK_STATS_STREAM_CONSUME(bytes) \ - Atomic_FetchAndAdd64(&vSockStatsConsumeTotal, bytes) + Atomic_ReadAdd64(&vSockStatsConsumeTotal, bytes) #define VSOCK_STATS_STREAM_PRODUCE(bytes) \ - Atomic_FetchAndAdd64(&vSockStatsProduceTotal, 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() diff --git a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h b/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h index 4c5d9904..91654c34 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h +++ b/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_int.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2009 VMware, Inc. All rights reserved. + * 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 @@ -19,7 +19,7 @@ /* * vmci_sockets_int.h -- * - * VMCI sockets private constants and types. + * 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 diff --git a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h b/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h index 603835b5..abc42ade 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h +++ b/open-vm-tools/modules/linux/vsock/linux/vmci_sockets_packet.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2012 VMware, Inc. All rights reserved. + * 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 @@ -19,7 +19,7 @@ /* * vmci_sockets_packet.h -- * - * Definition of VMCI Sockets packet format, constants, and types. + * Definition of vSockets packet format, constants, and types. */ #ifndef _VMCI_SOCKETS_PACKET_H_ @@ -108,51 +108,11 @@ typedef struct VSockPacket { } VSockPacket; /* - * SEQPACKET packets. - */ - -#define VSOCK_SEQ_PACKET_VERSION_1 1 -#define VSOCK_SEQ_PACKET_VERSION VSOCK_SEQ_PACKET_VERSION_1 - -/* Get the packet's payload size in bytes. */ -#define VSOCK_SEQ_PACKET_PAYLOAD_SIZE(_pkt) \ - (VMCI_DG_SIZE(&(_pkt)->hdr.dg) - (_pkt)->hdr.offset) - -/* Get a pointer to the packet's payload. */ -#define VSOCK_SEQ_PACKET_PAYLOAD(_pkt) \ - (void *)((char *)_pkt + (_pkt)->hdr.offset) - -typedef enum VSockSeqPacketType { - VSOCK_SEQ_PACKET_TYPE_INVALID = 0, // Invalid type. - VSOCK_SEQ_PACKET_TYPE_CONNECT, // Connection request. - VSOCK_SEQ_PACKET_TYPE_DATA, // Data. - VSOCK_SEQ_PACKET_TYPE_SHUTDOWN, // Shutdown. - VSOCK_SEQ_PACKET_TYPE_CLOSE, // Close (graceful or error). -} VSockSeqPacketType; - -/* Header for all packet versions. */ -typedef struct VSockSeqPacketHdr { - VMCIDatagram dg; // Datagram header. - uint8 version; // Version. - uint8 type; // Type of message. - uint16 offset; // Offset of data from start of packet. - int32 val; // Value. -} VSockSeqPacketHdr; - -/* Combination of all versions. */ -typedef struct VSockSeqPacket { - VSockSeqPacketHdr hdr; - /* Other versions go here. */ - /* Data is at base + hdr.offset. */ -} VSockSeqPacket; - -/* * Size assertions. */ MY_ASSERTS(VSockSeqPacketAsserts, ASSERT_ON_COMPILE(sizeof (VSockPacket) == 56); - ASSERT_ON_COMPILE(sizeof (VSockSeqPacket) == 32); ) #endif // _VMCI_SOCKETS_PACKET_H_ diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h b/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h index 745c8474..f86f2148 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h +++ b/open-vm-tools/modules/linux/vsock/linux/vsockCommon.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2007 VMware, Inc. All rights reserved. + * 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 @@ -31,7 +31,7 @@ * 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 VMCI Sockets api inside the kernel. + * than external kernel modules using vSockets API inside the kernel. */ #if defined VMX86_VMX @@ -51,7 +51,7 @@ /* 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. */ + /* In userland, just use the normal exported userlevel API. */ # define VMCISockGetAFValueInt() VMCISock_GetAFValue() # include <windows.h> # endif // WINNT_DDK @@ -72,7 +72,7 @@ extern int VSockVmci_GetAFValue(void); # define VMCISockGetAFValueInt() VSockVmci_GetAFValue() # else // __KERNEL__ - /* In userland, just use the normal exported userlevel api. */ + /* In userland, just use the normal exported userlevel API. */ # define VMCISockGetAFValueInt() VMCISock_GetAFValue() # endif #elif defined __APPLE__ @@ -189,7 +189,7 @@ __declspec(selectany) extern const WSAPROTOCOL_INFOW vsockProtocolInfos[] = { 0, /* Assigned by Winsock. */ { 1, 0 }, /* Base provider. */ 0, /* Version 0. */ - VMCI_SOCKETS_AF_VALUE, /* VMCI sockets protocol. */ + VMCI_SOCKETS_AF_VALUE, /* vSockets protocol. */ 16, /* Maximum address length in bytes. */ 16, /* Minimum address length in bytes. */ SOCK_DGRAM, /* STREAM. */ @@ -199,7 +199,7 @@ __declspec(selectany) extern const WSAPROTOCOL_INFOW vsockProtocolInfos[] = { SECURITY_PROTOCOL_NONE, /* No security. */ 0, /* Message size unimportant. */ 0, /* None. */ - L"VMCI sockets DGRAM" /* Protocol name. */ + L"vSockets DGRAM" /* Protocol name. */ }, { (XP1_GUARANTEED_DELIVERY | /* Guaranteed delivery. */ @@ -213,7 +213,7 @@ __declspec(selectany) extern const WSAPROTOCOL_INFOW vsockProtocolInfos[] = { 0, /* Assigned by Winsock. */ { 1, 0 }, /* Base provider. */ 0, /* Version 0. */ - VMCI_SOCKETS_AF_VALUE, /* VMCI sockets protocol. */ + VMCI_SOCKETS_AF_VALUE, /* vSockets protocol. */ 16, /* Maximum address length in bytes. */ 16, /* Minimum address length in bytes. */ SOCK_STREAM, /* STREAM. */ @@ -223,7 +223,7 @@ __declspec(selectany) extern const WSAPROTOCOL_INFOW vsockProtocolInfos[] = { SECURITY_PROTOCOL_NONE, /* No security. */ 0, /* Message size unimportant. */ 0, /* None. */ - L"VMCI sockets STREAM" /* Protocol name. */ + L"vSockets STREAM" /* Protocol name. */ }, }; diff --git a/open-vm-tools/modules/linux/vsock/linux/vsock_version.h b/open-vm-tools/modules/linux/vsock/linux/vsock_version.h index ae39173a..f46bf539 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsock_version.h +++ b/open-vm-tools/modules/linux/vsock/linux/vsock_version.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2011-2013 VMware, Inc. All rights reserved. + * Copyright (C) 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 @@ -25,8 +25,8 @@ #ifndef _VSOCK_VERSION_H_ #define _VSOCK_VERSION_H_ -#define VSOCK_DRIVER_VERSION 9.6.0.0 -#define VSOCK_DRIVER_VERSION_COMMAS 9,6,0,0 -#define VSOCK_DRIVER_VERSION_STRING "9.6.0.0" +#define VSOCK_DRIVER_VERSION 9.7.1.0 +#define VSOCK_DRIVER_VERSION_COMMAS 9,7,1,0 +#define VSOCK_DRIVER_VERSION_STRING "9.7.1.0" #endif /* _VSOCK_VERSION_H_ */ |