+2009-08-24 Marcelo Vanzin <mvanzin@vmware.com>
+ * Resync with internal trunk (2009.08.19)
+
+ * configure.ac: remove support for Linux kernels < 2.6.9.
+
+ * lib/include/vmtools.h, libvmtools/vmtoolsLog.c, doc/api/services/util.txt:
+ add new log handled that allows appending to existing log files, and fix
+ an issue where old log files would be "rotated" whenever the config file
+ was reloaded.
+
+ * lib/appUtil/appUtilX11.c, lib/ghIntegration/ghIntegrationX11.c,
+ lib/include/appUtil.h: fix compilation issues on FreeBSD when unity
+ was enabled.
+
+ * lib/dnd/dndLinux.c, lib/include/vmblock_user.h, tests/testVmblock/*: add
+ vmblock tests and, as part of the change, do some refactoring of vmblock
+ related functions.
+
+ * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/*,
+ toolbox/toolboxcmd-shrink.c, toolbox/toolboxShrink.c: refactor the wiper
+ structures so that they behave the same on Win32 and other platforms, and
+ also reuse data structures already in use by other parts of the code. This
+ fixes an "use after free" issue that toolbox-cmd had on Win32.
+
+ * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoInt.h,
+ lib/guestInfo/guestInfoPosix.c, lib/guestRpc/nicinfo.x,
+ lib/include/guestInfo.h, lib/include/netutil.h, lib/include/slashProc.h,
+ lib/netutil/netUtilLinux.c, lib/slashProc/*,
+ services/plugins/guestInfo/guestInfoServer.c: add support for sending more
+ network-related information to the host, such as routing tables and name
+ servers.
+
+ * lib/hgfsBd/hgfsBd.c: don't log RPC errors when HGFS is disabled.
+
+ * lib/hgfsHelper/*, lib/include/hgfsHelper.h, lib/vixTools/vixTools.c: new
+ library with functions to query information about HGFS; expose some HGFS
+ properties through VIX.
+
+ * lib/hgfsServer/*, lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c,
+ lib/include/hgfsServerPolicy.h: fix checking of whether an object belongs
+ to a particular share; this was causing issues with invalid information
+ being returned in certain cases.
+
+ * lib/hgfsServer/*, lib/include/hgfsProto.h: changes to support new VIX API
+ calls (mostly affecting Win32 only).
+
+ * lib/include/guestCaps.h, lib/include/unityCommon.h: add boilerplate for new
+ RPCs for setting windows as sticky / non-sticky (not yet implemented).
+
+ * lib/include/hgfsProto.h: new definitions for the next version of the HGFS
+ protocol.
+
+ * lib/include/xdrutil.h: make XDRUTIL_ARRAYAPPEND() more type-safe when using
+ GCC.
+
+ * lib/misc/codesetOld.c: fix some issues with UTF16 -> UTF8 conversion.
+
+ * lib/rpcChannel/rpcChannel.c, libvmtools/signalSource.c,
+ libvmtools/vmtools.c, libvmtools/vmtoolsConfig.c: g_assert -> ASSERT.
+
+ * lib/unityWindowTracker/unityWindowTracker.c: fix issue with z-ordering of
+ modal dialogs.
+
+ * libvmtools/vmtoolsConfig.c: fix some old config translation issues.
+
+ * modules/freebsd/shared/*, modules/freebsd/vmblock/*: make vmblock work on
+ FreeBSD 8.
+
+ * modules/freebsd/vmmemctl/*, modules/linux/vmmemctl/*,
+ modules/solaris/vmmemctl/*, : refactoring and code changes to support the
+ driver on Mac OS X.
+
+ * modules/linux/vmblock/*, modules/linux/vmci/*, modules/linux/vsock/linux/*:
+ remove compatibility code for older kernels.
+
+ * modules/linux/vmhgfs/*: fix memory leak in HgfsAccessInt().
+
+ * modules/linux/vmxnet3/*: fix kunmap usage in vmxnet3_shm, and reset the
+ shared pages when the char device is closed.
+
+ * modules/linux/vsock/linux/af_vsock.{c,h}, modules/linux/vsock/linux/util.c:
+ add vsock protocol negotiation for notifyOn ops. This allows the driver to
+ negotiate with the remove end which version of the notification protocol to
+ use.
+
+ * modules/linux/vsock/linux/notify.c, modules/linux/vsock/linux/notify.h,
+ modules/linux/vsock/linux/notifyQState.c,
+ modules/linux/vsock/linux/vsockPacket.h: add pktOn protocol. This new
+ protocol improves performance by detecting changes in the queue state
+ instead of sending WAITING_READ and WAITING_WRITE packets.
+
+ * services/plugins/hgfsServer/hgfsPlugin.c,
+ services/plugins/resolutionSet/resolutionSet.c,
+ services/vmtoolsd/mainLoop.c, services/vmtoolsd/pluginMgr.c,
+ services/vmtoolsd/toolsRpc.c: load plugins even when an RPC channel cannot
+ be instantiated (i.e., when running outside of a virtual machine); this
+ allows plugins to perform actions (at load time) also when running outside
+ virtual machines (e.g., to undo some configuration done when the OS was run
+ in a VM).
+
+ * services/vmtoolsd/mainLoop.c, services/vmtoolsd/mainPosix.c,
+ services/vmtoolsd/toolsCoreInt.h: handle SIGHUP differently; instead of
+ stopping the service, just re-load the config data. This should make it
+ easier to integrate the tools service with other tools such as logrotate.
+
+ * toolbox/toolbox-cmd.c, toolbox/toolboxcmd-stat.c: remove memory info query,
+ which didn't really return useful information.
+
+ * vmware-user/copyPasteUI.cpp: if the clipboard/primary with most recent
+ timestamp has no data on it, try the other before giving up during
+ copy/paste.
+
2009-07-22 Marcelo Vanzin <mvanzin@vmware.com>
* Resync with internal trunk (2009.07.17)
+open-vm-tools 2009.08.24 changes:
+ * Remove support for Linux kernels < 2.6.9.
+
+ * The vsock now implements a new notification protocol that has better
+ performance than the previous.
+
+ * New infrastructure for sending more network config-related information
+ about the virtual machine to the host.
+
+ * Other bug fixes and minor improvements to the code.
+
open-vm-tools 2009.07.22 changes:
* Better support for dkms by means of a script to help create a dkms tree.
### Initialization
###
-TOOLS_VERSION="2009.07.22"
+TOOLS_VERSION="2009.08.24"
AC_INIT(
[open-vm-tools],
- [2009.07.22],
+ [2009.08.24],
[open-vm-tools-devel@lists.sourceforge.net])
# In order to make this configure script auto-detect situations where
if test "$with_kernel_modules" = "yes"; then
case "$os" in
linux)
+ if test "$osVersion" -lt 206009; then
+ AC_MSG_ERROR([Kernels prior to 2.6.9 are not supported in this release of open-vm-tools. Configure using --without-kernel-modules to suppress building kernel drivers.])
+ fi
if test ! -d "$LINUXDIR/kernel/"; then
AC_MSG_ERROR([$LINUXDIR/kernel does not exist])
fi
CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE"
CPPFLAGS="$CPPFLAGS -D_SVID_SOURCE"
- if test "$osVersion" -ge 202000; then
- MODULES="$MODULES vmmemctl vmxnet"
- fi
- if test "$osVersion" -ge 204000; then
- MODULES="$MODULES vmblock vmci vmhgfs vsock"
- buildHgfsmounter=yes
- fi
- if test "$osVersion" -ge 206000; then
- MODULES="$MODULES vmxnet3"
- fi
- if test "$osVersion" -ge 206006; then
- MODULES="$MODULES vmsync"
- fi
- if test "$osVersion" -ge 206008; then
- MODULES="$MODULES pvscsi"
- fi
+ MODULES="$MODULES vmmemctl vmsync vmci vsock"
+ MODULES="$MODULES vmxnet vmxnet3 pvscsi"
+ MODULES="$MODULES vmblock vmhgfs"
+ buildHgfsmounter=yes
fi
if test "$os" = "freebsd"; then
lib/guestRpc/Makefile \
lib/hgfs/Makefile \
lib/hgfsBd/Makefile \
+ lib/hgfsHelper/Makefile \
lib/hgfsServer/Makefile \
lib/hgfsServerManagerGuest/Makefile \
lib/hgfsServerPolicyGuest/Makefile \
lib/rpcOut/Makefile \
lib/rpcVmx/Makefile \
lib/SLPv2Parser/Makefile \
+ lib/slashProc/Makefile \
lib/string/Makefile \
lib/stubs/Makefile \
lib/sync/Makefile \
tests/vmrpcdbg/Makefile \
tests/testDebug/Makefile \
tests/testPlugin/Makefile \
+ tests/testVmblock/Makefile \
docs/Makefile \
docs/api/Makefile \
scripts/Makefile \
- Valid values: error, critical, warning, message, info, debug, none
- This value is required when configuring a domain.
- handler: the handler to use when logging.
- - Valid values: std, outputdebugstring (Win32-only), file
+ - Valid values: std, outputdebugstring (Win32-only), file, file+
+ (same as "file", but appends to existing log file).
- Default: "std" on Unix, "outputdebugstring" on Windows.
- data: optional configuration data for the handler.
- - Required for the "file" handler (path to log file).
+ - Required for the "file" handlers (path to log file).
Logging configuration should be under the "[logging]" group in the
application's configuration file.
SUBDIRS += guestInfo
SUBDIRS += hgfs
SUBDIRS += hgfsBd
+SUBDIRS += hgfsHelper
SUBDIRS += hgfsServer
SUBDIRS += hgfsServerManagerGuest
SUBDIRS += hgfsServerPolicyGuest
SUBDIRS += rpcIn
SUBDIRS += rpcOut
SUBDIRS += rpcVmx
+if LINUX
+ SUBDIRS += slashProc
+endif
SUBDIRS += SLPv2Parser
SUBDIRS += string
SUBDIRS += stubs
* AppUtil_SendGuestCaps --
*
* Send a list of guest capabilities to the host.
- *
+ *
* Results:
* None.
*
#error "Gtk 2.0 is required"
#endif
+#include <libgen.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "escape.h"
#include "su.h"
#if defined(linux) || defined(sun) || defined(__FreeBSD__)
-#include "vmblock.h"
+#include "vmblock_user.h"
#include "mntinfo.h"
#endif
/* We need to make this suck less. */
#if defined(linux) || defined(sun) || defined(__FreeBSD__)
-#if defined(linux)
-
-static INLINE int
-VMBLOCK_CONTROL(int fd, int op, const char *path)
-{
- return write(fd, path, op);
-}
-
-#elif defined(__FreeBSD__)
-
-static INLINE int
-VMBLOCK_CONTROL(int fd, int cmd, const char *path)
-{
- char tpath[MAXPATHLEN];
-
- if (path != NULL) {
- /*
- * FreeBSD's ioctl data parameters must be of fixed size. Guarantee a safe
- * buffer of size MAXPATHLEN by copying the user's string to one of our own.
- */
- strlcpy(tpath, path, MAXPATHLEN);
- }
-
- return ioctl(fd, cmd, tpath);
-}
-
-#elif defined(sun)
-
-static INLINE int
-VMBLOCK_CONTROL(int fd, int cmd, const char *path)
-{
- return ioctl(fd, cmd, path);
-}
-
-#endif
-
-
/*
*----------------------------------------------------------------------------
*
}
-/*
- * DnD_VmblockFuseControl --
- *
- * Controlling function for FUSE-based blocker implementation.
- * Passes requests to block and unblock file access to fuse module.
- *
- * Results:
- * 0 on success, -1 on failure.
- *
- * Notes:
- * None.
- *
- */
-
-static ssize_t
-DnD_VmblockFuseControl(int fd, // IN
- char op, // IN
- const char *path) // IN
-{
- /*
- * buffer needs room for an operation character and a string with max length
- * PATH_MAX - 1.
- */
-
- char buffer[PATH_MAX];
- size_t pathLength;
-
- pathLength = strlen(path);
- if (pathLength >= PATH_MAX) {
- errno = ENAMETOOLONG;
- return -1;
- }
-
- buffer[0] = op;
- memcpy(buffer + 1, path, pathLength);
-
- /*
- * The lseek is only to prevent the file pointer from overflowing;
- * vmblock-fuse ignores the file pointer / offset. Overflowing the file
- * pointer causes write to fail:
- * http://article.gmane.org/gmane.comp.file-systems.fuse.devel/6648
- * There's also a race condition here where many threads all calling
- * VMBLOCK_CONTROL at the same time could have all their seeks executed one
- * after the other, followed by all the writes. Again, it's not a problem
- * unless the file pointer overflows which is very unlikely with 32 bit
- * offsets and practically impossible with 64 bit offsets.
- */
-
- if (lseek(fd, 0, SEEK_SET) < 0) {
- return -1;
- }
-
- if (write(fd, buffer, pathLength + 1) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-
/*
*----------------------------------------------------------------------------
*
{
ASSERT(blockFd >= 0);
- if (DnD_VmblockFuseControl(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK,
- blockPath) != 0) {
+ if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK,
+ blockPath) != 0) {
LOG(1, ("%s: Cannot add block on %s (%s)\n",
__func__, blockPath, strerror(errno)));
return FALSE;
const char *blockedPath) // IN
{
if (blockFd >= 0) {
- if (DnD_VmblockFuseControl(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK,
- blockedPath) != 0) {
+ if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK,
+ blockedPath) != 0) {
Log("%s: Cannot delete block on %s (%s)\n",
__func__, blockedPath, strerror(errno));
return FALSE;
#if defined(_WIN32)
#include <io.h>
#define S_IXUSR 0100
+#define S_IWUSR 0200
#else
#include <unistd.h>
#endif
} else {
/* is file, delete */
if (File_Unlink(curPath) == -1) {
+#if defined(_WIN32)
+ if (File_SetFilePermissions(curPath, S_IWUSR)) {
+ if (File_Unlink(curPath) == -1) {
+ sawFileError = TRUE;
+ }
+ } else {
+ sawFileError = TRUE;
+ }
+#else
sawFileError = TRUE;
+#endif
}
}
/* Return a serious failure status if the locking code did */
switch (err) {
- case 0: // file is currently locked
+ case 0: // File is currently locked
+ case EROFS: // Attempt to lock for write on RO FS
ret = FILEIO_LOCK_FAILED;
break;
- case ENAMETOOLONG: // path is too long
+ case ENAMETOOLONG: // Path is too long
ret = FILEIO_FILE_NAME_TOO_LONG;
break;
- default: // some sort of locking error
+ case ENOENT: // No such file or directory
+ ret = FILEIO_FILE_NOT_FOUND;
+ break;
+ case EACCES: // Permissions issues
+ ret = FILEIO_NO_PERMISSION;
+ break;
+ default: // Some sort of locking error
ret = FILEIO_ERROR;
}
}
#include "unicodeOperations.h"
#include "memaligned.h"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
#include "hostinfo.h"
+#endif
+
+#if defined(__APPLE__)
+#include <sys/sysctl.h>
#define XATTR_BACKUP_REENABLED "com.vmware.backupReenabled"
#endif
-/*
+/*
* fallocate() is only supported since the glibc-2.8 and
- * linux kernel-2.6.23.Presently the glibc in our toolchain is 2.3
+ * linux kernel-2.6.23. Presently the glibc in our toolchain is 2.3.
*/
#ifdef __linux__
- #ifndef SYS_fallocate
+ #ifndef SYS_fallocate
#ifdef __i386__
- #define SYS_fallocate 324
- #elif __x86_64__
- #define SYS_fallocate 285
+ #define SYS_fallocate 324
+ #elif __x86_64__
+ #define SYS_fallocate 285
#endif
#endif
- #ifndef FALLOC_FL_KEEP_SIZE
- #define FALLOC_FL_KEEP_SIZE 1
- #endif
+ #ifndef FALLOC_FL_KEEP_SIZE
+ #define FALLOC_FL_KEEP_SIZE 1
+ #endif
#endif
static const unsigned int FileIO_SeekOrigins[] = {
Bool enabled;
int countThreshold;
int sizeThreshold;
+ int aioNumThreads;
} FilePosixOptions;
#if defined(__APPLE__)
Config_GetLong(5, "filePosix.coalesce.count");
filePosixOptions.sizeThreshold =
Config_GetLong(16*1024, "filePosix.coalesce.size");
+ filePosixOptions.aioNumThreads =
+ Config_GetLong(0, "aiomgr.numThreads");
filePosixOptions.initialized = TRUE;
}
}
ssize_t retval = pread(fd->posix, buf, leftToRead, fileOffset);
if (retval == -1) {
- if (errno == EINTR || errno == EAGAIN) {
- LOG_ONCE((LGPFX" %s got %s. Retrying\n",
- __FUNCTION__, errno == EINTR ? "EINTR" : "EAGAIN"));
+ if (errno == EINTR) {
+ LOG_ONCE((LGPFX" %s got EINTR. Retrying\n", __FUNCTION__));
NOT_TESTED_ONCE();
continue;
}
ssize_t retval = pwrite(fd->posix, buf, leftToWrite, fileOffset);
if (retval == -1) {
- if (errno == EINTR || errno == EAGAIN) {
- LOG_ONCE((LGPFX" %s got %s. Retrying\n",
- __FUNCTION__, errno == EINTR ? "EINTR" : "EAGAIN"));
+ if (errno == EINTR) {
+ LOG_ONCE((LGPFX" %s got EINTR. Retrying\n", __FUNCTION__));
NOT_TESTED_ONCE();
continue;
}
ASSERT(fd);
#if __linux__ && defined(N_PLAT_NLM)
- /* Netware doesn't have st_blocks. Just fall back to GetSize. */
+ /* Netware doesn't have st_blocks. Just fall back to GetSize. */
return FileIO_GetSize(fd);
#else
/*
* TRUE on success. Sets errno on failure.
*
* Side effects:
- * None
+ * None.
*
*----------------------------------------------------------------------
*/
if (curSize > size) {
errno = EINVAL;
return FALSE;
- }
+ }
preallocLen = size - curSize;
#ifdef __APPLE__
return fcntl(fd->posix, F_PREALLOCATE, &prealloc) != -1;
#elif __linux__
- return syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE,
- curSize, preallocLen) == 0;
+ {
+ int ret;
+
+ ret = syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE,
+ curSize, preallocLen);
+ if (ret == 0) {
+ return TRUE;
+ }
+ errno = ret;
+ return FALSE;
+ }
#endif
#else
return result;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HostSupportsPrealloc --
+ *
+ * Returns TRUE if the host OS is new enough to support F_PREALLOCATE
+ * without data loss bugs. On OSX, this has been verified fixed
+ * on 10.6 build with kern.osreleasae 10.0.0d6.
+ *
+ * Results:
+ * TRUE if the current host OS is new enough.
+ * FALSE if it is not or we can't tell because of an error.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+HostSupportsPrealloc(void)
+{
+ char curRel[32];
+ char type;
+ unsigned static const int req[] = { 10, 0, 0, 6 };
+ unsigned int cur[4], i;
+ int num;
+ size_t len = sizeof(curRel);
+ Bool ret = FALSE;
+
+ if (sysctlbyname("kern.osrelease", (void *) &curRel, &len, NULL, 0) == -1) {
+ goto exit;
+ }
+
+ curRel[31] = '\0';
+ Log("Current OS Release is %s\n", curRel);
+
+ /*
+ * Apple's osversion is in the format X.Y.Z which maps to the public
+ * OSX version 10.X-4.Y, and Z is incremented for each publicly
+ * released build. The Z part is of the form A<type>B, where a and
+ * B are version numbers and <type> is either d (devel), a (alpha),
+ * b (beta), rc, or fc. If the <type>B is missing, then its a GA build.
+ *
+ * Since we're checking for 10.0.0d6, we can just say anything without
+ * a type or with a type other than d is higher. For d, we compare
+ * the last number.
+ */
+
+ num = sscanf(curRel, "%u.%u.%u%c%u", &cur[0], &cur[1], &cur[2], &type,
+ &cur[3]);
+ if (num < 3) {
+ goto exit;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (req[i] > cur[i]) {
+ goto exit;
+ } else if (req[i] < cur[i]) {
+ ret = TRUE;
+ goto exit;
+ }
+ }
+ if (num == 5 && type == 'd') {
+ ret = req[3] <= cur[3];
+ goto exit;
+ }
+ /*
+ * If we get a type with no letter (num == 4), thats odd.
+ * Consider it mal-formatted and fail.
+ */
+ ret = num != 4;
+
+exit:
+ if (!ret && filePosixOptions.initialized &&
+ filePosixOptions.aioNumThreads == 1) {
+ ret =TRUE;
+ }
+ return ret;
+}
+
+#else
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HostSupportsPrealloc --
+ *
+ * fallocate() is supported for ext4 and xfs since 2.6.23 kernels
+ *
+ * Results:
+ * TRUE if the current host is linux and kernel is >= 2.6.23.
+ * FALSE if it is not .
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+HostSupportsPrealloc(void)
+{
+#if (defined(__linux__ ) && !defined(VMX86_SERVER))
+ if (Hostinfo_OSVersion(0) >=2 && Hostinfo_OSVersion(1) >=6 &&
+ Hostinfo_OSVersion(2) >=23) {
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
#endif
+/*
+ *----------------------------------------------------------------------------
+ *
+ * FileIO_SupportsPrealloc --
+ *
+ * Checks if the HostOS/filesystem supports preallocation.
+ *
+ * Results:
+ * TRUE if supported by the Host OS/filesystem.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+FileIO_SupportsPrealloc(const char *pathName, // IN
+ Bool fsCheck) // IN
+{
+ Bool ret = TRUE;
+
+ if (!HostSupportsPrealloc()) {
+ return FALSE;
+ }
+
+ if (!fsCheck) {
+ return ret;
+ }
+
+#if (defined( __linux__) && !defined(VMX86_SERVER))
+ {
+ struct statfs statBuf;
+ Unicode fullPath;
+
+ ret = FALSE;
+ if (!pathName) {
+ return ret;
+ }
+
+ fullPath = File_FullPath(pathName);
+ if (!fullPath) {
+ return ret;
+ }
+
+ if (Posix_Statfs(fullPath, &statBuf) == 0 &&
+ statBuf.f_type == EXT4_SUPER_MAGIC) {
+ ret = TRUE;
+ }
+ Unicode_Free(fullPath);
+ }
+#endif
+ return ret;
+}
+
if (statfsbuf.f_type == VMFS_MAGIC_NUMBER) {
int fd;
FS_FreeSpaceArgs args = { 0 };
- Unicode directory = NULL;
+ Unicode specialPath = NULL;
+
+ /*
+ * If the file exists and can be opened we're all set. If the file
+ * doesn't exist we can use the parent directory for the ioctl.
+ * However, if the file exists and can't be opened (e.g. permissions
+ * issues) a correct answer can only be returned if the target isn't a
+ * directory. If the target is a directory its parent may be a mount
+ * point - leading across a mount point to a different file system.
+ * PR 412387
+ */
- File_SplitName(fullPath, NULL, &directory, NULL);
- /* Must use an ioctl() to get free space for a VMFS file. */
ret = -1;
- fd = Posix_Open(directory, O_RDONLY, 0);
+
+ fd = Posix_Open(fullPath, O_RDONLY, 0);
+
+ if (fd == -1) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ {
+ int err = errno;
+ struct stat statbuf;
+
+ if (Posix_Stat(fullPath, &statbuf) == -1) {
+ errno = err;
+ break;
+ }
+
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
+ Warning(LGPFX" %s: directory (%s) present but inaccessible\n",
+ __func__, UTF8(fullPath));
+ errno = err;
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+
+ case ENOENT:
+ default:
+ File_SplitName(fullPath, NULL, &specialPath, NULL);
+
+ fd = Posix_Open(specialPath, O_RDONLY, 0);
+ }
+ }
+
if (fd == -1) {
Warning(LGPFX" %s: open of %s failed with: %s\n", __func__,
- UTF8(directory), Msg_ErrString());
+ (specialPath == NULL) ? UTF8(fullPath) : UTF8(specialPath),
+ Msg_ErrString());
} else {
if (ioctl(fd, IOCTLCMD_VMFS_GET_FREE_SPACE, &args) == -1) {
Warning(LGPFX" %s: ioctl on %s failed with: %s\n", __func__,
- UTF8(fullPath), Msg_ErrString());
+ (specialPath == NULL) ? UTF8(fullPath) : UTF8(specialPath),
+ Msg_ErrString());
} else {
ret = args.bytesFree;
}
+
close(fd);
}
- Unicode_Free(directory);
+ Unicode_Free(specialPath);
}
#endif
return (FileAttributes(pathName, &fileData) == 0) &&
(fileData.fileType == FILE_TYPE_CHARDEVICE);
}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * File_SupportsPrealloc --
- *
- *
- * Results:
- * TRUE if APPLE or file system type is ext2/ext3/ext4
- * FALSE if not supported by default in auto mode
- *
- * Side effects:
- * None
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-File_SupportsPrealloc(const char *file)
-{
-
-#if (defined( __linux__) && !defined(VMX86_SERVER))
- struct statfs statBuf;
- if (FileGetStats(file, FALSE, &statBuf) &&
- statBuf.f_type == EXT4_SUPER_MAGIC) {
- return TRUE;
- }
-#elif APPLE
- return TRUE
-#endif
- return FALSE;
-}
VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_BULK_SNAPSHOT,
VIX_COMMAND_CATEGORY_PRIVILEGED),
+ VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST,
+ VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+
+ VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GENERATE_NONCE,
+ VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
};
return VIX_E_INVALID_MESSAGE_HEADER;
}
+ if ((VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 & message->requestFlags) &&
+ (message->commonHeader.totalMessageLength <
+ (uint64)message->commonHeader.headerLength +
+ message->commonHeader.bodyLength +
+ message->commonHeader.credentialLength +
+ sizeof (VixMsgAuthDataV1))) {
+ return VIX_E_INVALID_MESSAGE_HEADER;
+ }
+
return VIX_OK;
} // VixMsg_ValidateRequestMsg
#include "imageUtil.h"
#include "strutil.h"
#include <paths.h>
-#include <mntent.h>
#include "vm_atomic.h"
+#include "mntinfo.h"
#include "ghIntegration.h"
#include "ghIntegrationInt.h"
#include "guest_msg_def.h"
libGuestInfo_la_SOURCES += guestInfo.c
libGuestInfo_la_SOURCES += guestInfoPosix.c
+libGuestInfo_la_CPPFLAGS =
+libGuestInfo_la_CPPFLAGS += @GLIB2_CPPFLAGS@
+
AM_CFLAGS = $(DNET_CPPFLAGS)
*
*********************************************************/
-/*
- * guestInfo.c ---
+/**
+ * @file guestInfo.c
*
- * Provides interface to information about the guest, such as hostname,
- * NIC/IP address information, etc.
+ * Library backing parts of the vm.GuestInfo VIM APIs.
*/
#include <stdlib.h>
#include <string.h>
+#if defined _WIN32
+# include <ws2tcpip.h>
+#endif
+
#include "vm_assert.h"
#include "debug.h"
#include "guestInfoInt.h"
#include "str.h"
+#include "util.h"
#include "wiper.h"
#include "xdrutil.h"
+#include "netutil.h"
+
+
+/**
+ * Helper to initialize an opaque struct member.
+ *
+ * @todo Move to xdrutil.h? Sticking point is dependency on Util_SafeMalloc.
+ */
+#define XDRUTIL_SAFESETOPAQUE(ptr, type, src, size) \
+ do { \
+ (ptr)->type##_len = (size); \
+ (ptr)->type##_val = Util_SafeMalloc((size)); \
+ memcpy((ptr)->type##_val, (src), (size)); \
+ } while (0)
/*
- * Global functions
+ * Global functions.
*/
-
+
/*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfo_GetAvailableDiskSpace -- */ /**
*
- * GuestInfo_GetAvailableDiskSpace --
+ * @brief Given a mount point, return the amount of free space on that volume.
*
- * Get the amount of disk space available on the volume the FCP (file copy/
- * paste) staging area is in. DnD and FCP use same staging area in guest.
- * But it is only called in host->guest FCP case. DnD checks guest available
- * disk space in host side (UI).
+ * Get the amount of disk space available on the volume the FCP (file copy/
+ * paste) staging area is in. DnD and FCP use same staging area in guest.
+ * But it is only called in host->guest FCP case. DnD checks guest available
+ * disk space in host side (UI).
*
- * Results:
- * Available disk space size if succeed, otherwise 0.
+ * @param[in] pathName Mount point to examine.
*
- * Side effects:
- * None.
+ * @todo This doesn't belong in lib/guestInfo.
*
- *-----------------------------------------------------------------------------
+ * @return Bytes free on success, 0 on failure.
+ *
+ ******************************************************************************
*/
uint64
}
-
/*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfo_GetFqdn -- */ /**
*
- * GuestInfo_GetFqdn --
+ * @brief Returns the guest's hostname (aka fully qualified domain name, FQDN).
*
- * Returns the guest's hostname.
+ * @param[in] outBufLen Size of outBuf.
+ * @param[out] outBuf Output buffer.
*
- * Results:
- * Returns TRUE on success, FALSE on failure.
- * Returns the guest's fully qualified domain name in fqdn.
+ * @retval TRUE Success. Hostname written to @a outBuf.
+ * @retval FALSE Failure.
*
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
+ ******************************************************************************
*/
Bool
-GuestInfo_GetFqdn(int outBufLen, // IN: sizeof fqdn
- char fqdn[]) // OUT: buffer to store hostname
+GuestInfo_GetFqdn(int outBufLen, // IN
+ char fqdn[]) // OUT
{
return GuestInfoGetFqdn(outBufLen, fqdn);
}
/*
- *-----------------------------------------------------------------------------
- *
- * GuestInfo_GetNicInfo --
+ ******************************************************************************
+ * GuestInfo_GetNicInfo -- */ /**
*
- * Returns the guest's hostname.
+ * @brief Returns guest networking configuration (and some runtime state).
*
- * Results:
- * Return MAC addresses of all the NICs in the guest and their
- * corresponding IP addresses.
+ * @param[out] nicInfo Will point to a newly allocated NicInfo.
*
- * Returns TRUE on success and FALSE on failure.
- * Return MAC addresses of all NICs and their corresponding IPs.
+ * @note
+ * Caller is responsible for freeing @a nicInfo with GuestInfo_FreeNicInfo.
*
- * Side effects:
- * Memory is allocated for each NIC, as well as IP addresses of all NICs
- * on successful return.
+ * @retval TRUE Success. @a nicInfo now points to a populated NicInfoV3.
+ * @retval FALSE Failure.
*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
*/
Bool
-GuestInfo_GetNicInfo(GuestNicList *nicInfo) // OUT: storage for NIC information
+GuestInfo_GetNicInfo(NicInfoV3 **nicInfo) // OUT
{
- return GuestInfoGetNicInfo(nicInfo);
+ Bool retval = FALSE;
+
+ *nicInfo = Util_SafeCalloc(1, sizeof (struct NicInfoV3));
+
+ retval = GuestInfoGetNicInfo(*nicInfo);
+ if (!retval) {
+ free(*nicInfo);
+ *nicInfo = NULL;
+ }
+
+ return retval;
}
/*
- *----------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfo_FreeNicInfo -- */ /**
*
- * GuestInfo_GetDiskInfo --
+ * @brief Frees a NicInfoV3 structure and all memory it points to.
*
- * Get disk information.
+ * @param[in] nicInfo Pointer to NicInfoV3 container.
*
- * Results:
- * TRUE if successful, FALSE otherwise.
+ * @sa GuestInfo_GetNicInfo
*
- * Side effects:
- * Allocates memory for di->partitionList.
+ ******************************************************************************
+ */
+
+void
+GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo) // IN
+{
+ if (nicInfo != NULL) {
+ VMX_XDR_FREE(xdr_NicInfoV3, nicInfo);
+ free(nicInfo);
+ }
+}
+
+
+/*
+ ******************************************************************************
+ * GuestInfo_GetDiskInfo -- */ /**
*
- *----------------------------------------------------------------------
+ * @brief Get disk information.
+ *
+ * @param[in,out] di DiskInfo container.
+ *
+ * @note
+ * Allocates memory for di->partitionList.
+ *
+ * @retval TRUE Success.
+ * @retval FALSE Failure.
+ *
+ ******************************************************************************
*/
Bool
GuestInfo_GetDiskInfo(PGuestDiskInfo di) // IN/OUT
{
- return GuestInfoGetDiskInfo(di);
+ WiperPartition_List pl;
+ DblLnkLst_Links *curr;
+ unsigned int partCount = 0;
+ uint64 freeBytes = 0;
+ uint64 totalBytes = 0;
+ unsigned int partNameSize = 0;
+ Bool success = FALSE;
+
+ ASSERT(di);
+ partNameSize = sizeof (di->partitionList)[0].name;
+ di->numEntries = 0;
+ di->partitionList = NULL;
+
+ /* Get partition list. */
+ if (!WiperPartition_Open(&pl)) {
+ Debug("GetDiskInfo: ERROR: could not get partition list\n");
+ return FALSE;
+ }
+
+ DblLnkLst_ForEach(curr, &pl.link) {
+ WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link);
+
+ if (part->type != PARTITION_UNSUPPORTED) {
+ PPartitionEntry newPartitionList;
+ PPartitionEntry partEntry;
+ unsigned char *error;
+
+ error = WiperSinglePartition_GetSpace(part, &freeBytes, &totalBytes);
+ if (strlen(error)) {
+ Debug("GetDiskInfo: ERROR: could not get space for partition %s: %s\n",
+ part->mountPoint, error);
+ goto out;
+ }
+
+ if (strlen(part->mountPoint) + 1 > partNameSize) {
+ Debug("GetDiskInfo: ERROR: Partition name buffer too small\n");
+ goto out;
+ }
+
+ newPartitionList = realloc(di->partitionList,
+ (partCount + 1) * sizeof *di->partitionList);
+ if (newPartitionList == NULL) {
+ Debug("GetDiskInfo: ERROR: could not allocate partition list.\n");
+ goto out;
+ }
+
+ partEntry = &newPartitionList[partCount++];
+ Str_Strcpy(partEntry->name, part->mountPoint, partNameSize);
+ partEntry->freeBytes = freeBytes;
+ partEntry->totalBytes = totalBytes;
+
+ di->partitionList = newPartitionList;
+ }
+ }
+
+ di->numEntries = partCount;
+ success = TRUE;
+
+out:
+ WiperPartition_Close(&pl);
+ return success;
}
-/**
- * Add a NIC into the given list. The macAddress of the new GuestNic is
- * initialized with the given address.
+/*
+ * Private library functions.
+ */
+
+
+/*
+ ******************************************************************************
+ * GuestInfoAddNicEntry -- */ /**
+ *
+ * @brief GuestNicV3 constructor.
*
* @param[in,out] nicInfo List of NICs.
* @param[in] macAddress MAC address of new NIC.
+ * @param[in] dnsInfo Per-NIC DNS config state.
+ *
+ * @note The returned GuestNic will take ownership of @a dnsInfo. The caller
+ * must not free it directly.
*
- * @return The new NIC, or NULL on failure.
+ * @return Pointer to the new NIC.
+ *
+ ******************************************************************************
*/
-GuestNic *
-GuestInfoAddNicEntry(GuestNicList *nicInfo, // IN/OUT
- const char macAddress[NICINFO_MAC_LEN]) // IN
+GuestNicV3 *
+GuestInfoAddNicEntry(NicInfoV3 *nicInfo, // IN/OUT
+ const char macAddress[NICINFO_MAC_LEN], // IN
+ DnsConfigInfo *dnsInfo) // IN
{
- GuestNic *newNic;
+ GuestNicV3 *newNic;
newNic = XDRUTIL_ARRAYAPPEND(nicInfo, nics, 1);
- if (newNic != NULL) {
- Str_Strcpy(newNic->macAddress, macAddress, sizeof newNic->macAddress);
- }
+ ASSERT_MEM_ALLOC(newNic);
+
+ newNic->macAddress = Util_SafeStrdup(macAddress);
+ newNic->dnsConfigInfo = dnsInfo;
return newNic;
}
-/**
- * Add an IP address entry into the GuestNic.
+/*
+ ******************************************************************************
+ * GuestInfoAddIpAddress -- */ /**
+ *
+ * @brief Add an IP address entry into the GuestNic.
*
* @param[in,out] nic The NIC information.
- * @param[in] ipAddr The new IP address to add.
- * @param[in] af_type Interface type.
+ * @param[in] sockAddr The new IP address.
+ * @param[in] pfxLen Prefix length (use 0 if unknown).
+ * @param[in] origin Address's origin. (Optional.)
+ * @param[in] status Address's status. (Optional.)
*
* @return Newly allocated IP address struct, NULL on failure.
+ *
+ ******************************************************************************
*/
-VmIpAddress *
-GuestInfoAddIpAddress(GuestNic *nic, // IN/OUT
- const char *ipAddr, // IN
- const uint32 af_type) // IN
+IpAddressEntry *
+GuestInfoAddIpAddress(GuestNicV3 *nic, // IN/OUT
+ const struct sockaddr *sockAddr, // IN
+ InetAddressPrefixLength pfxLen, // IN
+ const IpAddressOrigin *origin, // IN
+ const IpAddressStatus *status) // IN
{
- VmIpAddress *ip;
+ IpAddressEntry *ip;
+
+ ASSERT(sockAddr);
ip = XDRUTIL_ARRAYAPPEND(nic, ips, 1);
- if (ip != NULL) {
- Str_Strcpy(ip->ipAddress, ipAddr, sizeof ip->ipAddress);
- ip->addressFamily = af_type;
+ ASSERT_MEM_ALLOC(ip);
+
+ ASSERT_ON_COMPILE(sizeof *origin == sizeof *ip->ipAddressOrigin);
+ ASSERT_ON_COMPILE(sizeof *status == sizeof *ip->ipAddressStatus);
+
+ switch (sockAddr->sa_family) {
+ case AF_INET:
+ {
+ static const IpAddressStatus defaultStatus = IAS_PREFERRED;
+
+ GuestInfoSockaddrToTypedIpAddress(sockAddr, &ip->ipAddressAddr);
+
+ ip->ipAddressPrefixLength = pfxLen;
+ ip->ipAddressOrigin = origin ? Util_DupeThis(origin, sizeof *origin) : NULL;
+ ip->ipAddressStatus = status ? Util_DupeThis(status, sizeof *status) :
+ Util_DupeThis(&defaultStatus, sizeof defaultStatus);
+ }
+ break;
+ case AF_INET6:
+ {
+ static const IpAddressStatus defaultStatus = IAS_UNKNOWN;
+
+ GuestInfoSockaddrToTypedIpAddress(sockAddr, &ip->ipAddressAddr);
+
+ ip->ipAddressPrefixLength = pfxLen;
+ ip->ipAddressOrigin = origin ? Util_DupeThis(origin, sizeof *origin) : NULL;
+ ip->ipAddressStatus = status ? Util_DupeThis(status, sizeof *status) :
+ Util_DupeThis(&defaultStatus, sizeof defaultStatus);
+ }
+ break;
+ default:
+ NOT_REACHED();
}
return ip;
}
-/**
- * Add an IPv4 netmask / IPv6 prefix length to the IpAddress in ASCII form.
+/*
+ ******************************************************************************
+ * GuestInfoSockaddrToTypedIpAddress -- */ /**
+ *
+ * @brief Converts a <tt>struct sockaddr</tt> to a @c TypedIpAddress.
*
- * If convertToMask is true the 'n' bits subnet mask is converted
- * to an ASCII string as a hexadecimal number (0xffffff00) and
- * added to the IPAddressEntry. (Applies to IPv4 only.)
+ * @param[in] sa Source @c sockaddr.
+ * @param[out] typedIp Destination @c TypedIpAddress.
*
- * If convertToMask is false the value is added to the IPAddressEntry in
- * string form - ie '24'.
+ * @warning Caller is responsible for making sure source is AF_INET or
+ * AF_INET6.
*
- * @param[in,out] ipAddressEntry The IP address info.
- * @param[in] subnetMaskBits The mask.
- * @param[in] convertToMask See above.
+ ******************************************************************************
*/
void
-GuestInfoAddSubnetMask(VmIpAddress *ipAddressEntry, // IN/OUT
- const uint32 subnetMaskBits, // IN
- Bool convertToMask) // IN
+GuestInfoSockaddrToTypedIpAddress(const struct sockaddr *sa, // IN
+ TypedIpAddress *typedIp) // OUT
{
- int i;
- uint32 subnetMask = 0;
-
- ASSERT(ipAddressEntry);
- /*
- * It's an error to set convertToMask on an IPv6 address.
- */
- ASSERT(ipAddressEntry->addressFamily == INFO_IP_ADDRESS_FAMILY_IPV4 ||
- !convertToMask);
-
- if (convertToMask && (subnetMaskBits <= 32)) {
- /*
- * Convert the subnet mask from a number of bits (ie. '24') to
- * hexadecimal notation such 0xffffff00
- */
- for (i = 0; i < subnetMaskBits; i++) {
- subnetMask |= (0x80000000 >> i);
- }
-
- // Convert the hexadecimal value to a string and add to the IpAddress Entry
- Str_Sprintf(ipAddressEntry->subnetMask,
- sizeof ipAddressEntry->subnetMask,
- "0x%x", subnetMask);
- } else {
- Str_Sprintf(ipAddressEntry->subnetMask,
- sizeof ipAddressEntry->subnetMask,
- "%d", subnetMaskBits);
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ typedIp->ipAddressAddrType = IAT_IPV4;
+ XDRUTIL_SAFESETOPAQUE(&typedIp->ipAddressAddr, InetAddress,
+ &sin->sin_addr.s_addr,
+ sizeof sin->sin_addr.s_addr);
+ break;
+ case AF_INET6:
+ typedIp->ipAddressAddrType = IAT_IPV6;
+ XDRUTIL_SAFESETOPAQUE(&typedIp->ipAddressAddr, InetAddress,
+ &sin6->sin6_addr.s6_addr,
+ sizeof sin6->sin6_addr.s6_addr);
+ break;
+ default:
+ NOT_REACHED();
}
- return;
}
-/**
- * Get disk information.
+#if defined linux || defined _WIN32
+/*
+ ******************************************************************************
+ * GuestInfoGetNicInfoIfIndex -- */ /**
+ *
+ * @brief Given a local interface's index, find its corresponding location in the
+ * NicInfoV3 @c nics vector.
+ *
+ * @param[in] nicInfo NIC container.
+ * @param[in] ifIndex Device to search for.
+ * @param[out] nicifIndex Array offset, if found.
*
- * @param[out] di Where to store the disk information.
+ * @retval TRUE Device found.
+ * @retval FALSE Device not found.
*
- * @return TRUE if successful, FALSE otherwise.
+ ******************************************************************************
*/
Bool
-GuestInfoGetDiskInfo(PGuestDiskInfo di)
+GuestInfoGetNicInfoIfIndex(NicInfoV3 *nicInfo, // IN
+ int ifIndex, // IN
+ int *nicIfIndex) // OUT
{
- int i = 0;
- WiperPartition_List *pl = NULL;
- unsigned int partCount = 0;
- uint64 freeBytes = 0;
- uint64 totalBytes = 0;
- WiperPartition nextPartition;
- unsigned int partNameSize = 0;
- Bool success = FALSE;
-
- ASSERT(di);
- partNameSize = sizeof (di->partitionList)[0].name;
- di->numEntries = 0;
- di->partitionList = NULL;
-
- /* Get partition list. */
- pl = WiperPartition_Open();
- if (pl == NULL) {
- Debug("GetDiskInfo: ERROR: could not get partition list\n");
+ char hwAddrString[NICINFO_MAC_LEN];
+ unsigned char hwAddr[16];
+ IanaIfType ifType;
+ Bool ret = FALSE;
+ u_int i;
+
+ ASSERT(nicInfo);
+ ASSERT(nicIfIndex);
+
+ if (NetUtil_GetHardwareAddress(ifIndex, hwAddr, sizeof hwAddr,
+ &ifType) != 6 ||
+ ifType != IANA_IFTYPE_ETHERNETCSMACD) {
return FALSE;
}
- for (i = 0; i < pl->size; i++) {
- nextPartition = pl->partitions[i];
- if (!strlen(nextPartition.comment)) {
- PPartitionEntry newPartitionList;
- unsigned char *error;
- error = WiperSinglePartition_GetSpace(&nextPartition, &freeBytes, &totalBytes);
- if (strlen(error)) {
- Debug("GetDiskInfo: ERROR: could not get space for partition %s: %s\n",
- nextPartition.mountPoint, error);
- goto out;
- }
-
- if (strlen(nextPartition.mountPoint) + 1 > partNameSize) {
- Debug("GetDiskInfo: ERROR: Partition name buffer too small\n");
- goto out;
- }
-
- newPartitionList = realloc(di->partitionList,
- (partCount + 1) * sizeof *di->partitionList);
- if (newPartitionList == NULL) {
- Debug("GetDiskInfo: ERROR: could not allocate partition list.\n");
- goto out;
- }
- di->partitionList = newPartitionList;
-
- Str_Strcpy((di->partitionList)[partCount].name, nextPartition.mountPoint,
- partNameSize);
- (di->partitionList)[partCount].freeBytes = freeBytes;
- (di->partitionList)[partCount].totalBytes = totalBytes;
- partCount++;
+ Str_Sprintf(hwAddrString, sizeof hwAddrString,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ hwAddr[0], hwAddr[1], hwAddr[2],
+ hwAddr[3], hwAddr[4], hwAddr[5]);
+
+ XDRUTIL_FOREACH(i, nicInfo, nics) {
+ GuestNicV3 *nic = XDRUTIL_GETITEM(nicInfo, nics, i);
+ if (!strcasecmp(nic->macAddress, hwAddrString)) {
+ *nicIfIndex = i;
+ ret = TRUE;
+ break;
}
}
- di->numEntries = partCount;
- success = TRUE;
-out:
- WiperPartition_Close(pl);
- return success;
+ return ret;
}
+#endif // if defined linux || defined _WIN32
+
+
+/*
+ * XXX
+ */
+
+
+/**
+ * Return a copy of arbitrary memory.
+ *
+ * @param[in] source Source address.
+ * @param[in] sourceSize Number of bytes to allocate, copy.
+ *
+ * @return Pointer to newly allocated memory.
+ *
+ * @todo Determine if I'm duplicating functionality.
+ * @todo Move this to bora/lib/util or whatever.
+ */
+void *
+Util_DupeThis(const void *source,
+ size_t sourceSize)
+{
+ void *dest;
+
+ ASSERT(source);
+
+ dest = Util_SafeMalloc(sourceSize);
+ memcpy(dest, source, sourceSize);
+
+ return dest;
+}
#include "guestInfo.h"
#include "guestrpc/nicinfo.h"
+#if defined __FreeBSD__ || defined __sun__ || defined __APPLE__
+# include <sys/socket.h> // struct sockaddr
+#endif
+
Bool GuestInfoGetFqdn(int outBufLen, char fqdn[]);
-Bool GuestInfoGetNicInfo(GuestNicList *nicInfo);
+Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo);
void GuestInfoMemset(void * mem, int value, unsigned int size);
Bool GuestInfoGetDiskInfo(PGuestDiskInfo di);
Bool GuestInfo_PerfMon(struct GuestMemInfo *vmStats);
-GuestNic *GuestInfoAddNicEntry(GuestNicList *nicInfo,
- const char macAddress[NICINFO_MAC_LEN]);
-VmIpAddress *GuestInfoAddIpAddress(GuestNic *nic,
- const char *ipAddr,
- const uint32 af_type);
-void GuestInfoAddSubnetMask(VmIpAddress *ipAddressEntry,
- const uint32 subnetMaskBits,
- Bool convertToMask);
-
+GuestNicV3 *GuestInfoAddNicEntry(NicInfoV3 *nicInfo, // IN/OUT
+ const char macAddress[NICINFO_MAC_LEN], // IN
+ DnsConfigInfo *dnsInfo); // IN
+
+IpAddressEntry *GuestInfoAddIpAddress(GuestNicV3 *nic, // IN/OUT
+ const struct sockaddr *sockAddr, // IN
+ InetAddressPrefixLength pfxLen, // IN
+ const IpAddressOrigin *origin, // IN
+ const IpAddressStatus *status); // IN
+#if defined linux || defined _WIN32
+Bool GuestInfoGetNicInfoIfIndex(NicInfoV3 *nicInfo, // IN
+ int ifIndex, // IN
+ int *nicIfIndex); // OUT
+#endif // if defined linux || defined _WIN32
+void GuestInfoSockaddrToTypedIpAddress(const struct sockaddr *sa, // IN
+ TypedIpAddress *typedIp); // OUT
+
+/* XXX */
+void * Util_DupeThis(const void *source, size_t sourceSize);
#endif
/*********************************************************
- * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ * Copyright (C) 2005 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
*
*********************************************************/
-
-/*
- * guestInfoPosix.c --
- *
- * Routines to get guest information. These are invoked by guestInfoServer
- * which writes this information into Vmdb.
+/**
+ * @file guestInfoPosix.c
*
+ * Contains POSIX-specific bits of GuestInfo collector library.
*/
-#ifndef VMX86_DEVEL
-
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <glib.h>
#include <fcntl.h>
#ifdef sun
# include <sys/systeminfo.h>
# include <dnet.h>
# endif
#endif
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#ifdef __linux__
+# include <net/if.h>
+#endif
+
+
+/*
+ * resolver(3) and IPv6:
+ *
+ * The ISC BIND resolver included various IPv6 implementations over time, but
+ * unfortunately the ISC hadn't bumped __RES accordingly. (__RES is -supposed-
+ * to behave as a version datestamp for the resolver interface.) Similarly
+ * the GNU C Library forked resolv.h and made modifications of their own, also
+ * without changing __RES.
+ *
+ * glibc 2.1.92 included a patch which provides IPv6 name server support by
+ * embedding in6_addr pointers in _res._u._ext. Since I only care about major
+ * and minor numbers, though, I'm going to condition this impl. on glibc 2.2.
+ *
+ * ISC, OTOH, provided accessing IPv6 servers via a res_getservers API.
+ * TTBOMK, this went public with BIND 8.3.0. Unfortunately __RES wasn't
+ * bumped for this release, so instead I'm going to assume that appearance with
+ * that release of a new macro, RES_F_DNS0ERR, implies this API is available.
+ * (For internal builds, we'll know instantly when a build breaks. The down-
+ * side is that this could cause some trouble for Open VM Tools users. ,_,)
+ *
+ * resolv.h version IPv6 API __RES
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * glibc 2.2+ _ext 19991006
+ * BIND 8.3.0 getservers 19991006
+ * BIND 8.3.4+ getservers 20030124(+?)
+ *
+ * To distinguish between the variants where __RES == 19991006, I'll
+ * discriminate on the existence of new macros included with the appropriate
+ * version.
+ */
+
+#if defined __GLIBC__
+# if __GLIBC_PREREQ(2,2)
+# define RESOLVER_IPV6_EXT
+# endif // __GLIBC_PREREQ(2,2)
+#elif (__RES > 19991006 || (__RES == 19991006 && defined RES_F_EDNS0ERR))
+# define RESOLVER_IPV6_GETSERVERS
+#endif // if defined __GLIBC__
+
+
#include "util.h"
#include "sys/utsname.h"
#include "sys/ioctl.h"
#include "guest_os.h"
#include "guestApp.h"
#include "guestInfo.h"
+#include "xdrutil.h"
+#include "slashProc.h"
+#include "netutil.h"
+#include "file.h"
/*
- *-----------------------------------------------------------------------------
- *
- * GuestInfoGetFqdn--
- *
- * Return the guest's fully qualified domain name.
- * This is just a thin wrapper around gethostname.
- *
- * Return value:
- * Returns TRUE on success and FALSE on failure.
- * Returns the guest's fully qualified domain name.
+ * Local functions
+ */
+
+
+#ifndef NO_DNET
+static void RecordNetworkAddress(GuestNicV3 *nic, const struct addr *addr);
+static int ReadInterfaceDetails(const struct intf_entry *entry, void *arg);
+static Bool RecordResolverInfo(NicInfoV3 *nicInfo);
+static void RecordResolverNS(DnsConfigInfo *dnsConfigInfo);
+static Bool RecordRoutingInfo(NicInfoV3 *nicInfo);
+#endif
+
+
+/*
+ ******************************************************************************
+ * GuestInfoGetFqdn -- */ /**
*
- * Side effects:
- * None
+ * @copydoc GuestInfo_GetFqdn
*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
*/
Bool
}
-#ifndef NO_DNET
/*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfoGetNicInfo -- */ /**
*
- * RecordNetworkAddress --
+ * @copydoc GuestInfo_GetNicInfo
*
- * Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores it
- * as part of a GuestNic structure.
+ ******************************************************************************
+ */
+
+Bool
+GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
+{
+#ifndef NO_DNET
+ intf_t *intf;
+
+ /* Get a handle to read the network interface configuration details. */
+ if ((intf = intf_open()) == NULL) {
+ Debug("GuestInfo: Error, failed NULL result from intf_open()\n");
+ return FALSE;
+ }
+
+ if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
+ intf_close(intf);
+ Debug("GuestInfo: Error, negative result from intf_loop\n");
+ return FALSE;
+ }
+
+ intf_close(intf);
+
+ if (!RecordResolverInfo(nicInfo)) {
+ return FALSE;
+ }
+
+ if (!RecordRoutingInfo(nicInfo)) {
+ return FALSE;
+ }
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+
+/*
+ * Local functions
+ */
+
+
+#ifndef NO_DNET
+/*
+ ******************************************************************************
+ * RecordNetworkAddress -- */ /**
*
- * Results:
- * If addr is IPv4 or IPv6, it will be appended to the GuestNic's list of
- * IP addresses.
+ * @brief Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores
+ * it as part of a GuestNicV3 structure.
*
- * Side effects:
- * None.
+ * @param[in] nic Operand NIC.
+ * @param[in] addr dnet(3) address.
*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
*/
static void
-RecordNetworkAddress(GuestNic *nic, // IN: operand NIC
+RecordNetworkAddress(GuestNicV3 *nic, // IN: operand NIC
const struct addr *addr) // IN: dnet(3) address to process
{
- char ipAddress[NICINFO_MAX_IP_LEN];
- VmIpAddress *ip = NULL;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr *)&ss;
- switch (addr->addr_type) {
- case ADDR_TYPE_IP:
- /*
- * GuestNicInfo clients expect IPv4 addresses and netmasks to be stored
- * as strings in separate fields. As such, we'll use ip_ntop instead of
- * addr_ntop to get a string without the netmask bits.
- */
- ip_ntop(&addr->addr_ip, ipAddress, sizeof ipAddress);
- ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV4);
- if (ip) {
- GuestInfoAddSubnetMask(ip, addr->addr_bits, TRUE);
- }
- break;
- case ADDR_TYPE_IP6:
- ip6_ntop(&addr->addr_ip6, ipAddress, sizeof ipAddress);
- ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV6);
- if (ip) {
- GuestInfoAddSubnetMask(ip, addr->addr_bits, FALSE);
- }
- break;
- default:
- Debug("%s: Unknown address type: %hu\n", __func__, addr->addr_type);
- break;
- }
+ memset(&ss, 0, sizeof ss);
+ addr_ntos(addr, sa);
+ GuestInfoAddIpAddress(nic, sa, addr->addr_bits, NULL, NULL);
}
/*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * ReadInterfaceDetails -- */ /**
*
- * ReadInterfaceDetails --
+ * @brief Callback function called by libdnet when iterating over all the NICs
+ * on the host.
*
- * Callback function called by libdnet when iterating over all the
- * NICs on the host.
+ * @param[in] entry Current interface entry.
+ * @param[in] arg Pointer to NicInfoV3 container.
*
- * Return value:
- * Returns 0 on success and -1 on failure.
- * Adds the MAC addresses of all NICs and their corresponding IPs.
+ * @note New GuestNicV3 structures are added to the NicInfoV3 structure.
*
- * Side effects:
- * Memory is allocated for each NIC, as well as IP addresses of all NICs
- * on successful return.
+ * @retval 0 Success.
+ * @retval -1 Failure.
*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
*/
-int
+static int
ReadInterfaceDetails(const struct intf_entry *entry, // IN: current interface entry
void *arg) // IN: Pointer to the GuestNicList
{
int i;
- GuestNicList *nicInfo = arg;
+ NicInfoV3 *nicInfo = arg;
- if ((entry->intf_type & INTF_TYPE_ETH) == INTF_TYPE_ETH) {
- GuestNic *nic;
+ ASSERT(entry);
+ ASSERT(arg);
+
+ if (entry->intf_type == INTF_TYPE_ETH) {
+ GuestNicV3 *nic = NULL;
char macAddress[NICINFO_MAC_LEN];
Str_Sprintf(macAddress, sizeof macAddress, "%s",
addr_ntoa(&entry->intf_link_addr));
- nic = GuestInfoAddNicEntry(nicInfo, macAddress);
-
- if (nic == NULL) {
- return -1;
- }
+ nic = GuestInfoAddNicEntry(nicInfo, macAddress, NULL);
+ ASSERT_MEM_ALLOC(nic);
/* Record the "primary" address. */
if (entry->intf_addr.addr_type == ADDR_TYPE_IP ||
return 0;
}
-#endif
/*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * RecordResolverInfo -- */ /**
*
- * GuestInfoGetNicInfo --
+ * @brief Query resolver(3), mapping settings to DnsConfigInfo.
*
- * Return MAC addresses of all the NICs in the guest and their
- * corresponding IP addresses.
+ * @param[out] nicInfo NicInfoV3 container.
*
- * Return value:
- * Returns TRUE on success and FALSE on failure.
- * Return MAC addresses of all NICs and their corresponding IPs.
+ * @retval TRUE Values collected, attached to @a nicInfo.
+ * @retval FALSE Something went wrong. @a nicInfo is unharmed.
*
- * Side effects:
- * Memory is allocated for each NIC, as well as IP addresses of all NICs
- * on successful return.
+ ******************************************************************************
+ */
+
+static Bool
+RecordResolverInfo(NicInfoV3 *nicInfo) // OUT
+{
+ DnsConfigInfo *dnsConfigInfo = NULL;
+ char namebuf[DNSINFO_MAX_ADDRLEN + 1];
+ char **s;
+
+ if (res_init() == -1) {
+ return FALSE;
+ }
+
+ dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo);
+
+ /*
+ * Copy in the host name.
+ */
+ if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) {
+ goto fail;
+ }
+ dnsConfigInfo->hostName =
+ Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName);
+ *dnsConfigInfo->hostName = Util_SafeStrdup(namebuf);
+
+ /*
+ * Repeat with the domain name.
+ */
+ dnsConfigInfo->domainName =
+ Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName);
+ *dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname);
+
+ /*
+ * Name servers.
+ */
+ RecordResolverNS(dnsConfigInfo);
+
+ /*
+ * Search suffixes.
+ */
+ for (s = _res.dnsrch; *s; s++) {
+ DnsHostname *suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1);
+ ASSERT_MEM_ALLOC(suffix);
+ *suffix = Util_SafeStrdup(*s);
+ }
+
+ /*
+ * "Commit" dnsConfigInfo to nicInfo.
+ */
+ nicInfo->dnsConfigInfo = dnsConfigInfo;
+
+ return TRUE;
+
+fail:
+ VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo);
+ free(dnsConfigInfo);
+ return FALSE;
+}
+
+
+/*
+ ******************************************************************************
+ * RecordResolverNS -- */ /**
+ *
+ * @brief Copies name servers used by resolver(3) to @a dnsConfigInfo.
*
- *-----------------------------------------------------------------------------
+ * @param[out] dnsConfigInfo Destination DnsConfigInfo container.
+ *
+ ******************************************************************************
*/
-Bool
-GuestInfoGetNicInfo(GuestNicList *nicInfo) // OUT
+static void
+RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
{
-#ifndef NO_DNET
- intf_t *intf;
+ int i;
- memset(nicInfo, 0, sizeof *nicInfo);
+#if defined RESOLVER_IPV6_GETSERVERS
+ {
+ union res_sockaddr_union *ns;
+ ns = Util_SafeCalloc(_res.nscount, sizeof *ns);
+ if (res_getservers(&_res, ns, _res.nscount) != _res.nscount) {
+ Warning("%s: res_getservers failed.\n", __func__);
+ return;
+ }
+ for (i = 0; i < _res.nscount; i++) {
+ struct sockaddr *sa = (struct sockaddr *)&ns[i];
+ if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
+ TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
+ ASSERT_MEM_ALLOC(ip);
+ GuestInfoSockaddrToTypedIpAddress(sa, ip);
+ }
+ }
+ }
+#else // if defined RESOLVER_IPV6_GETSERVERS
+ {
+ /*
+ * Name servers (IPv4).
+ */
+ for (i = 0; i < MAXNS; i++) {
+ struct sockaddr_in *sin = &_res.nsaddr_list[i];
+ if (sin->sin_family == AF_INET) {
+ TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
+ ASSERT_MEM_ALLOC(ip);
+ GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin, ip);
+ }
+ }
+# if defined RESOLVER_IPV6_EXT
+ /*
+ * Name servers (IPv6).
+ */
+ for (i = 0; i < MAXNS; i++) {
+ struct sockaddr_in6 *sin6 = _res._u._ext.nsaddrs[i];
+ if (sin6) {
+ TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
+ ASSERT_MEM_ALLOC(ip);
+ GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
+ }
+ }
+# endif // if defined RESOLVER_IPV6_EXT
+ }
+#endif // if !defined RESOLVER_IPV6_GETSERVERS
+}
- /* Get a handle to read the network interface configuration details. */
- if ((intf = intf_open()) == NULL) {
- Debug("GuestInfo: Error, failed NULL result from intf_open()\n");
+
+#if defined __linux__
+/*
+ ******************************************************************************
+ * RecordRoutingInfoIPv4 -- */ /**
+ *
+ * @brief Query the IPv4 routing subsystem and pack up contents
+ * (struct rtentry) into InetCidrRouteEntries.
+ *
+ * @param[out] nicInfo NicInfoV3 container.
+ *
+ * @note Do not call this routine without first populating @a nicInfo 's NIC
+ * list.
+ *
+ * @retval TRUE Values collected, attached to @a nicInfo.
+ * @retval FALSE Something went wrong. @a nicInfo is unharmed.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
+{
+ GPtrArray *routes = NULL;
+ guint i;
+ Bool ret = FALSE;
+
+ if ((routes = SlashProcNet_GetRoute()) == NULL) {
return FALSE;
}
- if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
- intf_close(intf);
- Debug("GuestInfo: Error, negative result from intf_loop\n");
+ for (i = 0; i < routes->len; i++) {
+ struct rtentry *rtentry;
+ struct sockaddr_in *sin_dst;
+ struct sockaddr_in *sin_gateway;
+ struct sockaddr_in *sin_genmask;
+ InetCidrRouteEntry *icre;
+ uint32_t ifIndex;
+
+ rtentry = g_ptr_array_index(routes, i);
+
+ if ((rtentry->rt_flags & RTF_UP) == 0 ||
+ !GuestInfoGetNicInfoIfIndex(nicInfo,
+ if_nametoindex(rtentry->rt_dev),
+ &ifIndex)) {
+ continue;
+ }
+
+ icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
+ ASSERT_MEM_ALLOC(icre);
+
+ sin_dst = (struct sockaddr_in *)&rtentry->rt_dst;
+ sin_gateway = (struct sockaddr_in *)&rtentry->rt_gateway;
+ sin_genmask = (struct sockaddr_in *)&rtentry->rt_genmask;
+
+ GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_dst,
+ &icre->inetCidrRouteDest);
+
+ addr_stob((struct sockaddr *)sin_genmask,
+ (uint16_t *)&icre->inetCidrRoutePfxLen);
+
+ /*
+ * Gateways are optional (ex: one can bind a route to an interface w/o
+ * specifying a next hop address).
+ */
+ if (rtentry->rt_flags & RTF_GATEWAY) {
+ TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
+ GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_gateway, ip);
+ icre->inetCidrRouteNextHop = ip;
+ }
+
+ /*
+ * Interface, metric.
+ */
+ icre->inetCidrRouteIfIndex = ifIndex;
+ icre->inetCidrRouteMetric = rtentry->rt_metric;
+ }
+
+ ret = TRUE;
+
+ SlashProcNet_FreeRoute(routes);
+ return ret;
+}
+
+
+/*
+ ******************************************************************************
+ * RecordRoutingInfoIPv6 -- */ /**
+ *
+ * @brief Query the IPv6 routing subsystem and pack up contents
+ * (struct in6_rtmsg) into InetCidrRouteEntries.
+ *
+ * @param[out] nicInfo NicInfoV3 container.
+ *
+ * @note Do not call this routine without first populating @a nicInfo 's NIC
+ * list.
+ *
+ * @retval TRUE Values collected, attached to @a nicInfo.
+ * @retval FALSE Something went wrong. @a nicInfo is unharmed.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
+{
+ GPtrArray *routes = NULL;
+ guint i;
+ Bool ret = FALSE;
+
+ if ((routes = SlashProcNet_GetRoute6()) == NULL) {
return FALSE;
}
- intf_close(intf);
+ for (i = 0; i < routes->len; i++) {
+ struct sockaddr_storage ss;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
+ struct in6_rtmsg *in6_rtmsg;
+ InetCidrRouteEntry *icre;
+ uint32_t ifIndex = -1;
+
+ in6_rtmsg = g_ptr_array_index(routes, i);
+
+ if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 ||
+ !GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
+ &ifIndex)) {
+ continue;
+ }
+
+ icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
+ ASSERT_MEM_ALLOC(icre);
+
+ /*
+ * Destination.
+ */
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr = in6_rtmsg->rtmsg_dst;
+ GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6,
+ &icre->inetCidrRouteDest);
+
+ icre->inetCidrRoutePfxLen = in6_rtmsg->rtmsg_dst_len;
+
+ /*
+ * Next hop.
+ */
+ if (in6_rtmsg->rtmsg_flags & RTF_GATEWAY) {
+ TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
+ sin6->sin6_addr = in6_rtmsg->rtmsg_gateway;
+ GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
+ icre->inetCidrRouteNextHop = ip;
+ }
+
+ /*
+ * Interface, metric.
+ */
+ icre->inetCidrRouteIfIndex = ifIndex;
+ icre->inetCidrRouteMetric = in6_rtmsg->rtmsg_metric;
+ }
+
+ ret = TRUE;
+
+ SlashProcNet_FreeRoute6(routes);
+ return ret;
+}
+
+
+/*
+ ******************************************************************************
+ * RecordRoutingInfo -- */ /**
+ *
+ * @brief Query the routing subsystem and pack up contents into
+ * InetCidrRouteEntries.
+ *
+ * @param[out] nicInfo NicInfoV3 container.
+ *
+ * @note Do not call this routine without first populating @a nicInfo 's NIC
+ * list.
+ *
+ * @retval TRUE Values collected, attached to @a nicInfo.
+ * @retval FALSE Something went wrong.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+RecordRoutingInfo(NicInfoV3 *nicInfo)
+{
+ Bool ret = TRUE;
+
+ if (File_Exists("/proc/net/route") && !RecordRoutingInfoIPv4(nicInfo)) {
+ Warning("%s: Unable to collect IPv4 routing table.\n", __func__);
+ ret = FALSE;
+ }
+
+ if (File_Exists("/proc/net/ipv6_route") && !RecordRoutingInfoIPv6(nicInfo)) {
+ Warning("%s: Unable to collect IPv6 routing table.\n", __func__);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+#else // if defined __linux__
+static Bool
+RecordRoutingInfo(NicInfoV3 *nicInfo)
+{
return TRUE;
-#else
- return FALSE;
-#endif
}
+#endif // else
+
+#endif // ifndef NO_DNET
*/
#define GHI_HANDLERS_ACTIONURI_MAX_PATH 1040
+/*
+ * Maximum length for a guest app hash value (usually much shorter).
+ */
+#define GHI_EXEC_INFO_HASH_MAX_LEN 1024
+
#endif // ifndef _GHI_COMMON_DEFINES_H_
#include "ghiCommonDefines.h"
-#define GHI_EXEC_INFO_HASH_MAX_LEN 1024
-
/*
* Enumerates the different versions of the messages.
*/
* version one is legacy code we can't change.
*/
enum NicInfoVersion {
- NIC_INFO_V2 = 2
+ NIC_INFO_V1 = 1, /* XXX Not represented here. */
+ NIC_INFO_V2 = 2,
+ NIC_INFO_V3 = 3
};
/*
/* MAC Addresses are "AA:BB:CC:DD:EE:FF" = 18 bytes. */
const NICINFO_MAC_LEN = 18;
+/*
+ * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType.
+ */
+enum NicInfoAddrType {
+ NICINFO_ADDR_IPV4 = 0,
+ NICINFO_ADDR_IPV6 = 1
+};
+
struct VmIpAddress {
- /*
- * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType.
- */
- uint32 addressFamily;
+ NicInfoAddrType addressFamily;
Bool dhcpEnabled;
char ipAddress[NICINFO_MAX_IP_LEN];
/*
struct GuestNic nics<NICINFO_MAX_NICS>;
};
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * NIC Info version 3.
+ *
+ * V3 adds routing, DNS, and WINS information to the NIC list.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+
+/*
+ * IP v4 and v6 addressing.
+ *
+ * These types were redefined primarily to allow much more efficient wire
+ * encoding.
+ */
+
+
+/*
+ * See RFC 4001, InetAddress.
+ */
+const INET_ADDRESS_MAX_LEN = 255;
+typedef opaque InetAddress<INET_ADDRESS_MAX_LEN>;
+
+
+/*
+ * See RFC 4001, InetAddressType.
+ */
+enum InetAddressType {
+ IAT_UNKNOWN = 0,
+ IAT_IPV4 = 1,
+ IAT_IPV6 = 2,
+ IAT_IPV4Z = 3,
+ IAT_IPV6Z = 4,
+ IAT_DNS = 16
+};
+
+
+/*
+ * See RFC 4001, InetAddressPrefixLength.
+ */
+typedef unsigned int InetAddressPrefixLength;
+
+
+/*
+ * See RFC 4293, IpAddressOriginTC.
+ */
+enum IpAddressOrigin {
+ IAO_OTHER = 1,
+ IAO_MANUAL = 2,
+ IAO_DHCP = 4,
+ IAO_LINKLAYER = 5,
+ IAO_RANDOM = 6
+};
+
+
+/*
+ * See RFC 4293, IpAddressStatusTC.
+ *
+ * "The status of an address. Most of the states correspond to states
+ * from the IPv6 Stateless Address Autoconfiguration protocol.
+ * ...
+ * "In the absence of other information, an IPv4 address is always
+ * preferred(1)."
+ */
+enum IpAddressStatus {
+ IAS_PREFERRED = 1,
+ IAS_DEPRECATED = 2,
+ IAS_INVALID = 3,
+ IAS_INACCESSIBLE = 4,
+ IAS_UNKNOWN = 5,
+ IAS_TENTATIVE = 6,
+ IAS_DUPLICATE = 7,
+ IAS_OPTIMISTIC = 8
+};
+
+
+/*
+ * Convenient type for lists of addresses.
+ */
+struct TypedIpAddress {
+ InetAddressType ipAddressAddrType;
+ InetAddress ipAddressAddr;
+};
+
+
+/*
+ * See RFC 4293, IpAddressEntry.
+ *
+ * "An address mapping for a particular interface."
+ *
+ * We deviate from the RFC in a few places:
+ * - The prefix length is listed explicitly here rather than reference
+ * a separate prefix table.
+ * - Interface indices aren't included as this structure is dependent
+ * upon/encapsulated by a GuestNicV3 structure.
+ */
+struct IpAddressEntry {
+ TypedIpAddress ipAddressAddr;
+ InetAddressPrefixLength ipAddressPrefixLength;
+ IpAddressOrigin *ipAddressOrigin;
+ IpAddressStatus *ipAddressStatus;
+};
+
+
+/*
+ * Runtime DNS resolver state.
+ */
+
+
+/*
+ * Quoth RFC 2181 §11 (Name Syntax):
+ * "The length of any one label is limited to between 1 and 63 octets. A
+ * full domain name is limited to 255 octets (including the separators)."
+ */
+const DNSINFO_MAX_ADDRLEN = 255;
+typedef string DnsHostname<DNSINFO_MAX_ADDRLEN>;
+
+
+/*
+ * Arbitrary limits.
+ */
+const DNSINFO_MAX_SUFFIXES = 10;
+const DNSINFO_MAX_SERVERS = 16;
+
+struct DnsConfigInfo {
+ DnsHostname *hostName;
+ DnsHostname *domainName;
+ TypedIpAddress serverList<DNSINFO_MAX_SERVERS>;
+ DnsHostname searchSuffixes<DNSINFO_MAX_SUFFIXES>;
+};
+
+
+/*
+ * Runtime WINS resolver state. Addresses are assumed to be IPv4 only.
+ */
+
+struct WinsConfigInfo {
+ TypedIpAddress primary;
+ TypedIpAddress secondary;
+};
+
+
+/*
+ * Runtime routing tables.
+ */
+
+
+/*
+ * Arbitrary limit.
+ */
+const NICINFO_MAX_ROUTES = 100;
+
+
+/*
+ * See RFC 4292 for details.
+ */
+enum InetCidrRouteType {
+ ICRT_OTHER = 1,
+ ICRT_REJECT = 2,
+ ICRT_LOCAL = 3,
+ ICRT_REMOTE = 4
+};
+
+struct InetCidrRouteEntry {
+ TypedIpAddress inetCidrRouteDest;
+ InetAddressPrefixLength inetCidrRoutePfxLen;
+
+ /*
+ * Next hop isn't mandatory.
+ */
+ TypedIpAddress *inetCidrRouteNextHop;
+
+ /*
+ * inetCidrRouteProto is omitted as we're concerned only with static/
+ * netmgmt routes.
+ */
+
+ /* This is an array index into GuestNicListV3::nics. */
+ uint32 inetCidrRouteIfIndex;
+
+ /* XXX Do we really need this? */
+ InetCidrRouteType inetCidrRouteType;
+
+ /* -1 == unused. */
+ uint32 inetCidrRouteMetric;
+};
+
+
+/*
+ * Fun with DHCP
+ */
+
+const DHCP_MAX_CONFIG_SIZE = 16384;
+
+struct DhcpConfigInfo {
+ bool enabled;
+ string dhcpSettings<DHCP_MAX_CONFIG_SIZE>;
+};
+
+
+/*
+ * Top-level containers.
+ */
+
+
+/*
+ * Describes a single NIC.
+ */
+
+struct GuestNicV3 {
+ string macAddress<NICINFO_MAC_LEN>;
+ IpAddressEntry ips<NICINFO_MAX_IPS>;
+ DnsConfigInfo *dnsConfigInfo;
+ WinsConfigInfo *winsConfigInfo;
+ DhcpConfigInfo *dhcpConfigInfov4;
+ DhcpConfigInfo *dhcpConfigInfov6;
+};
+
+
+/*
+ * Attempts to model general network state.
+ */
+
+struct NicInfoV3 {
+ GuestNicV3 nics<NICINFO_MAX_NICS>;
+ InetCidrRouteEntry routes<NICINFO_MAX_ROUTES>;
+ DnsConfigInfo *dnsConfigInfo;
+ WinsConfigInfo *winsConfigInfo;
+ DhcpConfigInfo *dhcpConfigInfov4;
+ DhcpConfigInfo *dhcpConfigInfov6;
+};
+
+
/*
* This defines the protocol for a "nic info" message. The union allows
* us to create new versions of the protocol later by creating new values
union GuestNicProto switch (NicInfoVersion ver) {
case NIC_INFO_V2:
struct GuestNicList *nicsV2;
+case NIC_INFO_V3:
+ struct NicInfoV3 *nicInfoV3;
};
-
char *requestPacket) // IN: Buffer (obtained from HgfsBd_GetBuf)
{
char const *replyPacket; // Buffer returned by HgfsBd_Dispatch
- size_t packetSize;
- int error;
+ size_t replyLen;
+ Bool success;
/*
* Send a bogus (empty) request to the VMX. If hgfs is disabled on
* (it will be an error packet because our request was malformed,
* but we just discard it anyway).
*/
- packetSize = 0;
- error = HgfsBd_Dispatch(out,
- requestPacket,
- &packetSize,
- &replyPacket);
- if (error < 0) {
- return FALSE;
+ success = RpcOut_send(out, requestPacket - HGFS_CLIENT_CMD_LEN,
+ HGFS_CLIENT_CMD_LEN,
+ &replyPacket, &replyLen);
+ if (success == TRUE) {
+ ASSERT(replyLen <= HGFS_LARGE_PACKET_MAX);
}
- return TRUE;
+ return success;
}
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libHgfsHelper.la
+
+libHgfsHelper_la_SOURCES =
+libHgfsHelper_la_SOURCES += hgfsHelperPosix.c
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * hgfsHelperPosix.c --
+ *
+ * Provides a posix helper library for guest applications to access
+ * the HGFS file system.
+ *
+ */
+
+#if !defined __linux__ && !defined __FreeBSD__ && !defined sun && !defined __APPLE__
+# error This file should not be compiled
+#endif
+
+#include "vmware.h"
+#include "debug.h"
+
+#include "hgfsHelper.h"
+
+#if defined __linux__
+#define HGFSHLPR_DEFAULT_MOUNT_PATH "/mnt/hgfs"
+#elif defined sun
+#define HGFSHLPR_DEFAULT_MOUNT_PATH "/hgfs"
+#elif defined __APPLE__
+#define HGFSHLPR_DEFAULT_MOUNT_PATH "/Volumes/Shared Folders"
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsHlpr_QuerySharesDefaultRootPath --
+ *
+ * Queries the driver for its share's root paths.
+ * Currently only one is expected to be supported
+ * and returned, although later versions may not.
+ * E.g. "/mnt/hgfs" is the root path to
+ * the HGFS shares.
+ *
+ * Results:
+ * TRUE always.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsHlpr_QuerySharesDefaultRootPath(Unicode *hgfsRootPath)
+{
+#if defined __FreeBSD__
+ return FALSE;
+#else
+ ASSERT(hgfsRootPath != NULL);
+
+ *hgfsRootPath = Unicode_AllocWithUTF8(HGFSHLPR_DEFAULT_MOUNT_PATH);
+
+ Debug("%s: HGFS shares root path name \"%s\"\n",
+ __FUNCTION__, UTF8(*hgfsRootPath));
+
+ return TRUE;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsHlpr_FreeSharesRootPath --
+ *
+ * Frees the share's root paths previously returned
+ * to the caller from the HgfsHlpr_QuerySharesRootPath.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsHlpr_FreeSharesRootPath(Unicode hgfsRootPath)
+{
+ Unicode_Free(hgfsRootPath);
+}
* NOTE: This flag is only meant to be used while testing. This should
* _always_ be undefined when checking code in.
*/
-
#if 0
#define HGFS_ASSERT_CLIENT(op) \
do { \
* NOTE: This flag is only meant to be used while testing. This should
* _always_ be undefined when checking code in.
*/
-
#if 0
#define HGFS_ASSERT_MINIMUM_OP(op) \
do { \
/* Local functions. */
-static Bool HgfsServerCheckPathPrefix(const char *path,
- const char *share,
- size_t shareLen);
static void HgfsInvalidateSessionObjects(DblLnkLst_Links *shares,
HgfsSessionInfo *session);
static Bool HgfsAddToCacheInternal(HgfsHandle handle,
static HgfsSearch *HgfsAddNewSearch(char const *utf8Dir,
DirectorySearchType type,
char const *utf8ShareName,
+ char const *rootDir,
HgfsSessionInfo *session);
static void HgfsDumpAllSearches(HgfsSessionInfo *session);
static void HgfsDumpAllNodes(HgfsSessionInfo *session);
Bool
HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle
HgfsSessionInfo *session, // IN: Session info
- fileDesc *fd) // OUT: OS handle (file descriptor)
+ fileDesc *fd, // OUT: OS handle (file descriptor)
+ void **fileCtx) // OUT: OS file context
{
Bool found = FALSE;
HgfsFileNode *fileNode = NULL;
}
*fd = fileNode->fileDesc;
+ if (fileCtx) {
+ *fileCtx = fileNode->fileCtx;
+ }
found = TRUE;
exit:
HgfsSessionInfo *session,// IN: Session info
char **fileName, // OUT: UTF8 file name
size_t *fileNameSize) // OUT: UTF8 file name size
+{
+ Bool unused1, unused2;
+ return HgfsHandle2FileNameMode(handle, session, &unused1, &unused2, fileName,
+ fileNameSize);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsHandle2FileNameMode --
+ *
+ * Given an OS handle/fd, return file's hgfs name and permissions
+ * associated with the corresponding shared folder.
+ *
+ * Results:
+ * TRUE if the node was found.
+ * FALSE otherwise.
+ *
+ * Side effects:
+ * Allocates memory and makes a copy of the file name.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsHandle2FileNameMode(HgfsHandle handle, // IN: Hgfs file handle
+ HgfsSessionInfo *session,// IN: Session info
+ Bool *readPermissions, // OUT: shared folder permissions
+ Bool *writePermissions, // OUT: shared folder permissions
+ char **fileName, // OUT: UTF8 file name
+ size_t *fileNameSize) // OUT: UTF8 file name size
{
Bool found = FALSE;
HgfsFileNode *existingFileNode = NULL;
if (name == NULL) {
goto exit_unlock;
}
+ *readPermissions = existingFileNode->shareInfo.readPermissions;
+ *writePermissions = existingFileNode->shareInfo.writePermissions;
nameSize = existingFileNode->utf8NameLen;
memcpy(name, existingFileNode->utf8Name, nameSize);
name[nameSize] = '\0';
SyncMutex_Lock(&session->nodeArrayLock);
for (i = 0; i < session->numNodes; i++) {
HgfsFileNode *existingFileNode = &session->nodeArray[i];
-
if ((existingFileNode->state == FILENODE_STATE_IN_USE_CACHED) &&
(existingFileNode->serverLock != HGFS_LOCK_NONE) &&
(!stricmp(existingFileNode->utf8Name, utf8Name))) {
copy->flags = original->flags;
copy->state = original->state;
copy->handle = original->handle;
+ copy->fileCtx = original->fileCtx;
found = TRUE;
exit:
Bool
HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle
HgfsSessionInfo *session, // IN: Session info
- fileDesc fd) // OUT: OS handle (file desc)
+ fileDesc fd, // IN: OS handle (file desc)
+ void *fileCtx) // IN: OS file context
{
HgfsFileNode *node;
Bool updated = FALSE;
}
node->fileDesc = fd;
+ node->fileCtx = fileCtx;
updated = TRUE;
exit:
* if the file does not exist, which it is okay, as creating
* a new file is not allowed and should be failed.
*/
-
*flags = HGFS_OPEN;
}
}
* This has to be unsigned and with maximum bit length. This is
* required to take care of "negative" differences as well.
*/
-
uintptr_t ptrDiff;
if (DOLOG(4)) {
/*
* Rebase the links of all file nodes
*/
-
for (i = 0; i < session->numNodes; i++) {
HgfsServerRebase(newMem[i].links.prev, DblLnkLst_Links)
HgfsServerRebase(newMem[i].links.next, DblLnkLst_Links)
newMem[i].state = FILENODE_STATE_UNUSED;
newMem[i].utf8Name = NULL;
newMem[i].utf8NameLen = 0;
+ newMem[i].fileCtx = NULL;
/* Append at the end of the list */
DblLnkLst_LinkLast(&session->nodeFreeList, &newMem[i].links);
}
node->utf8Name = NULL;
node->state = FILENODE_STATE_UNUSED;
+ ASSERT(node->fileCtx == NULL);
+ node->fileCtx = NULL;
/* Prepend at the beginning of the list */
DblLnkLst_LinkFirst(&session->nodeFreeList, &node->links);
HgfsSessionInfo *session) // IN: session info
{
HgfsFileNode *newNode;
+ char* rootDir;
ASSERT(openInfo);
ASSERT(localId);
/* Set new node's fields */
if (!HgfsServerGetOpenMode(openInfo, &newNode->mode)) {
HgfsRemoveFileNode(newNode, session);
-
return NULL;
}
* Save a copy of the share name so we can look up its
* access mode at various times over the node's lifecycle.
*/
-
newNode->shareName = malloc(shareNameLen + 1);
if (newNode->shareName == NULL) {
LOG(4, ("%s: out of memory\n", __FUNCTION__));
HgfsRemoveFileNode(newNode, session);
-
return NULL;
}
memcpy(newNode->shareName, shareName, shareNameLen);
if (newNode->utf8Name == NULL) {
LOG(4, ("%s: out of memory\n", __FUNCTION__));
HgfsRemoveFileNode(newNode, session);
-
return NULL;
}
memcpy(newNode->utf8Name, openInfo->utf8Name, newNode->utf8NameLen);
newNode->utf8Name[newNode->utf8NameLen] = '\0';
+ newNode->shareInfo.rootDirLen = strlen(openInfo->shareInfo.rootDir);
+ rootDir = malloc(newNode->shareInfo.rootDirLen + 1);
+ if (rootDir == NULL) {
+ LOG(4, ("HgfsAddNewFileNode: out of memory\n"));
+ HgfsRemoveFileNode(newNode, session);
+ return NULL;
+ }
+ memcpy(rootDir, openInfo->shareInfo.rootDir, newNode->shareInfo.rootDirLen);
+ rootDir[newNode->shareInfo.rootDirLen] = '\0';
+ newNode->shareInfo.rootDir = rootDir;
+
newNode->handle = HgfsServerGetNextHandleCounter();
newNode->localId = *localId;
newNode->fileDesc = fileDesc;
newNode->serverLock = openInfo->acquiredLock;
newNode->state = FILENODE_STATE_IN_USE_NOT_CACHED;
+ newNode->shareInfo.readPermissions = openInfo->shareInfo.readPermissions;
+ newNode->shareInfo.writePermissions = openInfo->shareInfo.writePermissions;
LOG(4, ("%s: got new node, handle %u\n", __FUNCTION__,
HgfsFileNode2Handle(newNode)));
-
return newNode;
}
if (HgfsIsCachedInternal(handle, session)) {
ASSERT((node = HgfsHandle2FileNode(handle, session)) &&
node->state == FILENODE_STATE_IN_USE_CACHED);
-
return TRUE;
}
* Instead, we'll just await the lobotomization of the node cache to
* really fix this.
*/
-
- if (HgfsCloseFile(node->fileDesc)) {
+ if (HgfsCloseFile(node->fileDesc, node->fileCtx)) {
LOG(4, ("%s: Could not close fd %u\n", __FUNCTION__, node->fileDesc));
return FALSE;
}
+ node->fileCtx = NULL;
/*
* If we have just removed the node then the number of used nodes better
/*
* Move this node to the end of the list.
*/
-
DblLnkLst_Unlink1(&node->links);
DblLnkLst_LinkLast(&session->nodeCachedList, &node->links);
newMem[i].utf8DirLen = 0;
newMem[i].utf8ShareName = NULL;
newMem[i].utf8ShareNameLen = 0;
+ newMem[i].shareInfo.rootDir = NULL;
+ newMem[i].shareInfo.rootDirLen = 0;
newMem[i].dents = NULL;
newMem[i].numDents = 0;
HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in
DirectorySearchType type, // IN: What kind of search is this?
char const *utf8ShareName, // IN: Share name containing the directory
+ char const *rootDir, // IN: Root directory for the share
HgfsSessionInfo *session) // IN: Session info
{
HgfsSearch *newSearch;
return NULL;
}
+ newSearch->shareInfo.rootDirLen = strlen(rootDir);
+ newSearch->shareInfo.rootDir = strdup(rootDir);
+ if (newSearch->shareInfo.rootDir == NULL) {
+ HgfsRemoveSearchInternal(newSearch, session);
+ return NULL;
+ }
+
LOG(4, ("%s: got new search, handle %u\n", __FUNCTION__,
HgfsSearch2SearchHandle(newSearch)));
-
return newSearch;
}
free(search->utf8Dir);
free(search->utf8ShareName);
+ free((char*)search->shareInfo.rootDir);
/* Prepend at the beginning of the list */
DblLnkLst_LinkFirst(&session->searchFreeList, &search->links);
* at the top of hgfsServerInt.h, you'll see that on Windows we only
* define d_reclen and d_name, as those are the only fields we need.
*/
-
dent->d_reclen = originalDent->d_reclen;
memcpy(dent->d_name, originalDent->d_name, nameLen);
dent->d_name[nameLen] = 0;
{ HgfsServerQueryVolume, HGFS_SIZEOF_OP(HgfsRequestQueryVolumeV3) },
{ HgfsServerSymlinkCreate, HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3) },
{ HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange) },
+ { HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3) },
};
}
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsServerCheckPathPrefix --
- *
- * Given a path and a Hgfs host share path, check to see if the given
- * share is a prefix of the path.
- *
- * Results:
- * TRUE if share is a prefix of path.
- * FALSE otherwise.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsServerCheckPathPrefix(const char *path, // IN: Path to check
- const char *share, // IN: Prefix of path
- size_t shareLen) // IN: Length of share
-{
- ASSERT(path);
- ASSERT(share);
-
- /* First make sure that share is a prefix of path. */
- if (strncmp(path, share, shareLen) != 0) {
- return FALSE;
- }
-
- /*
- * Special case. The root share on Linux or Apple ("/") will not be followed
- * by a second path separator. In this case, no additional checks besides the
- * initial prefix check are needed. Just return success.
- */
-
- if (shareLen == 1 && *share == DIRSEPC) {
- return TRUE;
- }
-
- /*
- * Now check to prevent false positives. In particular, consider the case
- * where we have two shares: shareName and shareName1.
- * Given the path /shareName1/test, the above check will allow through both
- * shareName and shareName1. Check to make sure that the given share is
- * a full path component.
- */
-
- if (*(path + shareLen) == DIRSEPC) {
- return TRUE;
- }
-
- if (*(path + shareLen) == '\0') {
- return TRUE;
- }
-
- return FALSE;
-}
-
-
/*
*-----------------------------------------------------------------------------
*
* Iterate over each node, skipping those that are unused. For each node,
* if its filename is no longer within a share, remove it.
*/
-
for (i = 0; i < session->numNodes; i++) {
HgfsHandle handle;
DblLnkLst_Links *l;
share = DblLnkLst_Container(l, HgfsSharedFolder, links);
ASSERT(share);
- if (HgfsServerCheckPathPrefix(session->nodeArray[i].utf8Name,
- share->path,
- share->pathLen)) {
+ if (strcmp(session->nodeArray[i].shareInfo.rootDir, share->path) == 0) {
LOG(4, ("%s: Node is still valid\n", __FUNCTION__));
break;
}
* Iterate over each search, skipping those that are on the free list. For
* each search, if its base name is no longer within a share, remove it.
*/
-
for (i = 0; i < session->numSearches; i++) {
HgfsHandle handle;
DblLnkLst_Links *l;
share = DblLnkLst_Container(l, HgfsSharedFolder, links);
ASSERT(share);
- if (HgfsServerCheckPathPrefix(session->searchArray[i].utf8Dir,
- share->path, share->pathLen)) {
+ if (strcmp(session->searchArray[i].shareInfo.rootDir, share->path) == 0) {
LOG(4, ("%s: Search is still valid\n", __FUNCTION__));
break;
}
* delimiter on copy. Allow 0 length drives so that hidden feature "" can
* work.
*/
-
if (pathLength < 0 || pathLength >= sizeof p.mountPoint) {
LOG(4, ("%s: could not get the volume name\n", __FUNCTION__));
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerGetAccess --
+ * HgfsServerGetShareInfo --
*
- * Test a name for access permission and construct its local name
- * if access is allowed. The name returned is allocated and must be
- * freed by the caller.
+ * Construct local name based on the crossplatform CPName for the file.
+ * The name returned is allocated and must be freed by the caller.
*
* outLen can be NULL, in which case the length is not returned.
*
* Results:
- * A status code indicating either success (access is allowed) or
+ * A status code indicating either success (correspondent share exists) or
* a failure status.
*
* Side effects:
*/
HgfsNameStatus
-HgfsServerGetAccess(char *cpName, // IN: Cross-platform filename to check
- size_t cpNameSize, // IN: Size of name cpName
- HgfsOpenMode mode, // IN: Requested access mode
- uint32 caseFlags, // IN: Case-sensitivity flags
- char **bufOut, // OUT: File name in local fs
- size_t *outLen) // OUT: Length of name out
+HgfsServerGetShareInfo(char *cpName, // IN: Cross-platform filename to check
+ size_t cpNameSize, // IN: Size of name cpName
+ uint32 caseFlags, // IN: Case-sensitivity flags
+ HgfsShareInfo *shareInfo,// OUT: properties of the shared folder
+ char **bufOut, // OUT: File name in local fs
+ size_t *outLen) // OUT: Length of name out
{
HgfsNameStatus nameStatus;
- char const *sharePath;
char const *inEnd;
char *next;
char *myBufOut;
char *convertedMyBufOut;
char *out;
size_t outSize;
- size_t sharePathLen; /* Length of share's path */
size_t myBufOutLen;
size_t convertedMyBufOutLen;
int len;
}
/* Check permission on the share and get the share path */
- nameStatus = HgfsServerPolicy_GetSharePath(cpName, len, mode, &sharePathLen,
- &sharePath);
+ nameStatus = HgfsServerPolicy_ProcessCPName(cpName,
+ len,
+ &shareInfo->readPermissions,
+ &shareInfo->writePermissions,
+ &shareInfo->rootDir);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: No such share (%s) or access denied\n", __FUNCTION__,
- cpName));
-
+ LOG(4, ("%s: No such share (%s)\n", __FUNCTION__, cpName));
return nameStatus;
}
+ shareInfo->rootDirLen = strlen(shareInfo->rootDir);
/* Get the config options. */
nameStatus = HgfsServerPolicy_GetShareOptions(cpName, len, &shareOptions);
/*
* See if we are dealing with a "root" share or regular share
*/
-
- if (strlen(sharePath) == 0) {
+ if (shareInfo->rootDirLen == 0) {
size_t prefixLen;
/*
* buffer (for Win32) or simply get the prefix for root (for
* linux).
*/
-
tempSize = sizeof tempBuf;
tempPtr = tempBuf;
nameStatus = CPName_ConvertFromRoot((char const **) &cpName,
/*
* This is a regular share. Append the path to the out buffer.
*/
-
- if (outSize < sharePathLen + 1) {
+ if (outSize < shareInfo->rootDirLen + 1) {
LOG(4, ("%s: share path too big\n", __FUNCTION__));
nameStatus = HGFS_NAME_STATUS_TOO_LONG;
goto error;
}
- memcpy(out, sharePath, sharePathLen + 1);
- out += sharePathLen;
- outSize -= sharePathLen;
+ memcpy(out, shareInfo->rootDir, shareInfo->rootDirLen + 1);
+ out += shareInfo->rootDirLen;
+ outSize -= shareInfo->rootDirLen;
}
/* Convert the rest of the input name (if any) to a local name */
if (!HgfsServerPolicy_IsShareOptionSet(shareOptions,
HGFS_SHARE_HOST_DEFAULT_CASE) &&
HgfsServerCaseConversionRequired()) {
- nameStatus = HgfsServerConvertCase(sharePath, sharePathLen, myBufOut,
- myBufOutLen, caseFlags,
+ nameStatus = HgfsServerConvertCase(shareInfo->rootDir, shareInfo->rootDirLen,
+ myBufOut, myBufOutLen, caseFlags,
&convertedMyBufOut,
&convertedMyBufOutLen);
* We should use the resolved file path for further file system
* operations, instead of using the one passed from the client.
*/
-
- nameStatus = HgfsServerHasSymlink(myBufOut, myBufOutLen, sharePath,
- sharePathLen);
+ nameStatus = HgfsServerHasSymlink(myBufOut, myBufOutLen, shareInfo->rootDir,
+ shareInfo->rootDirLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: parent path failed to be resolved: %d\n", __FUNCTION__,
- nameStatus));
+ LOG(4, ("%s: parent path failed to be resolved: %d\n",
+ __FUNCTION__, nameStatus));
goto error;
}
}
*
* This function assumes that CPName_GetComponent() will always succeed
* with a size greater than 0, so it must ONLY be called after a call to
- * HgfsServerGetAccess() that returns HGFS_NAME_STATUS_COMPLETE.
+ * HgfsServerGetShareInfo() that returns HGFS_NAME_STATUS_COMPLETE.
*
* Results:
* True if it is a shared folder only, otherwise false
* our purposes, so we use PATH_MAX as a reasonable upper bound on the
* length of the name.
*/
-
maxLen = PATH_MAX;
#else
maxLen = sizeof pDirEntry->d_name;
HgfsInternalStatus
HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search
size_t baseDirLen, // IN: Length of directory
- DirectorySearchType type, // IN: Kind of search
char const *shareName, // IN: Share name containing the directory
- HgfsSessionInfo *session, // IN: Share name containing the directory
+ char const *rootDir, // IN: Shared folder root directory
+ HgfsSessionInfo *session, // IN: Session info
HgfsHandle *handle) // OUT: Search handle
{
HgfsSearch *search = NULL;
ASSERT(baseDir);
ASSERT(handle);
- ASSERT(type == DIRECTORY_SEARCH_TYPE_DIR);
ASSERT(shareName);
SyncMutex_Lock(&session->searchArrayLock);
- search = HgfsAddNewSearch(baseDir, type, shareName, session);
+ search = HgfsAddNewSearch(baseDir, DIRECTORY_SEARCH_TYPE_DIR, shareName,
+ rootDir, session);
if (!search) {
LOG(4, ("%s: failed to get new search\n", __FUNCTION__));
status = HGFS_INTERNAL_STATUS_ERROR;
ASSERT(handle);
SyncMutex_Lock(&session->searchArrayLock);
- search = HgfsAddNewSearch("", type, "", session);
+ search = HgfsAddNewSearch("", type, "", "", session);
if (!search) {
LOG(4, ("%s: failed to get new search\n", __FUNCTION__));
status = HGFS_INTERNAL_STATUS_ERROR;
ASSERT(session);
ASSERT(session->numCachedOpenNodes > 0);
- /* Remove the first item from the list that does not have a server lock. */
+ /*
+ * Remove the first item from the list that does not have a server lock,
+ * file context or is open in sequential mode.
+ */
while (!found) {
lruNode = DblLnkLst_Container(session->nodeCachedList.next,
HgfsFileNode, links);
ASSERT(lruNode->state == FILENODE_STATE_IN_USE_CACHED);
- if (lruNode->serverLock != HGFS_LOCK_NONE) {
- /* Move this node with the server lock to the beginning of the list. */
+ if (lruNode->serverLock != HGFS_LOCK_NONE || lruNode->fileCtx != NULL
+ || (lruNode->flags & HGFS_FILE_NODE_SEQUENTIAL_FL) != 0) {
+ /*
+ * Move this node with the server lock to the beginning of the list.
+ * Also, prevent files opened in HGFS_FILE_NODE_SEQUENTIAL_FL mode
+ * from being closed. -- On some platforms, this mode does not
+ * allow files to be closed/re-opened (eg: When restoring a file
+ * into a Windows guest you cannot use BackupWrite, then close and
+ * re-open the file and continue to use BackupWrite.
+ */
DblLnkLst_Unlink1(&lruNode->links);
DblLnkLst_LinkLast(&session->nodeCachedList, &lruNode->links);
} else {
found = TRUE;
}
}
- handle = HgfsFileNode2Handle(lruNode);
- if (!HgfsRemoveFromCacheInternal(handle, session)) {
- LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__));
-
+ if (found) {
+ handle = HgfsFileNode2Handle(lruNode);
+ if (!HgfsRemoveFromCacheInternal(handle, session)) {
+ LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__));
+ return FALSE;
+ }
+ } else {
+ LOG(4, ("%s: Could not find a node to remove from cache.\n", __FUNCTION__));
return FALSE;
}
* requestV3->fileName.length is user-provided, so this test must be
* carefully written to prevent wraparounds.
*/
-
if (requestV3->fileName.length > extra) {
/* The input packet is smaller than the request. */
* garbage, but it's simpler to copy everything now and check the
* valid bits before reading later.
*/
-
openInfo->mask = requestV3->mask;
openInfo->mode = requestV3->mode;
openInfo->cpName = requestV3->fileName.name;
openInfo->cpNameSize = requestV3->fileName.length;
- openInfo->caseFlags = requestV3->fileName.caseType;
+ openInfo->caseFlags = requestV3->fileName.caseType;
openInfo->flags = requestV3->flags;
openInfo->specialPerms = requestV3->specialPerms;
openInfo->ownerPerms = requestV3->ownerPerms;
* requestV2->fileName.length is user-provided, so this test must be
* carefully written to prevent wraparounds.
*/
-
if (requestV2->fileName.length > extra) {
/* The input packet is smaller than the request. */
return FALSE;
* If we've been asked to reuse a handle, we don't need to look at, let
* alone test the filename or its length.
*/
-
if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
*file = requestV3->fileName.fid;
*cpName = NULL;
* request->fileName.length is user-provided, so this test must be
* carefully written to prevent wraparounds.
*/
-
if (requestV3->fileName.length > extra) {
/* The input packet is smaller than the request */
}
*cpName = requestV3->fileName.name;
*cpNameSize = requestV3->fileName.length;
- *caseFlags = requestV3->fileName.caseType;
+ *caseFlags = requestV3->fileName.caseType;
}
break;
}
* request->fileName.length is user-provided, so this test must be
* carefully written to prevent wraparounds.
*/
-
if (requestV2->fileName.length > extra) {
/* The input packet is smaller than the request */
* alone test the filename or its length. This applies to the source
* and the target.
*/
-
if (requestV3->oldName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
*srcFile = requestV3->oldName.fid;
*cpOldName = NULL;
* request->fileName.length is user-provided, so this test must be
* carefully written to prevent wraparounds.
*/
-
if (requestV3->oldName.length > extra) {
/* The input packet is smaller than the request */
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWriteWin32StreamRequest --
+ *
+ * Unpack hgfs SendFileUsingReader request. Returns file to write to, data
+ * and whether to restore the security stream.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsHandle *file, // OUT: file to write to
+ char **payload, // OUT: data to write
+ size_t *requiredSize, // OUT: size of data
+ Bool *doSecurity) // OUT: restore sec.str.
+{
+ HgfsRequest *request;
+ size_t extra;
+
+ ASSERT(packetIn);
+ ASSERT(file);
+ ASSERT(payload);
+ ASSERT(requiredSize);
+ ASSERT(doSecurity);
+
+ request = (HgfsRequest *)packetIn;
+
+ switch (request->op) {
+ case HGFS_OP_WRITE_WIN32_STREAM_V3:
+ {
+ HgfsRequestWriteWin32StreamV3 *requestV3 =
+ (HgfsRequestWriteWin32StreamV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
+
+ /* Enforced by the dispatch function */
+ ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+ extra = packetSize - HGFS_REQ_PAYLOAD_SIZE_V3(request) + 1;
+
+ *file = requestV3->file;
+ *payload = requestV3->payload;
+ *requiredSize = requestV3->requiredSize;
+ *doSecurity = (requestV3->flags & HGFS_WIN32_STREAM_IGNORE_SECURITY) == 0;
+
+ /*
+ * requiredSize is user-provided, so this test must be carefully
+ * written to prevent wraparounds.
+ */
+ if (*requiredSize > extra) {
+ /*
+ * The driver wants to write more bytes than there is in its payload.
+ * Truncate the request.
+ */
+
+ *requiredSize = extra;
+ }
+
+ break;
+ }
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackWriteWin32StreamReply --
+ *
+ * Pack hgfs SendFileUsingReader reply.
+ * Returns the actual amount of data written in the reply.
+ *
+ * Results:
+ * TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ uint32 actualSize, // IN: amount written
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize) // OUT: size of packet
+{
+ HgfsRequest *header = (HgfsRequest *)packetIn;
+
+ ASSERT(packetIn);
+ ASSERT(packetOut);
+ ASSERT(packetSize);
+
+ *packetOut = NULL;
+ *packetSize = 0;
+
+ switch (header->op) {
+ case HGFS_OP_WRITE_WIN32_STREAM_V3: {
+ HgfsReplyWriteWin32StreamV3 *reply;
+
+ *packetSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+ *packetOut = Util_SafeMalloc(*packetSize);
+ ((HgfsReply *)*packetOut)->id = header->id;
+ ((HgfsReply *)*packetOut)->status = HgfsConvertFromInternalStatus(status);
+
+ reply = (HgfsReplyWriteWin32StreamV3 *)HGFS_REP_GET_PAYLOAD_V3(*packetOut);
+ reply->actualSize = actualSize;
+ reply->reserved = 0;
+ break;
+ }
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
/*
*-----------------------------------------------------------------------------
*
* Find out how many directories deep the source file is from the common
* part of the path.
*/
-
while(*relativeSource != '\0') {
sourceSep = strchr(relativeSource, DIRSEPC);
if (sourceSep != NULL) {
* to the relative target path.
*/
- targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) +
- sizeof '\0';
+ targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) + sizeof '\0';
result = malloc(targetSize);
currentPosition = result;
if (result != NULL) {
level--;
currentPosition += HGFS_PARENT_DIR_LEN;
}
- memcpy(currentPosition, relativeTarget, strlen(relativeTarget) +
- sizeof '\0');
+ memcpy(currentPosition, relativeTarget, strlen(relativeTarget) + sizeof '\0');
}
-
return result;
}
* is double checked in HgfsAckOplockBreak, so we'd be safe from a garbage
* value.
*/
-
HgfsAckOplockBreak(lockData, reply->serverLock);
}
# define HGFS_DEFAULT_SHARE_ACCESS 0
#endif // _WIN32
+typedef struct HgfsShareInfo {
+ /* Filename of the root directory for the shared folder */
+ const char *rootDir;
+
+ /* Length of the root directory filename (does not include nul terminator) */
+ size_t rootDirLen;
+
+ /* Read permissions for the shared folder, needed for handle => name conversions. */
+ Bool readPermissions;
+
+ /* Write permissions for the shared folder, needed for handle => name conversions. */
+ Bool writePermissions;
+} HgfsShareInfo;
+
/*
* This struct represents a file on the local filesystem that has been
* opened by a remote client. We store the name of the local file and
/* File flags - see below. */
uint32 flags;
+
+ /*
+ * Context as required by some file operations. Eg: BackupWrite on
+ * Windows: BackupWrite requires the caller to hold on to a pointer
+ * to a Windows internal data structure between subsequent calls to
+ * BackupWrite while restoring a file.
+ */
+ void *fileCtx;
+
+ /* Parameters associated with the share. */
+ HgfsShareInfo shareInfo;
} HgfsFileNode;
* when we want to retrieve the attributes for each dent.
*/
DirectorySearchType type;
+
+ /* Parameters associated with the share. */
+ HgfsShareInfo shareInfo;
} HgfsSearch;
/* HgfsSessionInfo flags. */
char *cpName;
char *utf8Name;
uint32 caseFlags; /* Case-sensitivity flags. */
+ HgfsShareInfo shareInfo; /* Parameters associated with the share. */
} HgfsFileOpenInfo;
typedef struct HgfsFileAttrInfo {
char **bufOut, // OUT: File name in local fs
size_t *outLen); // OUT: Length of name out
+HgfsNameStatus
+HgfsServerGetShareInfo(char *cpName, // IN: Cross-platform filename to check
+ size_t cpNameSize, // IN: Size of name cpName
+ uint32 caseFlags, // IN: Case-sensitivity flags
+ HgfsShareInfo* shareInfo,// OUT: Shared folder properties
+ char **bufOut, // OUT: File name in local fs
+ size_t *outLen); // OUT: Length of name out
+
Bool
HgfsServerIsSharedFolderOnly(char const *in, // IN: CP filename to check
size_t inSize); // IN: Size of name in
HgfsInternalStatus
HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search
size_t baseDirLen, // IN: Length of directory
- DirectorySearchType type, // IN: Kind of search
char const *shareName, // IN: Share name
+ char const *rootDir, // IN: Root directory for the share
HgfsSessionInfo *session, // IN: Session info
HgfsHandle *handle); // OUT: Search handle
size_t packetSize, // IN: size of packet
HgfsSessionInfo *session); // IN: opaque transport data
+HgfsInternalStatus
+HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsSessionInfo *session); // IN: opaque transport data
+
/* Unpack/pack requests/reply helper functions. */
Bool
char **packetOut, // OUT: outgoing packet
size_t *packetSize); // OUT: size of packet
+Bool
+HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsHandle *file, // OUT: file to write to
+ char **payload, // OUT: data to write
+ size_t *requiredSize, // OUT: size of data
+ Bool *doSecurity); // OUT: restore sec.str.
+
+Bool
+HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ uint32 actualSize, // IN: amount written
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize); // OUT: size of packet
+
/* Node cache functions. */
Bool
Bool
HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle
HgfsSessionInfo *session, // IN: session info
- fileDesc *fd); // OUT: OS handle (file descriptor)
+ fileDesc *fd, // OUT: OS handle (file descriptor)
+ void **fileCtx); // OUT: OS file context
Bool
HgfsFileDesc2Handle(fileDesc fd, // IN: OS handle (file descriptor)
HgfsSessionInfo *session, // IN: session info
char **fileName, // OUT: CP file name
size_t *fileNameSize); // OUT: CP file name size
-
+Bool
+HgfsHandle2FileNameMode(HgfsHandle handle, // IN: Hgfs file handle
+ HgfsSessionInfo *session,// IN: Session info
+ Bool *readPermissions, // OUT: shared folder permissions
+ Bool *writePermissions, // OUT: shared folder permissions
+ char **fileName, // OUT: UTF8 file name
+ size_t *fileNameSize); // OUT: UTF8 file name size
Bool
HgfsHandle2AppendFlag(HgfsHandle handle, // IN: Hgfs file handle
HgfsSessionInfo *session, // IN: session info
Bool
HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle
HgfsSessionInfo *session, // IN: session info
- fileDesc fd); // OUT: OS handle (file desc
+ fileDesc fd, // IN: OS handle (file desc
+ void *fileCtx); // IN: OS file context
Bool
HgfsUpdateNodeServerLock(fileDesc fd, // IN: OS handle
HgfsSearch *copy); // IN/OUT: Copy of the search
HgfsInternalStatus
-HgfsCloseFile(fileDesc fileDesc); // IN: OS handle of the file
+HgfsCloseFile(fileDesc fileDesc, // IN: OS handle of the file
+ void *fileCtx); // IN: file context
Bool
HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine
char *shareName,
HgfsFileAttrInfo *attr,
char **targetName);
+static HgfsInternalStatus HgfsAccess(char *fileName,
+ char *shareName,
+ size_t shareNameLen);
static HgfsInternalStatus HgfsGetattrFromFd(int fd,
HgfsSessionInfo *session,
* We've got all we need from the signal handler, let it continue handling
* signals of this type.
*/
-
Sig_Continue(sigNum);
/*
* break is pending will return the new lease we should use. It'll be
* F_RDLCK if we can downgrade, or F_UNLCK if we should break altogether.
*/
-
newLease = fcntl(fd, F_GETLEASE);
if (newLease == F_RDLCK) {
newServerLock = HGFS_LOCK_SHARED;
* the acknowledgement, and firing the platform-specific acknowledgement
* function (where we'll downgrade the lease).
*/
-
lockData = malloc(sizeof *lockData);
if (lockData) {
lockData->fileDesc = fd;
*
* HgfsCloseFile --
*
- * Closes the file descriptor.
+ * Closes the file descriptor and release the file context.
*
* Results:
* Zero on success.
*/
HgfsInternalStatus
-HgfsCloseFile(fileDesc fileDesc) // IN: File descriptor
+HgfsCloseFile(fileDesc fileDesc, // IN: File descriptor
+ void *fileCtx) // IN: File context
{
if (close(fileDesc) != 0) {
int error = errno;
LOG(4, ("%s: Could not close fd %d: %s\n", __FUNCTION__, fileDesc,
strerror(error)));
-
return error;
}
LOG(4, ("%s: couldn't stat local file \"%s\": %s\n", __FUNCTION__,
localName, strerror(error)));
-
return error;
}
* path. Unfortuntely, even the fast path may need to look at the node's
* append flag.
*/
-
node.utf8Name = NULL;
if (!HgfsGetNodeCopy(hgfsHandle, session, TRUE, &node)) {
/* XXX: Technically, this can also fail if we're out of memory. */
* in append mode. If not, close the file and reopen it in append
* mode.
*/
-
if (append && !(node.flags & HGFS_FILE_NODE_APPEND_FL)) {
- status = HgfsCloseFile(node.fileDesc);
+ status = HgfsCloseFile(node.fileDesc, node.fileCtx);
if (status != 0) {
LOG(4, ("%s: Couldn't close file \"%s\" for reopening\n",
__FUNCTION__, node.utf8Name));
* Update the node in the cache with the new value of the append
* flag.
*/
-
if (!HgfsUpdateNodeAppendFlag(hgfsHandle, session, TRUE)) {
LOG(4, ("%s: Could not update the node in the cache\n",
__FUNCTION__));
* reopening. This means we need to open a file. But first, verify
* that the file we intend to open isn't stale.
*/
-
status = HgfsCheckFileNode(node.utf8Name, &node.localId);
if (status != 0) {
goto exit;
* We're not interested in creating a new file. So let's just get the
* flags for a simple open request. This really should always work.
*/
-
HgfsServerGetOpenFlags(0, &openFlags);
/*
*
* XXX: We should use O_LARGEFILE, see lib/file/fileIOPosix.c --hpreg
*/
-
newFd = Posix_Open(node.utf8Name,
node.mode | openFlags | (append ? O_APPEND : 0));
* Update the original node with the new value of the file desc.
* This call might fail if the node is not used anymore.
*/
-
- if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd)) {
+ if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd, NULL)) {
LOG(4, ("%s: Could not update the node -- node is not used.\n",
__FUNCTION__));
status = EBADF;
*fd = newFd;
}
free(node.utf8Name);
-
return status;
}
openFlags &= ~O_NOFOLLOW;
}
+ /*
+ * Need to validate that open does not change the file for read
+ * only shared folders.
+ */
+ status = 0;
+ if (!openInfo->shareInfo.writePermissions) {
+ if ((openFlags & (O_APPEND | O_CREAT | O_TRUNC)) ||
+ (openMode & (O_WRONLY | O_RDWR))) {
+ status = access(openInfo->utf8Name, F_OK);
+ if (status < 0) {
+ status = errno;
+ if (status == ENOENT && (openFlags & O_CREAT) != 0) {
+ status = EACCES;
+ }
+ } else {
+ /*
+ * Handle the case when the file already exists:
+ * If there is an attempt to createa new file, fail with "EEXIST"
+ * error, otherwise set error to "EACCES".
+ */
+ if ((openFlags & O_CREAT) && (openFlags & O_EXCL)) {
+ status = EEXIST;
+ } else {
+ status = EACCES;
+ }
+ }
+ }
+ if (status != 0) {
+ goto exit;
+ }
+ }
+
+ if (!openInfo->shareInfo.readPermissions) {
+ /*
+ * "Drop Box" / "FTP incoming" type of shared folders.
+ * Allow creating a new file. Deny opening exisitng file.
+ */
+ status = access(openInfo->utf8Name, F_OK);
+ if (status < 0) {
+ status = errno;
+ if (status != ENOENT || (openFlags & O_CREAT) == 0) {
+ status = EACCES;
+ }
+ } else {
+ status = EACCES;
+ }
+ if (status != 0) {
+ goto exit;
+ }
+ }
+
/*
* Determine if hidden attribute needs to be updated.
* It needs to be updated if a new file is created or an existing file is truncated.
((openFlags & O_CREAT) && (openFlags & O_EXCL))) {
needToSetAttribute = TRUE;
} else if (openFlags & O_CREAT) {
- int err = access(openInfo->utf8Name, F_OK);
+ int err = Posix_Access(openInfo->utf8Name, F_OK);
needToSetAttribute = (err != 0) && (errno == ENOENT);
}
}
*
* XXX: Do I need to do fcntl(fileDesc, F_SETOWN, getpid())?
*/
-
if (fcntl(fileDesc, F_SETSIG, SIGIO)) {
error = errno;
Log("%s: Could not set SIGIO as the desired lease break signal for "
* If the client just wanted the best lock possible, start off with a write
* lease and move down to a read lease if that was unavailable.
*/
-
if ((desiredLock == HGFS_LOCK_OPPORTUNISTIC) ||
(desiredLock == HGFS_LOCK_EXCLUSIVE)) {
leaseType = F_WRLCK;
* someone else is already writing or reading to the file, try again with
* a read lease.
*/
-
if (desiredLock == HGFS_LOCK_OPPORTUNISTIC &&
(errno == EAGAIN || errno == EACCES)) {
leaseType = F_RDLCK;
/* Got a lease of some kind. */
LOG(4, ("%s: Got %s lease for fd %d\n", __FUNCTION__,
leaseType == F_WRLCK ? "write" : "read", fileDesc));
-
*serverLock = leaseType == F_WRLCK ? HGFS_LOCK_EXCLUSIVE : HGFS_LOCK_SHARED;
return TRUE;
#else
* symlinks to symlinks. If the file is an alias, wasAliased will be set to
* TRUE and fileRef will reference the target file.
*/
-
osStatus = FSPathMakeRef(fileName, &fileRef, NULL);
if (osStatus != noErr) {
LOG(4, ("%s: could not create file reference: error %d\n",
__FUNCTION__, (int32)osStatus));
goto exit;
}
-
/*
* If alias points to an unmounted volume, the volume needs to be explicitly
* mounted on the host. Mount flag kResolveAliasFileNoUI serves the purpose.
* (HgfsGetattrFromName) will assume that an error means the file is a
* regular file.
*/
-
osStatus = FSResolveAliasFileWithMountFlags(&fileRef, FALSE, &targetIsFolder,
&wasAliased,
kResolveAliasFileNoUI);
* and convert the CFURL to a basic UTF-8 string using a call to
* CFURLGetFileSystemRepresentation().
*/
-
resolvedRef = CFURLCreateFromFSRef(NULL, &fileRef);
if (resolvedRef == NULL) {
LOG(4, ("%s: could not create resolved URL reference from "
if (resolvedRef != NULL) {
CFRelease(resolvedRef);
}
-
return status;
#endif
}
ASSERT(convertedComponentSize);
/* Open the specified directory. */
- dir = opendir(dirPath);
+ dir = Posix_OpenDir(dirPath);
if (!dir) {
ret = errno;
goto exit;
* The current directory entry is a case insensitive match to
* the specified component. Malloc and copy the current directory entry.
*/
-
myConvertedComponentSize = dentryNameLen + 1;
myConvertedComponent = malloc(myConvertedComponentSize);
if (myConvertedComponent == NULL) {
if (!p) {
int error = errno;
LOG(4, ("%s: failed to realloc.\n", __FUNCTION__));
-
return error;
}
/* Copy out the converted component to curDir, and free it. */
Str_Strncat(p, *pathSize, DIRSEPS, sizeof (DIRSEPS));
Str_Strncat(p, *pathSize, convertedPath, convertedPathLen);
-
return 0;
}
} else {
*convertedFileNameLength = strlen(fileName);
}
-
return 0;
}
*/
if (caseFlags == HGFS_FILE_NAME_CASE_INSENSITIVE &&
- access(fileName, F_OK) == -1) {
+ Posix_Access(fileName, F_OK) == -1) {
LOG(4, ("%s: Case insensitive lookup, fileName: %s, flags: %u.\n",
__FUNCTION__, fileName, caseFlags));
-
error = HgfsCaseInsensitiveLookup(sharePath, sharePathLength,
fileName, fileNameLength,
convertedFileName,
* Success or non-ENOENT error code. HgfsCaseInsensitiveLookup can
* return ENOENT, and its ok to continue if it is ENOENT.
*/
-
switch (error) {
+ /*
+ * Both ENOENT and 0 mean that HgfsCaseInsensitiveLookup
+ * successfully built the converted name thus we return
+ * HGFS_NAME_STATUS_COMPLETE in these two cases.
+ */
+ case 0:
case ENOENT:
nameStatus = HGFS_NAME_STATUS_COMPLETE;
break;
nameStatus = HGFS_NAME_STATUS_FAILURE;
break;
}
-
return nameStatus;
}
} else {
*convertedFileNameLength = fileNameLength;
}
-
return nameStatus;
}
uint32 *permissions) // OUT: Effective permissions
{
*permissions = 0;
- if (access(fileName, R_OK) == 0) {
+ if (Posix_Access(fileName, R_OK) == 0) {
*permissions |= HGFS_PERM_READ;
}
- if (access(fileName, X_OK) == 0) {
+ if (Posix_Access(fileName, X_OK) == 0) {
*permissions |= HGFS_PERM_EXEC;
}
- if (!readOnlyShare && (access(fileName, W_OK) == 0)) {
+ if (!readOnlyShare && (Posix_Access(fileName, W_OK) == 0)) {
*permissions |= HGFS_PERM_WRITE;
}
return 0;
* regular files, directories, and symlinks. On Mac OS, we'll additionally
* treat finder aliases as symlinks.
*/
-
if (S_ISDIR(stats.st_mode)) {
attr->type = HGFS_FILE_TYPE_DIRECTORY;
LOG(4, ("%s: is a directory\n", __FUNCTION__));
* In the case of a symlink, we should populate targetName if the
* caller asked. Use st_size and readlink() to do so.
*/
-
if (targetName != NULL) {
myTargetName = Posix_ReadLink(fileName);
* not have read the entire link. If that happens, just return
* "out of memory".
*/
-
status = error ? error : ENOMEM;
goto exit;
}
* outside the shared folder then treat it the same way as if alias
* has not been resolved.
*/
-
HgfsNameStatus nameStatus;
size_t sharePathLen;
const char* sharePath;
* the length of the target name (not including the
* nul-terminator), and the permissions should be 777.
*/
-
stats.st_size = strlen(myTargetName);
stats.st_mode |= ACCESSPERMS;
attr->type = HGFS_FILE_TYPE_SYMLINK;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsAccess --
+ *
+ * Check is a file with the given name exists and accessible, error code
+ * otherwise.
+ * The function does not follow symlinks unless HGFS_SHARE_FOLLOW_SYMLINKS
+ * flag is specified for the shared folder.
+ *
+ * Results:
+ * Zero on success.
+ * Non-zero on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static HgfsInternalStatus
+HgfsAccess(char *fileName, // IN: local file path
+ char *shareName, // IN: Name of the share
+ size_t shareNameLen) // IN: Length of the share name
+{
+ HgfsFileAttrInfo attr;
+ HgfsShareOptions configOptions;
+ HgfsNameStatus nameStatus;
+ HgfsInternalStatus status;
+
+ /* Get the config options. */
+ nameStatus = HgfsServerPolicy_GetShareOptions(shareName, shareNameLen,
+ &configOptions);
+ if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
+ LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, shareName));
+ status = ENOENT;
+ } else {
+ status = HgfsGetattrFromName(fileName, configOptions, shareName,
+ &attr, NULL);
+ }
+ return status;
+}
+
/*
*-----------------------------------------------------------------------------
*
* For now, everything that isn't a directory or symlink is a regular
* file.
*/
-
if (S_ISDIR(stats.st_mode)) {
attr->type = HGFS_FILE_TYPE_DIRECTORY;
LOG(4, ("%s: is a directory\n", __FUNCTION__));
* In the case we have a Windows client, force the hidden flag.
* This will be ignored by Linux, Solaris clients.
*/
-
HgfsGetHiddenAttr(fileName, attr);
if (shareMode == HGFS_OPEN_MODE_READ_ONLY) {
* Share does not allow write, so tell the client
* everything is read only.
*/
-
if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS) {
attr->ownerPerms &= ~HGFS_PERM_WRITE;
}
exit:
free(fileName);
-
return status;
}
* the guest time, and alwaysUseHostTime will be TRUE if the config
* option to always use host time is set.
*/
-
if (attr->mask & HGFS_ATTR_VALID_ACCESS_TIME) {
if (!alwaysUseHostTime && (hints & HGFS_ATTR_HINT_SET_ACCESS_TIME)) {
/* Use the guest-provided time */
* toggle permsChanged since it should not influence our decision of
* whether to actually call chmod or not.
*/
-
permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions);
if (permsChanged) {
LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions));
* the truncate request. At this point, the server must safeguard itself
* against deadlock.
*/
-
if (!HgfsHandle2ServerLock(file, session, &serverLock)) {
LOG(4, ("%s: File handle is no longer valid.\n", __FUNCTION__));
status = EBADF;
Bool idChanged = FALSE;
HgfsServerLock serverLock;
HgfsShareOptions configOptions;
-
- nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
- HGFS_OPEN_MODE_WRITE_ONLY, caseFlags,
- &localName, NULL);
+ size_t localNameLen;
+ HgfsShareInfo shareInfo;
+
+ nameStatus = HgfsServerGetShareInfo(cpName,
+ cpNameSize,
+ caseFlags,
+ &shareInfo,
+ &localName,
+ &localNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: access check failed\n", __FUNCTION__));
status = HgfsConvertFromNameStatus(nameStatus);
* XXX: This is racy. But clients interested in preventing a race should
* have sent us a Setattr packet with a valid HGFS handle.
*/
-
if (File_IsSymLink(localName)) {
LOG(4, ("%s: pathname contains a symlink\n", __FUNCTION__));
status = EINVAL;
goto exit_free;
}
+ if (!HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_WRITE_ONLY,
+ shareInfo.writePermissions,
+ shareInfo.readPermissions)) {
+ status = EACCES;
+ goto exit_free;
+ }
+
/*
* Try to make each requested attribute change. In the event that
* one operation fails, we still attempt to perform any other
* toggle permsChanged since it should not influence our decision of
* whether to actually call chmod or not.
*/
-
permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions);
if (permsChanged) {
LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions));
}
idChanged = HgfsSetattrOwnership(attr, &newUid, &newGid);
-
/*
* Chown changes the uid and gid together. If one of them should
* not be changed, we pass in -1.
*/
-
if (idChanged) {
if (Posix_Lchown(localName, newUid, newGid) < 0) {
error = errno;
* the truncate request. At this point, the server must safeguard itself
* against deadlock.
*/
-
if (HgfsFileHasServerLock(localName, session, &serverLock, &fd)) {
LOG(4, ("%s: Client attempted to truncate an oplocked file\n",
__FUNCTION__));
exit_free:
free(localName);
-
exit:
return status;
}
* Allocate the new dent and set it up. We do a straight memcpy of
* the entire record to avoid dealing with platform-specific fields.
*/
-
myDents[myNumDents] = malloc(newDent->d_reclen);
if (myDents[myNumDents] == NULL) {
status = ENOMEM;
* On error, free all allocated dents. On success, set the dents pointer
* given to us by the client.
*/
-
if (status != 0) {
size_t i;
for (i = 0; i < myNumDents; i++) {
char *packetOut;
size_t packetOutSize;
HgfsOpenFlags savedOpenFlags = 0;
+ size_t localNameLen;
ASSERT(packetIn);
ASSERT(session);
goto exit;
}
- nameStatus = HgfsServerGetAccess(openInfo.cpName, openInfo.cpNameSize,
- openInfo.mode, openInfo.caseFlags,
- &localName, NULL);
+ nameStatus = HgfsServerGetShareInfo(openInfo.cpName,
+ openInfo.cpNameSize,
+ openInfo.caseFlags,
+ &openInfo.shareInfo,
+ &localName,
+ &localNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: access check failed\n", __FUNCTION__));
status = HgfsConvertFromNameStatus(nameStatus);
* since that won't break a shared oplock, but the clients should already
* realize that the second open can be avoided via sharing handles, too.
*/
-
if (HgfsFileHasServerLock(localName, session, &serverLock, &newFd)) {
LOG (4, ("%s: Client tried to open new handle for oplocked file %s.\n",
__FUNCTION__, localName));
* requiredSize is user-provided, so this test must be carefully
* written to prevent wraparounds.
*/
-
if (requiredSize > extra) {
/*
* The client wants to read more bytes than our payload can handle.
* Truncate the request
*/
-
requiredSize = extra;
}
if (status != 0) {
LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
free(packetOut);
-
return status;
}
if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__));
free(packetOut);
-
return EBADF;
}
* Seek to the offset and read from the file. Grab the IO lock to make
* this and the subsequent read atomic.
*/
-
SyncMutex_Lock(&session->fileIOLock);
if (!sequentialOpen) {
# ifdef linux
if (status != 0) {
LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
free(packetOut);
-
return status;
}
if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__));
free(packetOut);
-
return EBADF;
}
* requiredSize is user-provided, so this test must be carefully
* written to prevent wraparounds.
*/
-
if (requiredSize > extra) {
/*
* The driver wants to write more bytes than there is in its payload.
* Truncate the request
*/
-
requiredSize = extra;
}
HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
size_t replySize;
char *packetOut;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
* request->dirName.length is user-provided, so this test must be carefully
* written to prevent wraparounds.
*/
-
if (dirNameLength > extra) {
/* The input packet is smaller than the request */
status = EPROTO;
goto exit;
}
- /* It is now safe to read the dirName */
- nameStatus = HgfsServerGetAccess(dirName, dirNameLength,
- HGFS_OPEN_MODE_READ_ONLY,
- caseFlags, &baseDir, &baseDirLen);
+ /* It is now safe to read the file name. */
+ nameStatus = HgfsServerGetShareInfo(dirName,
+ dirNameLength,
+ caseFlags,
+ &shareInfo,
+ &baseDir,
+ &baseDirLen);
switch (nameStatus) {
case HGFS_NAME_STATUS_COMPLETE:
{
LOG(4, ("%s: dirName: %s.\n", __FUNCTION__, dirName));
status = HgfsServerSearchRealDir(baseDir,
baseDirLen,
- DIRECTORY_SEARCH_TYPE_DIR,
- dirName, session, &handle);
+ dirName,
+ shareInfo.rootDir,
+ session,
+ &handle);
free(baseDir);
+ /*
+ * If the directory exists but shared folder is write only
+ * then return access denied, otherwise preserve the original
+ * error code.
+ */
+ if (!shareInfo.readPermissions && HGFS_NAME_STATUS_COMPLETE == status) {
+ status = HGFS_NAME_STATUS_ACCESS_DENIED;
+ }
if (status != 0) {
LOG(4, ("%s: couldn't scandir\n", __FUNCTION__));
goto exit;
* Return handle to the search object as the reply to the search
* open.
*/
-
*replySearch = handle;
if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id,
exit:
free(packetOut);
-
return status;
}
search.utf8ShareName));
free(search.utf8Dir);
free(search.utf8ShareName);
-
return ENOENT;
}
}
* Construct the UTF8 version of the full path to the file, and call
* HgfsGetattrFromName to get the attributes of the file.
*/
-
fullNameLen = search.utf8DirLen + 1 + length;
fullName = (char *)malloc(fullNameLen + 1);
if (!fullName) {
free(search.utf8Dir);
free(search.utf8ShareName);
free(dent);
-
return ENOMEM;
}
memcpy(fullName, search.utf8Dir, search.utf8DirLen);
* share gets resolved into its full path, and gets its attributes
* via HgfsGetattrFromName.
*/
-
if (strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0) {
LOG(4, ("%s: assigning %s default attributes\n",
free(dent);
free(search.utf8Dir);
free(search.utf8ShareName);
-
return HgfsConvertFromNameStatus(nameStatus);
}
* problems on the host, the server still enumerates it and
* returns to the client.
*/
-
status = HgfsGetattrFromName(sharePath, configOptions, dent->d_name,
&attr, NULL);
if (status != 0) {
* No conversion needed on OS X because dent->d_name is the shareName
* that was converted to normal form C in hgfsServerPolicyHost.
*/
-
entryName = dent->d_name;
entryNameLen = length;
break;
* The POSIX implementation of HgfsSearchOpen could not have created
* this kind of search.
*/
-
NOT_IMPLEMENTED();
break;
default:
/*
* We need to unescape the name before sending it back to the client
*/
-
entryNameLen = HgfsEscape_Undo(entryName, entryNameLen + 1);
/*
* one with success. Now we return an error. This may be a non-issue
* since what filesystems allow dent lengths as high as 6144 bytes?
*/
-
status = 0;
if (!HgfsPackSearchReadReply(packetIn, status, entryName, entryNameLen,
&attr, &packetOut, &packetOutSize)) {
!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
free(packetOut);
}
-
return status;
}
HgfsShareOptions configOptions;
char *packetOut;
size_t packetOutSize;
+ size_t localNameLen;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
* Depending on whether this file/dir is real or virtual, either
* forge its attributes or look them up in the actual filesystem.
*/
-
- nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
- HGFS_OPEN_MODE_READ_ONLY,
- caseFlags, &localName, NULL);
+ nameStatus = HgfsServerGetShareInfo(cpName,
+ cpNameSize,
+ caseFlags,
+ &shareInfo,
+ &localName,
+ &localNameLen);
switch (nameStatus) {
case HGFS_NAME_STATUS_INCOMPLETE_BASE:
status = HgfsGetattrFromName(localName, configOptions, cpName, &attr,
&targetName);
free(localName);
- if (status != 0) {
+ if (status == 0 &&
+ !HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_READ_ONLY,
+ shareInfo.writePermissions,
+ shareInfo.readPermissions)) {
+ status = EACCES;
+ } else if (status != 0) {
/*
* If it is a dangling share server should not return ENOENT
* to the client because it causes confusion: a name that is returned
ASSERT(packetIn);
ASSERT(session);
+ LOG(4, ("NEW LIB! HgfsServerSetAttr Called!\n"));
+
if (!HgfsUnpackSetattrRequest(packetIn, packetSize, &attr, &hints,
&cpName, &cpNameSize, &file, &caseFlags)) {
status = EPROTO;
mode_t permissions;
char *packetOut;
size_t packetOutSize;
+ size_t localNameLen;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
return EPROTO;
}
- nameStatus = HgfsServerGetAccess(info.cpName, info.cpNameSize,
- HGFS_OPEN_MODE_WRITE_ONLY,
- info.caseFlags, &localName, NULL);
+ nameStatus = HgfsServerGetShareInfo(info.cpName,
+ info.cpNameSize,
+ info.caseFlags,
+ &shareInfo,
+ &localName,
+ &localNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: access check failed\n", __FUNCTION__));
ASSERT(localName);
+ /*
+ * For read-only shares we must never attempt to create a directory.
+ * However the error code must be different depending on the existence
+ * of the file or directory with the same name.
+ */
+ if (!shareInfo.writePermissions) {
+ int error = HgfsAccess(localName, info.cpName, info.cpNameSize);
+ if (error != 0) {
+ if (error == ENOENT) {
+ error = EACCES;
+ }
+ } else {
+ error = EEXIST;
+ }
+ LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error));
+ free(localName);
+ return error;
+ }
+
/*
* Create mode_t for use in mkdir(). If owner permissions are missing, use
* read/write/execute for the owner permissions. If group or other
* a directory requires a valid mode, it's highly unlikely that we'll ever
* be creating a directory without owner permissions.
*/
-
permissions = ~ALLPERMS;
permissions |= info.mask & HGFS_CREATE_DIR_VALID_SPECIAL_PERMS ?
info.specialPerms << 9 : 0;
* Set hidden attribute when requested.
* Do not fail directory creation if setting hidden attribute fails.
*/
-
HgfsSetHiddenXAttr(localName, TRUE);
}
uint32 caseFlags;
char *packetOut;
size_t packetOutSize;
+ size_t localNameLen;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
}
if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
- if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) {
+ if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions,
+ &shareInfo.readPermissions, &cpName, &cpNameSize)) {
LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__,
file));
-
return EBADF;
}
localName = cpName;
} else {
- nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
- HGFS_OPEN_MODE_WRITE_ONLY, caseFlags,
- &localName, NULL);
+ nameStatus = HgfsServerGetShareInfo(cpName,
+ cpNameSize,
+ caseFlags,
+ &shareInfo,
+ &localName,
+ &localNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: access check failed\n", __FUNCTION__));
ASSERT(localName);
+ /*
+ * Deleting a file needs both read and write permssions.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ int error = HgfsAccess(localName, cpName, cpNameSize);
+ if (error == 0) {
+ error = EACCES;
+ }
+ LOG(4, ("HgfsServerDeleteFile: failed access check, error %d\n", error));
+ free(localName);
+ return error;
+ }
+
LOG(4, ("%s: unlinking \"%s\"\n", __FUNCTION__, localName));
error = Posix_Unlink(localName);
free(localName);
uint32 caseFlags;
char *packetOut;
size_t packetOutSize;
+ size_t localNameLen;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
}
if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
- if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) {
+ if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions,
+ &shareInfo.readPermissions, &cpName, &cpNameSize)) {
LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__,
file));
-
return EBADF;
}
localName = cpName;
} else {
- nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
- HGFS_OPEN_MODE_WRITE_ONLY,
- caseFlags, &localName, NULL);
+ nameStatus = HgfsServerGetShareInfo(cpName,
+ cpNameSize,
+ caseFlags,
+ &shareInfo,
+ &localName,
+ &localNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: access check failed\n", __FUNCTION__));
return EPERM;
}
+ /*
+ * Deleting a directory needs both read and write permssions.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ int error = HgfsAccess(localName, cpName, cpNameSize);
+ if (error == 0) {
+ error = EACCES;
+ }
+ LOG(4, ("HgfsServerDeleteDir: failed access check, error %d\n", error));
+ free(localName);
+ return error;
+ }
+
ASSERT(localName);
LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, localName));
if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
free(packetOut);
}
-
return 0;
}
{
HgfsNameStatus nameStatus;
char *localOldName = NULL;
+ size_t localOldNameLen;
char *localNewName = NULL;
+ size_t localNewNameLen;
char *cpOldName;
uint32 cpOldNameLen;
char *cpNewName;
uint32 newCaseFlags = 0;
char *packetOut;
size_t packetOutSize;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
if (hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) {
size_t localOldNameLen;
- if (!HgfsHandle2FileName(srcFile, session, &localOldName,
- &localOldNameLen)) {
+ if (!HgfsHandle2FileNameMode(srcFile, session, &shareInfo.writePermissions,
+ &shareInfo.readPermissions, &localOldName,
+ &localOldNameLen)) {
LOG(4, ("%s: could not map cached source file handle %u\n",
__FUNCTION__, srcFile));
-
return EBADF;
}
} else {
- nameStatus = HgfsServerGetAccess(cpOldName, cpOldNameLen,
- HGFS_OPEN_MODE_READ_WRITE,
- oldCaseFlags, &localOldName, NULL);
+ nameStatus = HgfsServerGetShareInfo(cpOldName,
+ cpOldNameLen,
+ oldCaseFlags,
+ &shareInfo,
+ &localOldName,
+ &localOldNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
- LOG(4, ("%s: old name access check failed\n", __FUNCTION__));
-
return HgfsConvertFromNameStatus(nameStatus);
}
status = EPERM;
goto exit;
}
+
+ /*
+ * Renaming a file requires both read and write permissions for the original file.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ status = HgfsAccess(localOldName, cpOldName, cpOldNameLen);
+ if (status == 0) {
+ status = EACCES;
+ }
+ LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
+ goto exit;
+ }
}
if (hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) {
size_t localNewNameLen;
- if (!HgfsHandle2FileName(targetFile, session, &localNewName,
- &localNewNameLen)) {
+ if (!HgfsHandle2FileNameMode(targetFile, session, &shareInfo.writePermissions,
+ &shareInfo.readPermissions, &localNewName,
+ &localNewNameLen)) {
LOG(4, ("%s: could not map cached target file handle %u\n",
__FUNCTION__, targetFile));
-
return EBADF;
}
} else {
- nameStatus = HgfsServerGetAccess(cpNewName, cpNewNameLen,
- HGFS_OPEN_MODE_WRITE_ONLY,
- newCaseFlags, &localNewName, NULL);
+ nameStatus = HgfsServerGetShareInfo(cpNewName,
+ cpNewNameLen,
+ newCaseFlags,
+ &shareInfo,
+ &localNewName,
+ &localNewNameLen);
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: new name access check failed\n", __FUNCTION__));
status = HgfsConvertFromNameStatus(nameStatus);
}
}
+ /*
+ * Renaming a file requires both read and write permssions for the target file.
+ * However the error code must be different depending on the existence
+ * of the file with the same name.
+ */
+ if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+ status = HgfsAccess(localNewName, cpNewName, cpNewNameLen);
+ if (status == 0 || status == ENOENT) {
+ status = EACCES;
+ }
+ LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
+ goto exit;
+ }
+
LOG(4, ("%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__,
localOldName, localNewName));
error = Posix_Rename(localOldName, localNewName);
* XXX: Note that this operation can fail (out of memory), but we'd like
* the client to see success anyway, because the rename succeeded.
*/
-
status = 0;
HgfsUpdateNodeNames(localOldName, localNewName, session);
if (!HgfsPackRenameReply(packetIn, status, &packetOut, &packetOutSize)) {
uint64 *totalBytes;
char *packetOut;
size_t packetOutSize;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
* We don't yet support file handle for this operation.
* Clients should retry using the file name.
*/
-
if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
status = EPARAMETERNOTSUPPORTED;
* request->fileName.length is user-provided, so this test must be carefully
* written to prevent wraparounds.
*/
-
if (fileNameLength > extra) {
/* The input packet is smaller than the request. */
status = EPROTO;
}
/* It is now safe to read the file name field. */
- nameStatus = HgfsServerGetAccess(fileName, fileNameLength,
- HGFS_OPEN_MODE_READ_WRITE,
- caseFlags, &utf8Name, &utf8NameLen);
+ nameStatus = HgfsServerGetShareInfo(fileName,
+ fileNameLength,
+ caseFlags,
+ &shareInfo,
+ &utf8Name,
+ &utf8NameLen);
switch (nameStatus) {
case HGFS_NAME_STATUS_INCOMPLETE_BASE:
/*
* Now go through all shares and get share paths on the server.
* Then retrieve space info for each share's volume.
*/
-
offset = 0;
while ((dent = HgfsGetSearchResult(handle, session, offset,
TRUE)) != NULL) {
* need to make sure to handle them properly. In particular, they
* should be ignored within QueryVolume, as they're not real shares.
*/
-
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
LOG(4, ("%s: Skipping fake share %s\n", __FUNCTION__,
dent->d_name));
* The above check ignores '.' and '..' so we do not include them in
* the share count here.
*/
-
shares++;
/*
* Pick the drive with amount of space available and return that
* according to different volume info type.
*/
-
switch (infoType) {
case VOLUME_INFO_TYPE_MIN:
if ((outFreeBytes > freeBytes) || firstShare) {
char *packetOut;
size_t packetOutSize;
HgfsInternalStatus status = 0;
+ size_t localSymlinkNameLen;
+ HgfsShareInfo shareInfo;
ASSERT(packetIn);
ASSERT(session);
* targetName starts after symlinkName + the variable length array
* in symlinkName.
*/
-
targetNameP = (HgfsFileNameV3 *)(symlinkName + 1 + symlinkNameLength);
targetName = targetNameP->name;
targetNameLength = targetNameP->length;
* We don't yet support file handle for this operation.
* Clients should retry using the file name.
*/
-
if (requestV3->symlinkName.flags & HGFS_FILE_NAME_USE_FILE_DESC ||
targetNameP->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
* "targetName" field
*/
- nameStatus = HgfsServerGetAccess(symlinkName, symlinkNameLength,
- HGFS_OPEN_MODE_READ_WRITE,
- caseFlags, &localSymlinkName,
- NULL);
- if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
+ nameStatus = HgfsServerGetShareInfo(symlinkName,
+ symlinkNameLength,
+ caseFlags,
+ &shareInfo,
+ &localSymlinkName,
+ &localSymlinkNameLen);
+ if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
LOG(4, ("%s: symlink name access check failed\n",
__FUNCTION__));
status = HgfsConvertFromNameStatus(nameStatus);
goto exit;
}
+ if (!shareInfo.writePermissions ) {
+ int error = HgfsAccess(localSymlinkName, symlinkName, symlinkNameLength);
+ if (error != 0) {
+ if (error == ENOENT) {
+ error = EACCES;
+ }
+ } else {
+ error = EEXIST;
+ }
+ LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error));
+ free(localSymlinkName);
+ return error;
+ }
+
ASSERT(localSymlinkName);
extra -= symlinkNameLength;
* targetNameLength is user-provided, so this test must be carefully
* written to prevent wraparounds.
*/
-
if (targetNameLength > extra) {
/* The input packet is smaller than the request */
free(localSymlinkName);
session, 0)) {
goto exit;
}
-
return status;
exit:
free(packetOut);
-
return status;
}
* access to entire host) or
* - fileName and sharePath are same.
*/
-
if (fileNameLength == 0 ||
sharePathLength == 0 ||
Str_Strcmp(sharePath, fileName) == 0) {
/* Separate out parent directory of the fileName. */
File_GetPathName(fileName, &fileDirName, NULL);
-
/*
* File_GetPathName may return an empty string to signify the root of
* the filesystem. To simplify subsequent processing, let's convert such
* empty strings to "/" when found. See File_GetPathName header comment
* for details.
*/
-
if (strlen(fileDirName) == 0) {
char *p;
p = realloc(fileDirName, sizeof (DIRSEPS));
* Resolve parent directory of fileName.
* Use realpath(2) to resolve the parent.
*/
-
resolvedFileDirPath = Posix_RealPath(fileDirName);
if (resolvedFileDirPath == NULL) {
/* Let's return some meaningful errors if possible. */
exit:
free(resolvedFileDirPath);
free(fileDirName);
-
return nameStatus;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerWriteWin32Stream --
+ *
+ * Handle a write request in the WIN32_STREAM_ID format.
+ *
+ * Results:
+ * EOPNOTSUPP, because this is unimplemented.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+HgfsInternalStatus
+HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet
+ size_t packetSize, // IN: size of packet
+ HgfsSessionInfo *session) // IN: session info
+{
+ return EOPNOTSUPP;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
* lock if our previous call to fcntl() said we could, and if the client
* wants to downgrade to a shared lock. Otherwise, we break altogether.
*/
-
if (lockData->serverLock == HGFS_LOCK_SHARED &&
replyLock == HGFS_LOCK_SHARED) {
newLock = F_RDLCK;
} else {
LOG(4, ("%s: Error %d when getting attributes\n", __FUNCTION__, err));
}
-
return err;
}
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerPolicy_ProcessCPName --
+ *
+ * Get the local path for a share name by looking at the requested
+ * name, finding the matching share (if any) and returning the share's
+ * local path local path and permissions.
+ *
+ * Results:
+ * An HgfsNameStatus value indicating the result is returned.
+ *
+ * The local path for the shareName is also returned if a match is found.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+HgfsNameStatus
+HgfsServerPolicy_ProcessCPName(char const *nameIn, // IN: name in CPName form
+ size_t nameInLen, // IN: length of the name
+ Bool *readAccess, // OUT: Read permissions
+ Bool *writeAccess, // OUT: Write permissions
+ char const **shareBaseDir) // OUT: Shared directory
+{
+ HgfsSharedFolder *myShare;
+
+ ASSERT(nameIn);
+ ASSERT(shareBaseDir);
+
+ myShare = HgfsServerPolicyGetShare(&myState, nameIn, nameInLen);
+ if (!myShare) {
+ LOG(4, ("%s: No matching share name\n", __FUNCTION__));
+ return HGFS_NAME_STATUS_DOES_NOT_EXIST;
+ }
+
+ *readAccess = myShare->readAccess;
+ *writeAccess = myShare->writeAccess;
+ *shareBaseDir = myShare->path;
+ return HGFS_NAME_STATUS_COMPLETE;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
return HGFS_NAME_STATUS_COMPLETE;
}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerPolicy_CheckMode --
+ *
+ * Checks if the requested mode may be granted depending on read/write permissions.
+ *
+ * Results:
+ * TRUE if the requested mode can be granted, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsServerPolicy_CheckMode(HgfsOpenMode mode, // IN: mode to check
+ Bool writePermissions, // IN: callers write permissions
+ Bool readPermissions) // IN: callers read permissions
+{
+ /*
+ * See if access is allowed in the requested mode.
+ *
+ * XXX Yeah, this is retarded. We should be using bits instead of
+ * an enum for HgfsOpenMode. Add it to the todo list. [bac]
+ */
+ switch (HGFS_OPEN_MODE_ACCMODE(mode)) {
+ case HGFS_OPEN_MODE_READ_ONLY:
+ if (!readPermissions) {
+ LOG(4, ("HgfsServerPolicyCheckMode: Read access denied\n"));
+ return FALSE;
+ }
+ break;
+
+ case HGFS_OPEN_MODE_WRITE_ONLY:
+ if (!writePermissions) {
+ LOG(4, ("HgfsServerPolicyCheckMode: Write access denied\n"));
+ return FALSE;
+ }
+ break;
+
+ case HGFS_OPEN_MODE_READ_WRITE:
+ if (!readPermissions || !writePermissions) {
+ LOG(4, ("HgfsServerPolicyCheckMode: Read/write access denied\n"));
+ return FALSE;
+ }
+ break;
+
+ default:
+ LOG(0, ("HgfsServerPolicyCheckMode: Invalid mode\n"));
+ ASSERT(FALSE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
*
* ImageUtil_ConstructPNGBuffer --
*
- * Writes a PNG of the image to the DynBuf passed in.
- *
- * Results:
- * TRUE if successful, FALSE otherwise.
- *
- * Side effects:
- * If successful, imageData should be destroyed.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN
- DynBuf *imageData) // OUT
-
-{
- return ImageUtil_ConstructPNGBufferEx(image, NULL, imageData);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * ImageUtil_ConstructPNGBufferEx --
- *
* Writes a PNG of the image to the DynBuf passed in. Accepts a zlib
* compression level (0-9, 0 means no compression, -1 means "use the
* default").
*/
Bool
-ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN
- const ImagePngWriteOptions *pOptions, // IN/OPT
- DynBuf *imageData) // OUT
+ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN
+ const ImagePngWriteOptions *pOptions, // IN/OPT
+ DynBuf *imageData) // OUT
{
png_structp png_ptr;
png_infop info_ptr;
};
#endif // __cplusplus
-#endif //_WIN32
+#else // not _WIN32
-#if defined(linux)
#include <glib.h>
void AppUtil_Init(void);
#define BUILD_NUMBER \
- "build-179896"
+ "build-187411"
#define BUILD_NUMBER_NUMERIC \
- 179896
+ 187411
#define BUILD_NUMBER_NUMERIC_STRING \
- "179896"
+ "187411"
#define PRODUCT_BUILD_NUMBER \
- "product-build-620"
+ "product-build-653"
#define PRODUCT_BUILD_NUMBER_NUMERIC \
- 620
+ 653
#define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \
- "620"
+ "653"
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * community_source.h --
+ *
+ * Macros for excluding source code from community.
+ */
+
+#ifndef _COMMUNITY_SOURCE_H_
+#define _COMMUNITY_SOURCE_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+/*
+ * Convenience macro for COMMUNITY_SOURCE
+ */
+#undef EXCLUDE_COMMUNITY_SOURCE
+#ifdef COMMUNITY_SOURCE
+ #define EXCLUDE_COMMUNITY_SOURCE(x)
+#else
+ #define EXCLUDE_COMMUNITY_SOURCE(x) x
+#endif
+
+#undef COMMUNITY_SOURCE_INTEL_SECRET
+#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE)
+/*
+ * It's ok to include INTEL_SECRET source code for non-commsrc,
+ * or for drops directed at Intel.
+ */
+ #define COMMUNITY_SOURCE_INTEL_SECRET
+#endif
+
+#endif
EXTERN char *File_ExpandAndCheckDir(const char *dirName);
-EXTERN Bool File_SupportsPrealloc(const char *file);
-
#ifdef __cplusplus
} // extern "C" {
#endif
Bool isExcluded);
#endif
+Bool FileIO_SupportsPrealloc(const char *pathName, Bool fsCheck);
+
#endif // _FILEIO_H_
GHI_CAP_TRAY_ICONS = 19, // supports ghi.guest.trayIcon commands
GHI_CAP_SET_FOCUSED_WINDOW = 20, // supports ghi.guest.setFocusedWindow
GHI_CAP_GET_EXEC_INFO_HASH = 21, // supports ghi.guest.getExecInfoHash
+ UNITY_CAP_STICKY_WINDOWS = 22, // supports unity.window.{un,}stick
} GuestCapabilities;
typedef struct {
{ GHI_CAP_TRAY_ICONS, GHI_CAP_VMDB_PATH, "trayIcons" },
{ GHI_CAP_SET_FOCUSED_WINDOW, GHI_CAP_VMDB_PATH, "setFocusedWindow"},
{ GHI_CAP_GET_EXEC_INFO_HASH, GHI_CAP_VMDB_PATH, "getExecInfoHash"},
+ { UNITY_CAP_STICKY_WINDOWS, UNITY_CAP_VMDB_PATH, "sticky"},
};
#endif // VM_NEED_VMDB_GUEST_CAP_MAPPING
/*
* Global functions
+ *
+ * XXX These belong in a bora-vmsoft header.
*/
#ifndef N_PLAT_NLM
extern Bool GuestInfo_GetFqdn(int outBufLen, char fqdn[]);
-extern Bool GuestInfo_GetNicInfo(GuestNicList *nicInfo);
+extern Bool GuestInfo_GetNicInfo(NicInfoV3 **nicInfo);
+extern void GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo);
extern Bool GuestInfo_GetDiskInfo(PGuestDiskInfo di);
extern Bool GuestInfo_GetOSName(unsigned int outBufFullLen,
unsigned int outBufLen, char *osNameFull,
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * hgfsClient.h
+ *
+ * Provides a helper library for guest applications to access
+ * the HGFS file system.
+ */
+
+#ifndef _HGFS_HELPER_H_
+#define _HGFS_HELPER_H_
+
+#include "vm_basic_types.h"
+#include "unicode.h"
+
+Bool HgfsHlpr_QuerySharesDefaultRootPath(Unicode *hgfsRootPath);
+void HgfsHlpr_FreeSharesRootPath(Unicode hgfsRootPath);
+#if defined(_WIN32)
+Bool HgfsHlpr_ReadRegistryDefaultRootPath(Unicode *hgfsRootPath);
+#endif // _WIN32
+
+#endif
HGFS_OP_QUERY_VOLUME_INFO_V3, /* Query volume information */
HGFS_OP_CREATE_SYMLINK_V3, /* Create a symlink */
HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */
+ HGFS_OP_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */
+
+ /*
+ * Operations for version 4, deprecating version 3 operations.
+ */
+
+ HGFS_OP_CREATE_SESSION_V4, /* Create a session and return host capabilities. */
+ HGFS_OP_DESTROY_SESSION_V4, /* Destroy/close session. */
+ HGFS_OP_OPEN_V4, /* Open file */
+ HGFS_OP_DIRECTORY_READ_V4, /* Read directory entries. */
+ HGFS_OP_ENUMERATE_STREAMS_V4, /* Enumerate alternative named streams for a file. */
+ HGFS_OP_GETATTR_V4, /* Get file attributes */
+ HGFS_OP_SETATTR_V4, /* Set file attributes */
+ HGFS_OP_DELETE_V4, /* Delete a file or a directory */
+ HGFS_OP_LINKMOVE_V4, /* Rename/move/create hard link. */
+ HGFS_OP_FSCTL_V4, /* Sending FS control requests. */
+ HGFS_OP_ACCESS_CHECK_V4, /* Flush all cached data to the disk. */
+ HGFS_OP_FSYNC_V4, /* Access check. */
+ HGFS_OP_QUERY_VOLUME_INFO_V4, /* Query volume information. */
+ HGFS_OP_OPLOCK_ACQUIRE_V4, /* Acquire OPLOCK. */
+ HGFS_OP_OPLOCK_BREAK_V4, /* Break or downgrade OPLOCK. */
+ HGFS_OP_LOCK_BYTE_RANGE_V4, /* Acquire byte range lock. */
+ HGFS_OP_UNLOCK_BYTE_RANGE_V4, /* Release byte range lock. */
+ HGFS_OP_QUERY_EAS_V4, /* Query extended attributes. */
+ HGFS_OP_SET_EAS_V4, /* Add or modify extended attributes. */
+ HGFS_OP_SET_WATCH_V4, /* Start monitoring directory changes. */
+ HGFS_OP_REMOVE_WATCH_V4, /* Stop monitoring directory changes. */
+ HGFS_OP_NOTIFY_V4, /* Notification for a directory change event. */
HGFS_OP_MAX, /* Dummy op, must be last in enum */
} HgfsOp;
#define HGFS_ATTR_HIDDEN_FORCED (1 << 3)
#define HGFS_ATTR_REPARSE_POINT (1 << 4)
+/* V4 additional definitions for hgfsAttrFlags. */
+#define HGFS_ATTR_COMPRESSED (1 << 5)
+#define HGFS_ATTR_ENCRYPTED (1 << 6)
+#define HGFS_ATTR_OFFLINE (1 << 7)
+#define HGFS_ATTR_READONLY (1 << 8)
+#define HGFS_ATTR_SPARSE (1 << 9)
+#define HGFS_ATTR_TEMPORARY (1 << 10)
/*
* Specifies which open request fields contain
#define HGFS_OPEN_VALID_SERVER_LOCK (1 << 10)
#define HGFS_OPEN_VALID_FILE_NAME (1 << 11)
+/* V4 additional open mask flags. */
+#define HGFS_OPEN_VALID_EA (1 << 12)
+#define HGFS_OPEN_VALID_ACL (1 << 13)
+#define HGFS_OPEN_VALID_STREAM_NAME (1 << 14)
/*
* Specifies which attribute fields contain
#include "vmware_pack_end.h"
HgfsReplyWriteV3;
+/* Stream write flags */
+typedef enum {
+ HGFS_WIN32_STREAM_IGNORE_SECURITY = (1<<0),
+} HgfsWin32StreamFlags;
+
+/*
+ * HgfsRequestWriteWin32Stream.
+ * Server must support HGFS_LARGE_PACKET_MAX to implement this op.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestWriteWin32StreamV3 {
+ HgfsHandle file; /* Opaque file ID used by the server */
+ HgfsWin32StreamFlags flags;
+ uint32 reserved1;
+ uint32 requiredSize;
+ uint64 reserved2; /* Reserved for future use */
+ char payload[1];
+}
+#include "vmware_pack_end.h"
+HgfsRequestWriteWin32StreamV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyWriteWin32StreamV3 {
+ uint32 actualSize;
+ uint64 reserved; /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyWriteWin32StreamV3;
+
/* Deprecated */
#include "vmware_pack_end.h"
HgfsReplySymlinkCreateV3;
+/* HGFS protocol version 4 definitions. */
+
+/*
+ * HGFS_PACKET_FLAG_NOTIFICATION set in flags field means that
+ * this is a notification or a callback request (not a reply to client request).
+ */
+
+#define HGFS_PACKET_FLAG_NOTIFICATION (1 << 0)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsHeader {
+ uint8 version; /* Header version. */
+ uint8 reserved1[3]; /* Reserved for future use. */
+ uint8 dummy; /* Needed to distinguish between older and newer header. */
+ uint8 reserved2[3]; /* Reserved for future use. */
+ uint32 packetSize; /* Size of the packet, including the header size. */
+ uint32 headerSize; /* Size of the Hgfs header. */
+ uint32 requestId; /* Request ID. */
+ uint32 op; /* Operation. */
+ uint32 status; /* Return value. */
+ uint32 flags; /* Flags. */
+ uint32 information; /* Generic field, used e.g. for native error code. */
+ uint64 sessionId; /* Session ID. */
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsHeader;
+
+/*
+ * Flag HGFS_REQUEST_SUPPORTED is set for every requests that are supported by the host.
+ */
+#define HGFS_REQUEST_SUPPORTED (1 << 0)
+
+/*
+ * Following flags define which optional parameters for file open
+ * requests are supported by the host.
+ * HGFS_OPENV4_SUPPORTS_EA - host is capable of setting EA when creating
+ * a new file.
+ * HGFS_OPENV4_SUPPORTS_ACL - host is capable of setting ACLs when creating
+ * a new file.
+ * HGFS_OPENV4_SUPPORTS_NAMED_STREAMS - opening/enumerating named streams
+ * is supported.
+ * HGFS_OPENV4_SUPPORTS_SHARED_ACCESS - host supports file sharing restrictions.
+ * HGFS_OPENV4_SUPPORTS_UNIX_PERMISSIONS - host stores POSIX permissions with
+ * file.
+ * HGFS_OPENV4_POSIX_FILE_DELETION - host supports POSIX file deletion semantics.
+ */
+typedef uint32 HgfsOpenV4Capabilities;
+#define HGFS_OPENV4_SUPPORTS_EA (1 << 1)
+#define HGFS_OPENV4_SUPPORTS_ACL (1 << 2)
+#define HGFS_OPENV4_SUPPORTS_NAMED_STREAMS (1 << 3)
+#define HGFS_OPENV4_SUPPORTS_SHARED_ACCESS (1 << 4)
+#define HGFS_OPENV4_SUPPORTS_UNIX_PERMISSIONS (1 << 5)
+#define HGFS_OPENV4_POSIX_FILE_DELETION (1 << 6)
+
+/*
+ * There is a significant difference in byte range locking semantics between Windows
+ * and POSIX file systems. Windows implements mandatory locking which means that every
+ * read or write request that conflicts with byte range locks is rejected. POSIX has
+ * an advisory locking which means that locks are validated only when another lock is
+ * requested and are not enforced for read/write operations.
+ * Applications in guest OS may expect byte range locking semantics that matches guest
+ * OS which may be different from semantics that is natively supported by host OS. In
+ * this case either HGFS server or HGFS client should provide compensation for the host
+ * OS semantics to maintain application compatibility.
+ * Client must know if the server is capable to provide appropriate byte range locking
+ * semantics to perform some compensation on behalf of server when necessary.
+ *
+ * Following flags define various capabilities of byte range lock implementation on
+ * the host.
+ *
+ * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_64 means that server is capable of locking 64 bit
+ * length ranges.
+ * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_32 means that server is limited to 32-bit ranges.
+ * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_MANDATORY means that server is capable of enforcing
+ * read/write restrictions for locked ranges.
+ * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_ADVISORY means that server supports advisory locking;
+ * locks are validated only for other bytes
+ * range locking and are not enforced
+ * for read/write operations.
+ */
+typedef uint32 HgfsByteRangeLockingCapabilities;
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_64 (1 << 1)
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_32 (1 << 2)
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_MANDATORY (1 << 3)
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_ADVISORY (1 << 4)
+
+/* HGFS_SUPPORTS_HARD_LINKS is set when the host supports hard links. */
+typedef uint32 HgfsLinkMoveCapabilities;
+#define HGFS_SUPPORTS_HARD_LINKS (1 << 1)
+
+ /*
+ * HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS is set when host supports
+ * fine grain event reporting for directory notification.
+ */
+typedef uint32 HgfsSetWatchCapabilities;
+#define HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS (1 << 1)
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsCapability {
+ HgfsOp op; /* Op. */
+ uint32 flags; /* Flags. */
+}
+#include "vmware_pack_end.h"
+HgfsCapability;
+
+typedef HgfsFileName HgfsUserName;
+typedef HgfsFileName HgfsGroupName;
+
+/* Following structures describe user identity on the host which runs HGFS service. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsIdentity {
+ uint32 uid; /* user id. */
+ uint32 gid; /* Primary group id. */
+ HgfsUserName user; /* User name in form specified in RFC 3530. */
+ HgfsGroupName group; /* Group name in form specified in RFC 3530. */
+}
+#include "vmware_pack_end.h"
+HgfsIdentity;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestCreateSession {
+ uint32 numCapabilities; /* Number of capabilities to follow. */
+ uint32 maxPacketSize; /* Maximum packet size supported. */
+ uint64 reserved; /* Reserved for future use. */
+ HgfsCapability capabilities[1]; /* Array of HgfsCapabilities. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestCreateSession;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyCreateSession {
+ uint64 sessionId; /* Session ID. */
+ uint32 numCapabilities; /* Number of capabilities to follow. */
+ uint32 maxPacketSize; /* Maximum packet size supported. */
+ uint32 identityOffset; /* Offset to HgfsIdentity or 0 if no identity. */
+ uint64 reserved; /* Reserved for future use. */
+ HgfsCapability capabilities[1]; /* Array of HgfsCapabilities. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyCreateSession;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDestroySession {
+ uint64 sessionId; /* Session ID. */
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestDestroySession;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDestroySession {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyDestroySession;
+
+/* Adds new error status: HGFS_STATUS_INVALID_SESSION. */
+
+/*
+ * If file handle is used to set watch (HGFS_FILE_NAME_USE_FILE_DESC
+ * is set in the fileName), closing this handle implicitly removes the watch.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetWatch {
+ uint64 events; /* What events to watch? */
+ uint32 flags; /* Flags. */
+ uint64 reserved; /* Reserved for future use. */
+ HgfsFileNameV3 fileName; /* Filename to watch. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetWatch;
+
+/*
+ * Coarse grain notification event types.
+ */
+#define HGFS_ACTION_ADDED (1 << 0) /* File was added. */
+#define HGFS_ACTION_REMOVED (1 << 1) /* File was removed. */
+#define HGFS_ACTION_MODIFIED (1 << 2) /* File attributes were changed. */
+#define HGFS_ACTION_RENAMED (1 << 3) /* File was renamed. */
+
+/*
+ * Fine grain notification event types.
+ * HgfsRequestSetWatch events.
+ * Events marked with (*) apply only to directories.
+ */
+#define HGFS_NOTIFY_ACCESS (1 << 0) /* File accessed (read) */
+#define HGFS_NOTIFY_ATTRIB (1 << 1) /* Windows file attributes changed. */
+#define HGFS_NOTIFY_SIZE (1 << 2) /* File size changed. */
+#define HGFS_NOTIFY_ATIME (1 << 3) /* Access time changed. */
+#define HGFS_NOTIFY_MTIME (1 << 4) /* Modification time changed. */
+#define HGFS_NOTIFY_CTIME (1 << 5) /* Attribute change time changed. */
+#define HGFS_NOTIFY_CRTIME (1 << 6) /* Creation time changed. */
+#define HGFS_NOTIFY_NAME (1 << 7) /* File / Directory name changed. */
+#define HGFS_NOTIFY_OPEN (1 << 8) /* File opened */
+#define HGFS_NOTIFY_CLOSE_WRITE (1 << 9) /* File opened for writing closed */
+#define HGFS_NOTIFY_CLOSE_NOWRITE (1 << 10) /* File opened for reading closed */
+#define HGFS_NOTIFY_CREATE (1 << 11) /* File / directory created */
+#define HGFS_NOTIFY_DELETE (1 << 12) /* (*) File / directory deleted */
+#define HGFS_NOTIFY_DELETE_SELF (1 << 13) /* Watched file / directory deleted */
+#define HGFS_NOTIFY_MODIFY (1 << 14) /* File or directory modified. */
+#define HGFS_NOTIFY_MOVE_SELF (1 << 15) /* Watched file / directory moved. */
+#define HGFS_NOTIFY_MOVE_FROM (1 << 16) /* (*) Moved out of watched directory. */
+#define HGFS_NOTIFY_MOVE_TO (1 << 17) /* (*) Moved into watched directory. */
+#define HGFS_NOTIFY_RENAME (1 << 18) /* File / directory name changed. */
+
+/* HgfsRequestSetWatch flags. */
+#define HGFS_NOTIFY_FLAG_WATCH_TREE (1 << 0) /* Watch the entire directory tree. */
+#define HGFS_NOTIFY_FLAG_DONT_FOLLOW (1 << 1) /* Don't follow symlinks. */
+#define HGFS_NOTIFY_FLAG_ONE_SHOT (1 << 2) /* Generate only one notification. */
+#define HGFS_NOTIFY_FLAG_POSIX_HINT (1 << 3) /* Client is POSIX and thus expects
+ * fine grain notification. Server
+ * may provide coarse grain
+ * notification even if this flag is
+ * set.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetWatch {
+ HgfsHandle watchId; /* Watch identifier for subsequent references. */
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetWatch;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestRemoveWatch {
+ HgfsHandle watchId; /* Watch identifier to remove. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestRemoveWatch;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyRemoveWatch {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyRemoveWatch;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsNotifyEvent {
+ uint32 nextOffset; /* Offset of next event; 0 if it i sthe last one. */
+ uint64 mask; /* Event occurred. */
+ uint64 reserved; /* Reserved for future use. */
+ HgfsFileName fileName; /* Filename. */
+ HgfsFileName oldName; /* New filename for rename operation. */
+}
+#include "vmware_pack_end.h"
+HgfsNotifyEvent;
+
+/* Too many events, some or all event were dropped by the server. */
+#define HGFS_NOTIFY_FLAG_OVERFLOW (1 << 0)
+/* Watch had been removed either explicitly or implicitly. */
+#define HGFS_NOTIFY_FLAG_REMOVED (1 << 1)
+/* Server generated coasrse grain events. */
+#define HGFS_NOTIFY_FLAG_COARSE_GRAIN (1 << 2)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestNotify {
+ HgfsHandle watchId; /* Watch identifier. */
+ uint32 flags; /* Various flags. */
+ uint32 count; /* Number of events occured. */
+ uint64 reserved; /* Reserved for future use. */
+ HgfsNotifyEvent events[1]; /* Events. HgfsNotifyEvent(s). */
+}
+#include "vmware_pack_end.h"
+HgfsRequestNotify;
+
+// Query EA flags values.
+#define HGFS_QUERY_EA_INDEX_SPECIFIED (1 << 0)
+#define HGFS_QUERY_EA_SINGLE_ENTRY (1 << 1)
+#define HGFS_QUERY_EA_RESTART_SCAN (1 << 2)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestQueryEA {
+ uint32 flags; /* EA flags. */
+ uint32 index;
+ uint64 reserved; /* Reserved for future use. */
+ uint32 eaNameLength; /* EA name length. */
+ uint32 eaNameOffset; /* Offset of the eaName field. */
+ HgfsFileNameV3 fileName; /* File to watch. */
+ char eaNames[1]; /* List of NULL terminated EA names.
+ * Actual location of the data depends on
+ * fileName length and defined by eaNameOffset.
+ */
+}
+#include "vmware_pack_end.h"
+HgfsRequestQueryEA;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyQueryEA {
+ uint32 nextOffset; /* Offset of the next structure when more then
+ * one record is returned.
+ */
+ uint32 flags; /* EA flags. */
+ uint32 index; /* Index needed to resume scan. */
+ uint64 reserved; /* Reserved for future use. */
+ uint32 eaDataLength; /* EA value length. */
+ char eaData[1]; /* NULL termianed EA name followed by EA value. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyQueryEA;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsEA {
+ uint32 nextOffset; /* Offset of the next structure in the chain. */
+ uint32 valueLength; /* EA value length. */
+ char data[1]; /* NULL terminated EA name followed by EA value. */
+}
+#include "vmware_pack_end.h"
+HgfsEA;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetEA {
+ uint32 flags; /* Flags, see below. */
+ uint64 reserved; /* Reserved for future use. */
+ uint32 numEAs; /* Number of EAs in this request. */
+ HgfsEA attributes[1]; /* Array of attributes. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetEA;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetEA {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetEA;
+
+/*
+ * EA Flags. When both flags are set EA is either created or replaced if it exists.
+ * HGFS_EA_FLAG_CREATE - create if EA is not present, error otherwise.
+ * HGFS_EA_FLAG_REPLACE - Replace exisitng EA. Error if EA not already present.
+ */
+#define HGFS_EA_FLAG_CREATE (1 << 0)
+#define HGFS_EA_FLAG_REPLACE (1 << 1)
+
+/*
+ * Byte range lock flag values:
+ * HGFS_RANGE_LOCK_EXCLUSIVE - Requested lock is exclusive when this flag is set,
+ * otherwise it is a shared lock.
+ * HGFS_RANGE_LOCK_FAIL_IMMEDIATLY - If the flag is not set server waits until the
+ * lock becomes available.
+ */
+#define HGFS_RANGE_LOCK_EXCLUSIVE (1 << 0)
+#define HGFS_RANGE_LOCK_FAIL_IMMEDIATLY (1 << 1)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestLockRange {
+ HgfsHandle fid; /* File to take lock on. */
+ uint32 flags; /* Various flags. */
+ uint64 start; /* Starting offset in the file. */
+ uint64 length; /* Number of bytes to lock. */
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestLockRange;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyLockRange {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyLockRange;
+
+#define HGFS_RANGE_LOCK_UNLOCK_ALL (1 << 0)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestUnlockRange {
+ HgfsHandle fid; /* File to take lock on. */
+ uint32 flags; /* Various flags. */
+ uint64 start; /* Starting offset in the file. */
+ uint64 length; /* Number of bytes to lock. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestUnlockRange;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyUnlockRange {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyUnlockRange;
+
+/*
+ * There are three types of oplocks: level 1, batch, and level 2. Both the level 1 and
+ * batch oplocks are "exclusive access" opens. They are used slightly differently,
+ * however, and hence have somewhat different semantics. A level 2 oplock is a "shared
+ * access" grant on the file.
+ * Level 1 is used by a remote client that wishes to modify the data. Once granted a
+ * Level 1 oplock, the remote client may cache the data, modify the data in its cache
+ * and need not write it back to the server immediately.
+ * Batch oplocks are used by remote clients for accessing script files where the file is
+ * opened, read or written, and then closed repeatedly. Thus, a batch oplock
+ * corresponds not to a particular application opening the file, but rather to a remote
+ * clients network file system caching the file because it knows something about the
+ * semantics of the given file access. The name "batch" comes from the fact that this
+ * behavior was observed by Microsoft with "batch files" being processed by command line
+ * utilities. Log files especially exhibit this behavior when a script it being
+ * processed each command is executed in turn. If the output of the script is redirected
+ * to a log file the file fits the pattern described earlier, namely open/write/close.
+ * With many lines in a file this pattern can be repeated hundreds of times.
+ * Level 2 is used by a remote client that merely wishes to read the data. Once granted
+ * a Level 2 oplock, the remote client may cache the data and need not worry that the
+ * data on the remote file server will change without it being advised of that change.
+ * An oplock must be broken whenever the cache consistency guarantee provided by the
+ * oplock can no longer be provided. Thus, whenever a second network client attempts to
+ * access data in the same file across the network, the file server is responsible for
+ * "breaking" the oplocks and only then allowing the remote client to access the file.
+ * This ensures that the data is guaranteed to be consistent and hence we have preserved
+ * the consistency guarantees essential to proper operation.
+ *
+ * HGFS_OPLOCK_NONE: no oplock. No caching on client side.
+ * HGFS_OPLOCK_SHARED: shared (or LEVEL II) oplock. Read caching is allowed.
+ * HGFS_OPLOCK_EXCLUSIVE: exclusive (or LEVEL I) oplock. Read/write caching is allowed.
+ * HGFS_OPLOCK_BATCH: batch oplock. Read/Write and Open caching is allowed.
+ */
+
+typedef enum {
+ HGFS_OPLOCK_NONE,
+ HGFS_OPLOCK_SHARED,
+ HGFS_OPLOCK_EXCLUSIVE,
+ HGFS_OPLOCK_BATCH,
+} HgfsOpportunisticLock;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestServerLockChangeV2 {
+ HgfsHandle fid; /* File to take lock on. */
+ HgfsOpportunisticLock serverLock; /* Lock type. */
+ uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsRequestServerLockChangeV2;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyServerLockChangeV2 {
+ HgfsOpportunisticLock serverLock; /* Lock granted. */
+ uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyServerLockChangeV2;
+
+/*
+ * This request is sent from server to the client to notify that oplock
+ * is revoked or downgraded.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOplockBreakV4 {
+ HgfsHandle fid; /* File handle. */
+ HgfsOpportunisticLock serverLock; /* Lock downgraded to this type. */
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestOplockBreakV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOplockBreakV4 {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOplockBreakV4;
+
+/*
+ * Flusing of a whole volume is not supported.
+ * Flusing of reqular files is supported on all hosts.
+ * Flusing of directories is supproted on POSIX hosts and is
+ * NOOP on Windows hosts.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestFsyncV4 {
+ HgfsHandle fid; /* File to sync. */
+ uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsRequestFsyncV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyFsyncV4 {
+ uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyFsyncV4;
+
+/*
+ * This request is name based only.
+ * Server fails this request if HGFS_FILE_E_USE_FILE_DESC is set in the fileName.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestAccessCheckV4 {
+ HgfsFileNameV3 fileName; /* File concerned. */
+ HgfsPermissions perms; /* Permissions to check for. */
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestAccessCheckV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyAccessCheckV4 {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyAccessCheckV4;
+
+/*
+ * Additional HgfsPersmissions type: checks file existense without
+ * requesting any particular access.
+ * Matches F_OK mode parameter for POSIX access (2) API.
+ */
+#define HGFS_PERM_EXISTS 8
+
+/*
+ * HGFS_PLATFORM_ALL is a HGFS specific platform independent FSCTL
+ * that correspond to different OS specific codes.
+ * Other types of FSCTL are platform specific to allow better user
+ * experience when guest and host OS are the same. HGFS does not interpret
+ * platform specific FSCTL in any way, it just passes it through to the
+ * host. If the host run appropriate OS it executes FSCTL on user's behalf,
+ * otherwise it fails the request.
+ */
+typedef enum HgfsPlatformType {
+ HGFS_PLATFORM_ALL,
+ HGFS_PLATFORM_WINDOWS,
+ HGFS_PLATFORM_LINUX,
+ HGFS_PLATFORM_MAC
+}HgfsPlatformType;
+
+#define HGFS_FSCTL_SET_SPARSE 1 /* Platform independent FSCTL to make file sparse. */
+
+/* Platform together with the code define exact meaning of the operation. */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestFsctlV4 {
+ HgfsHandle fid;
+ uint32 code;
+ HgfsPlatformType platform;
+ uint32 dataLength;
+ char data[1];
+}
+#include "vmware_pack_end.h"
+HgfsRequestFsctlV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyFsctlV4 {
+ uint32 dataLength;
+ char data[1];
+}
+#include "vmware_pack_end.h"
+HgfsReplyFsctlV4;
+
+/*
+ * Creating a new file or reading file attributes involves ACL. There is a good
+ * definition of multi-platform ACLs in RFC 3530, section 5.11. HGFS should use
+ * ACLs defined in this document (http://tools.ietf.org/html/rfc3530#section-5.11).
+ * ACL support is not mandatory. If a request to create file with ACL comes to a host
+ * that does not support ACL, the request should succeed and setting ACL is ignored.
+ * Such behavior is consistent with other file systems.
+ */
+typedef uint64 HgfsOpenCreateOptions;
+
+/* O_SYMLINK in Mac OS or FILE_FLAG_OPEN_REPARSE_POINT in Windows. */
+#define HGFS_OPENCREATE_OPTION_SYMLINK (1 << 0)
+/* O_SHLOCK in Mac OS or obtain shared range lock for the whole file. */
+#define HGFS_OPENCREATE_OPTION_SHLOCK (1 << 1)
+/* O_EXLOCK in Mac OS or obtain exclusive range lock for the whole file. */
+#define HGFS_OPENCREATE_OPTION_EXLOCK (1 << 2)
+/* O_SYNC in Linux, ignored in Mac, FILE_FLAG_WRITE_THROUGH in Windows. */
+#define HGFS_OPENCREATE_OPTION_WRITETHROUGH (1 << 3)
+/* FILE_FLAG_NO_BUFFERING in Windows, O_SYNC in Linux, ignored on Mac OS. */
+#define HGFS_OPENCREATE_OPTION_NO_BUFERING (1 << 4)
+/*
+ * O_NOFOLLOW in POSIX. Windows server checks for reparse point
+ * and fails the request if file has one.
+ */
+#define HGFS_OPENCREATE_OPTION_NO_FOLLOW (1 << 5)
+/* FILE_FLAG_NO_RECALL in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_NO_RECALL (1 << 6)
+/* FILE_FLAG_RANDOM_ACCESS in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_RANDOM (1 << 7)
+/* FILE_FLAG_SEQUENTIAL_SCAN in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_SEQUENTIAL (1 << 8)
+/* FILE_FLAG_BACKUP_SEMANTICS in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_BACKUP_SEMANTICS (1 << 9)
+/* Fail opening if the file already exists and it is not a directory. */
+#define HGFS_OPENCREATE_OPTION_DIRECTORY (1 << 10)
+/* Fail opening if the file already exists and it is a directory. */
+#define HGFS_OPENCREATE_OPTION_NON_DIRECTORY (1 << 11)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOpenV4 {
+ HgfsOpenValid mask; /* Bitmask that specified which fields are valid. */
+ HgfsOpenMode mode; /* Which type of access requested. See desiredAccess */
+ HgfsOpenFlags flags; /* Which flags to open the file with */
+ HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */
+ HgfsPermissions ownerPerms; /* Desired 'owner' permissions for file creation */
+ HgfsPermissions groupPerms; /* Desired 'group' permissions for file creation */
+ HgfsPermissions otherPerms; /* Desired 'other' permissions for file creation */
+ HgfsAttrFlags attr; /* Attributes, if any, for file creation */
+ uint64 allocationSize; /* How much space to pre-allocate during creation */
+ uint32 desiredAccess; /* Extended support for windows access modes */
+ uint32 shareAccess; /* Windows only, share access modes */
+ HgfsOpenCreateOptions createOptions; /* Various options. */
+ HgfsOpportunisticLock requestedLock; /* The type of lock desired by the client */
+ HgfsFileNameV3 fileName; /* fid can be used only for relative open,
+ * i.e. to open named stream.
+ */
+ HgfsFileName streamName; /* Name of the alternative named stream.
+ * All flags are the same as defined in fileName.
+ * The name is used in conjuction with fileName
+ * field, for example if Windows opens file
+ * "abc.txt:stream" then fileName contains
+ * "abc.txt" and streamName contains "stream"
+ */
+ /*
+ * EA to set if the file is created or overwritten. The parameter should be ignored
+ * if the file already exists.
+ * It is needed to correctly implement Windows semantics for opening files.
+ * It should work atomically - failure to add EA should result in failure to create
+ * the new file.
+ * If the host file system does not support EA server should fail the request rather
+ * then succeeding and silently dropping EA.
+ */
+ HgfsRequestSetEA extendedAttributes;
+ uint32 aclLength; /* Length of the acl field. */
+ char acl[1]; /* Multi-platform ACL as defined in RFC 3530. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestOpenV4;
+
+typedef enum HgfsOpenResult {
+ HGFS_FILE_OPENED,
+ HGFS_FILE_CREATED,
+ HGFS_FILE_OVERWRITTEN,
+ HGFS_FILE_SUPERSIDED,
+ } HgfsOpenResult;
+
+/*
+ * Win32 API has a special value for the desired access - MAXIMUM_ALLOWED.
+ * Such desired access means that file system must grant as much rights for the file
+ * as it is allowed for the current user.
+ * HGFS client must know what access rights were granted to properly communicate this
+ * information to the IoManager; grantedAccess field is used for this purpose.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOpenV4 {
+ HgfsHandle file; /* Opaque file ID used by the server */
+ HgfsOpportunisticLock grantedLock; /* The type of lock acquired by the server */
+ HgfsOpenResult openResult; /* Opened/overwritten or a new file created? */
+ uint32 grantedAccess; /* Granted access rights. */
+ uint64 fileId; /* Persistent volume-wide unique file id. */
+ uint64 volumeId; /* Persistent unique volume id. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOpenV4;
+
+/*
+ * Flags that define behaviour of the move/creating hard link operation.
+ */
+typedef uint64 HgfsMoveLinkFlags;
+
+#define HGFS_LINKMOVE_FLAG_REPLACE_EXISTING (1 << 0) /* Delete existing target. */
+#define HGFS_LINKMOVE_FLAG_HARD_LINK (1 << 1) /* Create hard link. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestLinkMoveV4 {
+ HgfsFileNameV3 oldFileName; /* Path to the exisitng source file.*/
+ HgfsFileNameV3 newFileName; /* Path to the destinatio name.*/
+ HgfsMoveLinkFlags flags; /* Flags that define behaviour of the operation.*/
+}
+#include "vmware_pack_end.h"
+HgfsRequestLinkMoveV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyLinkMove4 {
+ uint64 reserved; /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyLinkMove4;
+
+/*
+ * HgfsQueryVolumeMaskV4 mask in a request defines which volume properties client needs;
+ * mask in a reply defines which properties were actually returned by the host.
+ *
+ * HGFS_QUERY_VOLUME_MASK_SIZE controls totalBytes, freeBytes and availableBytes.
+ * HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES controls capabilities.
+ * HGFS_QUERY_VOLUME_MASK_ATTRIBUTES controls creationTime.
+ * HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY controls bytesPerSector and sectorPerCluster.
+ * HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL controls volume label.
+ * HGFS_QUERY_VOLUME_MASK_FS_NAME controls fileSystemName.
+ */
+typedef uint64 HgfsQueryVolumeMaskV4;
+
+#define HGFS_QUERY_VOLUME_MASK_SIZE (1 << 0)
+#define HGFS_QUERY_VOLUME_MASK_ATTRIBUTES (1 << 1)
+#define HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES (1 << 2)
+#define HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL (1 << 3)
+#define HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY (1 << 4)
+#define HGFS_QUERY_VOLUME_MASK_FS_NAME (1 << 5)
+
+typedef uint64 HgfsFileSystemCapabilities;
+#define HGFS_VOLUME_CASE_SENSITIVE (1 << 0)
+#define HGFS_VOLUME_SUPPORTS_EA (1 << 1)
+#define HGFS_VOLUME_SUPPORTS_COMPRESSION (1 << 2)
+#define HGFS_VOLUME_SUPPORTS_SHORT_NAMES (1 << 3)
+#define HGFS_VOLUME_SUPPORTS_ACL (1 << 4)
+#define HGFS_VOLUME_READ_ONLY (1 << 5)
+#define HGFS_VOLUME_SUPPORTS_ENCRYPTION (1 << 6)
+#define HGFS_VOLUME_SUPPORTS_OBJECT_ID (1 << 7)
+#define HGFS_VOLUME_SUPPORTS_REMOTE_STORAGE (1 << 8)
+#define HGFS_VOLUME_SUPPORTS_SYMLINKS (1 << 9)
+#define HGFS_VOLUME_SUPPORTS_SPARSE_FILES (1 << 10)
+#define HGFS_VOLUME_SUPPORTS_UNICODE (1 << 11)
+#define HGFS_VOLUME_SUPPORTS_QUOTA (1 << 12)
+#define HGFS_VOLUME_SUPPORTS_NAMED_STREAMS (1 << 13)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestQueryVolumeV4 {
+ HgfsQueryVolumeMaskV4 mask;
+ HgfsFileNameV3 name;
+}
+#include "vmware_pack_end.h"
+HgfsRequestQueryVolumeV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyQueryVolumeV4 {
+ HgfsQueryVolumeMaskV4 mask; /* Identifies which values were set by the host. */
+ uint64 totalBytes; /* Total volume capacity. */
+ uint64 freeBytes; /* Free space on the volume. */
+ uint64 availableBytes; /* Free space available for the user. */
+ HgfsFileSystemCapabilities capabilities; /* File system capabilities. */
+ uint64 creationTime; /* Volume creation time. */
+ uint32 bytesPerSector; /* Sector size for the volume. */
+ uint32 sectorsPerCluster; /* Cluster size for the volume. */
+ HgfsFileName volumeLabel; /* Volume name or label. */
+ HgfsFileName fileSystemName;/* File system name. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyQueryVolumeV4;
+
+typedef uint32 HgfsDirectoryReadMaskV4;
+#define HGFS_DIRECTORY_READ_NAME (1 << 0)
+#define HGFS_DIRECTORY_READ_SHORT_NAME (1 << 1)
+#define HGFS_DIRECTORY_READ_FILE_SIZE (1 << 2)
+#define HGFS_DIRECTORY_READ_ALLOCATION_SIZE (1 << 3)
+#define HGFS_DIRECTORY_READ_EA_SIZE (1 << 4)
+#define HGFS_DIRECTORY_READ_TIME_STAMP (1 << 5)
+#define HGFS_DIRECTORY_READ_FILE_ATTRIBUTES (1 << 6)
+#define HGFS_DIRECTORY_READ_FILE_NODE_TYPE (1 << 7)
+
+typedef uint32 HgfsDirectoryReadFlagsV4;
+#define HGFS_DIRECTORY_READ_INITIAL_QUERY (1 << 1)
+#define HGFS_DIRECTORY_READ_SINGLE_ENTRY (1 << 2)
+
+/*
+ * Read directory request can be used to enumerate files in a directory.
+ * File handle used in the request must be returned by HgfsRequestOpenV4 or later.
+ * searchPattern parameter allows filter out file names in the server for optimization.
+ * It is optional - host may ignore patterns and return entries that do not match
+ * the pattern. It is client responsibility to filter out names that do not match
+ * the pattern.
+ *
+ * The mask field in request allows client to specify which properties it is
+ * interested in. It allows to implement optimization in the server by skipping
+ * parameters which client does not need.
+ *
+ * Service fills mask field in the reply buffer to specify which of the requested
+ * properties it supports, which may be a subset of requested properties.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestReadDirectoryV4 {
+ HgfsDirectoryReadMaskV4 mask;
+ HgfsDirectoryReadFlagsV4 flags;
+ HgfsHandle fid;
+ uint32 restartIndex;
+ HgfsFileName searchPattern;
+}
+#include "vmware_pack_end.h"
+HgfsRequestReadDirectoryV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsDirectoryEntryV4 {
+ uint32 nextEntryOffset;
+ uint32 fileIndex;
+ HgfsAttrFlags attributes;
+ HgfsFileType fileType;
+ uint64 fileSize;
+ uint64 allocationSize;
+ uint64 creationTime;
+ uint64 accessTime;
+ uint64 modificationTime;
+ uint64 changeAttributesTime;
+ uint32 eaSize;
+ HgfsFileName shortName;
+ HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsDirectoryEntryV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyReadDirectoryV4 {
+ uint32 numberEntriesReturned;
+ uint32 offsetToContinue;
+ HgfsDirectoryReadMaskV4 mask; /* Returned mask that may be a subset of requested mask. */
+ HgfsDirectoryEntryV4 entries[1];
+}
+#include "vmware_pack_end.h"
+HgfsReplyReadDirectoryV4;
+
+/*
+ * File handle returned by HgfsRequestOpenV4 or later. Descriptors returned by
+ * HgfsHandle fid; earlier versions of HgfsRequestOpen are not supported.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestEnumerateStreamsV4 {
+ uint32 restartIndex;
+}
+#include "vmware_pack_end.h"
+HgfsRequestEnumerateStreamsV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestStreamEntryV4 {
+ uint32 nextEntryOffset;
+ uint32 fileIndex;
+ HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestStreamEntryV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestGetAttrV4 {
+ uint32 mask;
+ uint32 flags;
+ HgfsFileNameV3 name;
+}
+#include "vmware_pack_end.h"
+HgfsRequestGetAttrV4;
+
+/*
+ * V4 reports different file size for symlinks then V3 or V2.
+ * It does not return file name length as EOF - it reports actual EOF.
+ * On POSIX the value is always 0 and on Windows it is an actual EOF of
+ * a file with a reparse point.
+ * Each client must adjust the value for file size according to guest OS rules.
+ *
+ * Mask in HgfsAttr2V2 should be extended to include short name, symlink target and ACL.
+ * If the host does not support a requested feature it is free to clear the
+ * correspondent bit in the mask and ignore the feature.
+ *
+ * Multi-platform notice: symbolic link is represented by a file with REPARSE_POINT
+ * on Windows. Thus Windows supports swtiching a file type between
+ * regular or directory => symlink and back.
+ * Setting symlinkTarget attribute on Windows host results in assigning
+ * reparse point to the host file.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsAttrV4 {
+ HgfsAttrV2 attr;
+ uint32 numberOfLinks;
+ HgfsFileName shortName;
+ HgfsFileName symlinkTarget;
+ uint32 aclLength;
+ char acl[1];
+}
+#include "vmware_pack_end.h"
+HgfsAttrV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyGetAttrV4 {
+ HgfsAttrV4 attr;
+}
+#include "vmware_pack_end.h"
+HgfsReplyGetAttrV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetAttrV4 {
+ uint32 mask; /* Defines which attributes were set. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetAttrV4;
+
+/*
+ * Unlike V3 deletion this command can be used to delete both files and directories.
+ * Its semantics depends on whether fid or file path is specified in the fileName.
+ * When path is used it implements/emulates POSIX semantics - name is deleted from
+ * the directory however if the file is opened it is still accessible. When fid is used
+ * the file name disappears from the folder only when the last handle for the file is
+ * closed - Windows style deletion.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDeleteFileV4 {
+ HgfsFileNameV3 fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestDeleteFileV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDeleteFileV4 {
+ uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyDeleteFileV4;
#endif /* _HGFS_PROTO_H_ */
Bool
HgfsServerPolicy_IsShareOptionSet(HgfsShareOptions shareOptions, // IN: Config options
uint32 option); // IN: Option to check
+HgfsNameStatus
+HgfsServerPolicy_ProcessCPName(char const *nameIn, // IN: name in CPName form
+ size_t nameInLen, // IN: length of the name
+ Bool *readAccess, // OUT: Read permissions
+ Bool *writeAccess, // OUT: Write permissions
+ char const **shareBaseDir); // OUT: Shared directory
void
HgfsServerPolicy_FreeShareList(HgfsServerPolicy_ShareList *shareList); // IN: list to free
HgfsServerPolicy_ShareList *
HgfsServerPolicy_GetSharesWithTag(const char *tag); // IN: tag to search for
+Bool
+HgfsServerPolicy_CheckMode(HgfsOpenMode mode, // IN: mode to check
+ Bool writePermissions, // IN: callers write permissions
+ Bool readPermissions); // IN: callers read permissions
+
#endif // _HGFS_SERVER_POLICY_H_
#endif
extern Bool Hostinfo_TouchBackDoor(void);
extern Bool Hostinfo_TouchXen(void);
+extern char *Hostinfo_HypervisorCPUIDSig(void);
#define HGMP_PRIVILEGE 0
#define HGMP_NO_PRIVILEGE 1
void Hostinfo_LogLoadAverage(void);
Bool Hostinfo_GetLoadAverage(uint32 *l);
+#ifdef __APPLE__
+size_t Hostinfo_GetKernelZoneElemSize(char const *name);
+#endif
#endif /* ifndef _HOSTINFO_H_ */
const unsigned char *imageData,
size_t dataLen,
int pngReadFlags);
-EXTERN Bool ImageUtil_ConstructPNGBuffer(const ImageInfo *image, DynBuf *imageData);
-EXTERN Bool ImageUtil_ConstructPNGBufferEx(const ImageInfo *image,
- const ImagePngWriteOptions *options,
- DynBuf *imageData);
+EXTERN Bool ImageUtil_ConstructPNGBuffer(const ImageInfo *image,
+ const ImagePngWriteOptions *options,
+ DynBuf *imageData);
EXTERN Bool ImageUtil_ConstructBMPBuffer(const ImageInfo *image, DynBuf *imageData);
-EXTERN Bool ImageUtil_ConstructBuffer(const ImageInfo *image, ImageType imageType,
- DynBuf *imageData);
+
EXTERN void ImageUtil_FreeImageData(ImageInfo *image);
EXTERN Bool ImageUtil_Combine(const ImageInfo *images, const VMPoint *origins,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*********************************************************/
-
+
#ifndef _LOGLEVEL_USER_H_
#define _LOGLEVEL_USER_H_
LOGLEVEL_VAR(usb), \
LOGLEVEL_VAR(vusbmouse), \
LOGLEVEL_VAR(vusbkeyboard), \
+ LOGLEVEL_VAR(vusbhid), \
LOGLEVEL_VAR(hidQueue), \
LOGLEVEL_VAR(pci_1394), \
LOGLEVEL_VAR(1394), \
LOGLEVEL_VAR(brtalk), /* macWireless and wpa_supplicant */ \
LOGLEVEL_VAR(button), \
LOGLEVEL_VAR(util), \
- LOGLEVEL_VAR(largepage),
+ LOGLEVEL_VAR(largepage), \
+ LOGLEVEL_VAR(guestAppMonitor),
LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER);
-#endif /* _LOGLEVEL_USER_H_ */
+#endif /* _LOGLEVEL_USER_H_ */
#define __NETUTIL_H__
#ifdef _WIN32
-#include <winsock2.h>
-#include <iphlpapi.h>
-#include <windows.h>
+/*
+ * Redefine the WINNT version for this file to be 'LONGHORN' so that we'll get
+ * the definitions for MIB_IPFORWARDTABLE2 et. al.
+ */
+# if (_WIN32_WINNT < 0x0600)
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x0600
+# endif
+
+# include <windows.h>
+# include <ws2tcpip.h>
+# include "vmware/iphlpapi_packed.h"
+#else
+# include <arpa/inet.h>
#endif
#include "vm_basic_types.h"
# include "guestInfo.h"
#endif
+/*
+ * Interface types as assigned by IANA.
+ * See http://www.iana.org/assignments/ianaiftype-mib for more details.
+ */
+
+typedef enum {
+ IANA_IFTYPE_OTHER = 1,
+ IANA_IFTYPE_ETHERNETCSMACD = 6,
+} IanaIfType;
+
/*
* Modified from iptypes.h...
PIP_ADAPTER_ADDRESSES adap_addresses,
PULONG SizePointer);
+PMIB_IPFORWARDTABLE NetUtilWin32_GetIpForwardTable(void);
+PMIB_IPFORWARD_TABLE2 NetUtilWin32_GetIpForwardTable2(void);
+void NetUtilWin32_FreeMibTable(PMIB_IPFORWARD_TABLE2);
#endif
#ifdef N_PLAT_NLM
void NetUtil_MonitorIPStop(void);
#endif
+#ifdef WIN32
+int NetUtil_InetPToN(int af, const char *src, void *dst);
+const char *NetUtil_InetNToP(int af, const void *src, char *dst,
+ socklen_t size);
+#else // ifdef WIN32
+# define NetUtil_InetPToN inet_pton
+# define NetUtil_InetNToP inet_ntop
+#endif
+
#if defined(linux)
# ifdef DUMMY_NETUTIL
/*
int NetUtil_GetIfIndex(const char *ifName);
char *NetUtil_GetIfName(int ifIndex);
-
#endif // if defined(linux)
-#endif
+size_t NetUtil_GetHardwareAddress(int ifIndex, // IN
+ char *hwAddr, // OUT
+ size_t hwAddrSize, // IN
+ IanaIfType *ifType); // OUT
+
+#endif // ifndef _NETUTIL_H_
extern double Preference_GetDouble(double defaultValue, const char *fmt);
extern char *Preference_GetString(const char *defaultValue, const char *fmt);
extern char *Preference_GetStringPlain(const char *defaultValue, const char *fmt);
+extern char *Preference_GetStringEnum(const void *defaultValue,
+ const char **choices,
+ const char *name);
extern int32 Preference_Generation(void);
extern void Preference_Log(void);
extern char *Preference_GetPathName(const char *defaultValue, const char *fmt);
#error Use safetime.h instead of time.h, stat.h, and types.h
#endif
+#undef FMTTIME
+#define FMTTIME FMT64"d"
+
#if (_MSC_VER < 1400)
#define _STAT_DEFINED
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file slashProc.h
+ */
+
+#ifndef _SLASHPROC_H_
+#define _SLASHPROC_H_
+
+#include <glib.h>
+#include <net/route.h>
+
+
+/*
+ * Global functions
+ */
+
+
+EXTERN GHashTable *SlashProcNet_GetSnmp(void);
+EXTERN GHashTable *SlashProcNet_GetSnmp6(void);
+
+EXTERN GPtrArray *SlashProcNet_GetRoute(void);
+EXTERN void SlashProcNet_FreeRoute(GPtrArray *);
+
+EXTERN GPtrArray *SlashProcNet_GetRoute6(void);
+EXTERN void SlashProcNet_FreeRoute6(GPtrArray *);
+
+#endif // ifndef _SLASHPROC_H_
BOOL System_SetProcessPrivilege(LPCTSTR lpszPrivilege, Bool bEnablePrivilege);
int32 System_GetSPVersion(void);
Bool System_IsLoginScreenActive(void);
+Bool System_IsProcessElevated(void);
Bool System_IsScreenSaverActive(void);
Bool System_IsScreenSaverRunning(void);
Bool System_StartDesktopSwitchThread(DesktopSwitchThreadArgs *args);
#define UNITY_RPC_DESKTOP_CONFIG_SET "unity.desktop.config.set"
#define UNITY_RPC_DESKTOP_ACTIVE_SET "unity.desktop.active.set"
#define UNITY_RPC_WINDOW_DESKTOP_SET "unity.window.desktop.set"
+#define UNITY_RPC_WINDOW_STICK "unity.window.stick"
+#define UNITY_RPC_WINDOW_UNSTICK "unity.window.unstick"
#define GHI_RPC_GUEST_SHELL_ACTION "ghi.guest.shell.action"
#define GHI_RPC_SET_GUEST_HANDLER "ghi.guest.handler.set"
@param[in] UnityWindowId UnityWindowId of window to move
@param[in] offset Offset into desktop configuration, as defined by
@ref UNITY_RPC_DESKTOP_CONFIG_SET, 0 or greater.
+
+
+ @def UNITY_RPC_WINDOW_STICK
+ @brief "Stick" a window to the screen.
+ @code
+ UNITY_RPC_WINDOW_STICK UnityWindowId
+ @endcode
+ @param[in] UnityWindowId UnityWindowId of window to stick.
+
+ @def UNITY_RPC_WINDOW_UNSTICK
+ @brief "Unstick" a window from the screen.
+ @code
+ UNITY_RPC_WINDOW_UNSTICK UnityWindowId
+ @endcode
+ @param[in] UnityWindowId UnityWindowId of window to unstick.
+
@}
*/
#endif // __APPLE__
-EXTERN uint32 CRC_Compute(uint8 *buf, int len);
-EXTERN uint32 Util_Checksum32(uint32 *buf, int len);
-EXTERN uint32 Util_Checksum(uint8 *buf, int len);
+EXTERN uint32 CRC_Compute(const uint8 *buf, int len);
+EXTERN uint32 Util_Checksum32(const uint32 *buf, int len);
+EXTERN uint32 Util_Checksum(const uint8 *buf, int len);
EXTERN uint32 Util_Checksumv(void *iov, int numEntries);
EXTERN Unicode Util_ExpandString(ConstUnicode fileName);
EXTERN void Util_ExitThread(int);
}
static INLINE_SINGLE_CALLER uint32
-UtilCRCUpdate(uint32 crc, uint8 *buf, int len)
+UtilCRCUpdate(uint32 crc, const uint8 *buf, int len)
{
uint32 c = crc;
int n;
*----------------------------------------------------------------------
*/
uint32
-CRC_Compute(uint8 *buf, int len)
+CRC_Compute(const uint8 *buf, int len)
{
return UtilCRCUpdate(0xffffffffL, buf, len) ^ 0xffffffffL;
}
VIX_E_NEED_KEY = 30,
VIX_E_LICENSE = 32,
VIX_E_VM_HOST_DISCONNECTED = 34,
+ VIX_E_AUTHENTICATION_FAIL = 35,
/* Handle Errors */
VIX_E_INVALID_HANDLE = 1000,
VIX_PROPERTY_SNAPSHOT_POWERSTATE = 4205,
VIX_PROPERTY_SNAPSHOT_IS_REPLAYABLE = 4207,
+ VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH = 4525,
+
+ /* Virtual machine encryption properties */
+ VIX_PROPERTY_VM_ENCRYPTION_PASSWORD = 7001,
};
/*
enum {
VIX_INSTALLTOOLS_MOUNT_TOOLS_INSTALLER = 0x00,
- VIX_INSTALLTOOLS_AUTO_UPGRADE = 0x01
+ VIX_INSTALLTOOLS_AUTO_UPGRADE = 0x01,
+ VIX_INSTALLTOOLS_RETURN_IMMEDIATELY = 0x02
};
VixHandle VixVM_InstallTools(VixHandle vmHandle,
VIX_REQUESTMSG_RETURN_ON_INITIATING_TOOLS_UPGRADE = 0x02,
VIX_REQUESTMSG_RUN_IN_ANY_VMX_STATE = 0x04,
VIX_REQUESTMSG_REQUIRES_INTERACTIVE_ENVIRONMENT = 0x08,
+ VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 = 0x10,
};
VixMsgSetVMStateRequest;
+typedef
+#include "vmware_pack_begin.h"
+struct VixMsgAuthDataV1 {
+ int64 nonce;
+ uint32 sequenceNumber;
+ uint8 hashValue[32];
+}
+#include "vmware_pack_end.h"
+VixMsgAuthDataV1;
VixCommandMakeSessionKeyResponse;
+typedef
+#include "vmware_pack_begin.h"
+struct VixCommandGenerateNonceResponse {
+ VixCommandResponseHeader header;
+
+ int64 nonce;
+}
+#include "vmware_pack_end.h"
+VixCommandGenerateNonceResponse;
+
+
enum {
VIX_CYPHERTYPE_NONE = 0,
VIX_CYPHERTYPE_DEFAULT = 1,
VIX_COMMAND_REMOVE_BULK_SNAPSHOT = 172,
+ VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST = 173,
+
+ VIX_COMMAND_GENERATE_NONCE = 174,
+
/*
* HOWTO: Adding a new Vix Command. Step 2a.
*
* Once a new command is added here, a command info field needs to be added
* in bora/lib/foundryMsg. as well.
*/
- VIX_COMMAND_LAST_NORMAL_COMMAND = 173,
+ VIX_COMMAND_LAST_NORMAL_COMMAND = 175,
VIX_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND = 998,
VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND = 999,
#endif
#endif
-/*
- * Convenience macro for COMMUNITY_SOURCE
- */
-#undef EXCLUDE_COMMUNITY_SOURCE
-#ifdef COMMUNITY_SOURCE
- #define EXCLUDE_COMMUNITY_SOURCE(x)
-#else
- #define EXCLUDE_COMMUNITY_SOURCE(x) x
-#endif
-
-#undef COMMUNITY_SOURCE_INTEL_SECRET
-#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE)
-/*
- * It's ok to include INTEL_SECRET source code for non-commsrc,
- * or for drops directed at Intel.
- */
- #define COMMUNITY_SOURCE_INTEL_SECRET
-#endif
-
/*
* Convenience macros and definitions. Can often be used instead of #ifdef.
*/
#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
# define FMTTIME FMTSZ"d"
#else
-# define FMTTIME "ld"
+# if defined(_MSC_VER)
+# ifndef _SAFETIME_H_
+# if (_MSC_VER < 1400) || defined(_USE_32BIT_TIME_T)
+# define FMTTIME "ld"
+# else
+# define FMTTIME FMT64"d"
+# endif
+# else
+# ifndef FMTTIME
+# error "safetime.h did not define FMTTIME"
+# endif
+# endif
+# else
+# define FMTTIME "ld"
+# endif
#endif
/*
#define PRODUCT_VDDK_SHORT_NAME "VDDK"
#define PRODUCT_VDDK_NAME MAKE_NAME("VMware Virtual Disk Development Kit")
-#define PRODUCT_VDM_CLIENT_NAME MAKE_NAME("VDM Client")
+#define PRODUCT_VDM_CLIENT_NAME MAKE_NAME("View Client")
#define PRODUCT_VDM_CLIENT_NAME_FOR_LICENSE PRODUCT_VDM_CLIENT_NAME
// XXX VMvisor is the underlying technology for possibly several products,
|| defined(VMX86_WGS) \
|| defined(VMX86_DESKTOP) \
|| defined(VMX86_ENTERPRISE_DESKTOP) \
- || defined(VMX86_MUI) \
+ || defined(VMX86_MUI) \
|| defined(VMX86_API) \
|| defined(VMX86_VPX) \
|| defined(VMX86_WBC) \
* For Host Agent (hostd)
*/
-#define HOST_AGENT_PRODUCT_NAME PRODUCT_NAME " Host Agent"
+#define HOST_AGENT_PRODUCT_NAME PRODUCT_NAME " Host Agent"
/* Used by bora/vim/lib/vmgina module.
* @todo Use this also in /bora/install/msi/InstUtil/desktop/vmInstUtil.cpp
* to guarantee that the service is installed with exactly this name.
*/
-#define HOST_AGENT_SERVICE_NAME "VMwareHostd"
+#define HOST_AGENT_SERVICE_NAME "VMwareHostd"
#endif /* VM_PRODUCT_H */
#define TOOLS_VERSION_WS70_BETA2_V_MNR 1
#define TOOLS_VERSION_WS70_BETA2_V_BASE 1
+#ifndef RC_INVOKED
+#define TOOLS_VERSION_WS70_RC TOOLS_VERSION_TO_UINT(TOOLS_VERSION_WS70_RC_V)
+#endif /* RC_INVOKED */
+#define TOOLS_VERSION_WS70_RC_V_MJR 8
+#define TOOLS_VERSION_WS70_RC_V_MNR 1
+#define TOOLS_VERSION_WS70_RC_V_BASE 2
+
#ifndef RC_INVOKED
#define TOOLS_VERSION_FUSION30_BETA1 TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_BETA1_V)
#endif /* RC_INVOKED */
#define TOOLS_VERSION_FUSION30_BETA2_V_MNR 2
#define TOOLS_VERSION_FUSION30_BETA2_V_BASE 1
+#ifndef RC_INVOKED
+#define TOOLS_VERSION_FUSION30_RC TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_RC_V)
+#endif /* RC_INVOKED */
+#define TOOLS_VERSION_FUSION30_RC_V_MJR 8
+#define TOOLS_VERSION_FUSION30_RC_V_MNR 2
+#define TOOLS_VERSION_FUSION30_RC_V_BASE 2
-#define TOOLS_VERSION_CURRENT TOOLS_VERSION_WS70_BETA2
-#define TOOLS_VERSION_CURRENT_STR TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_BETA2)
-#define TOOLS_VERSION_CURRENT_CSV TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_BETA2)
+#define TOOLS_VERSION_CURRENT TOOLS_VERSION_WS70_RC
+#define TOOLS_VERSION_CURRENT_STR TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_RC)
+#define TOOLS_VERSION_CURRENT_CSV TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_RC)
/*
#elif defined(VMX86_VCB)
#define PRODUCT_VERSION 1,0,0,PRODUCT_BUILD_NUMBER_NUMERIC
#elif defined(VMX86_VLICENSE)
- #define PRODUCT_VERSION 1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC
+ #define PRODUCT_VERSION 1,1,2,PRODUCT_BUILD_NUMBER_NUMERIC
#else
#define PRODUCT_VERSION 3,1,0,PRODUCT_BUILD_NUMBER_NUMERIC
#endif
#define FOUNDRY_VERSION "e.x.p"
#define FOUNDRY_FILE_VERSION 1,7,0,PRODUCT_BUILD_NUMBER_NUMERIC
#define VMLS_VERSION "e.x.p"
-#define VLICENSE_VERSION "1.1.0"
+#define VLICENSE_VERSION "1.1.2"
#define DDK_VERSION "e.x.p"
#define VIM_API_VERSION "4.0"
#define VIPERL_VERSION "1.1.0"
/*
* The current Tools version, derived from vm_tools_version.h. Do not modify this.
*/
-#define TOOLS_VERSION "2009.07.22"
+#define TOOLS_VERSION "2009.08.24"
#ifdef VMX86_VPX
#define VIM_API_TYPE "VirtualCenter"
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of VMware Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission of VMware Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vmblock_user.h --
+ *
+ * Provides interfaces that allow user level programs to talk to the
+ * vmblock fs.
+ */
+
+#ifndef _VMBLOCK_USER_H_
+#define _VMBLOCK_USER_H_
+
+#include "vm_basic_types.h"
+#include "vmblock.h"
+
+static INLINE int
+VMBLOCK_CONTROL_FUSE(int fd, // IN
+ char op, // IN
+ const char *path) // IN
+{
+ /*
+ * buffer needs room for an operation character and a string with max length
+ * PATH_MAX - 1.
+ */
+
+ char buffer[PATH_MAX];
+ size_t pathLength;
+
+ pathLength = strlen(path);
+ if (pathLength >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ buffer[0] = op;
+ memcpy(buffer + 1, path, pathLength);
+
+ /*
+ * The lseek is only to prevent the file pointer from overflowing;
+ * vmblock-fuse ignores the file pointer / offset. Overflowing the file
+ * pointer causes write to fail:
+ * http://article.gmane.org/gmane.comp.file-systems.fuse.devel/6648
+ * There's also a race condition here where many threads all calling
+ * VMBLOCK_CONTROL at the same time could have all their seeks executed one
+ * after the other, followed by all the writes. Again, it's not a problem
+ * unless the file pointer overflows which is very unlikely with 32 bit
+ * offsets and practically impossible with 64 bit offsets.
+ */
+
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ return -1;
+ }
+
+ if (write(fd, buffer, pathLength + 1) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+#if defined(vmblock_fuse)
+
+#define VMBLOCK_CONTROL(fd, op, path) VMBLOCK_CONTROL_FUSE(fd, op, path)
+
+#elif defined(linux)
+
+static INLINE int
+VMBLOCK_CONTROL(int fd, int op, const char *path)
+{
+ return write(fd, path, op);
+}
+
+#elif defined(__FreeBSD__)
+
+static INLINE int
+VMBLOCK_CONTROL(int fd, int cmd, const char *path)
+{
+ char tpath[MAXPATHLEN];
+ size_t pathSize;
+
+ if (path == NULL) {
+ return -1;
+ }
+
+ /*
+ * FreeBSD's ioctl data parameters must be of fixed size. Guarantee a safe
+ * buffer of size MAXPATHLEN by copying the user's string to one of our own.
+ */
+ pathSize = strlcpy(tpath, path, MAXPATHLEN);
+ if (pathSize >= sizeof tpath) {
+ return -1;
+ }
+
+ return ioctl(fd, cmd, tpath);
+}
+
+#elif defined(sun)
+
+static INLINE int
+VMBLOCK_CONTROL(int fd, int cmd, const char *path)
+{
+ return ioctl(fd, cmd, path);
+}
+
+#endif
+
+#endif // _VMBLOCK_USER_H_
GKeyFile **config,
time_t *mtime);
+void
+VMTools_ResetLogging(gboolean cleanDefault);
+
gboolean
VMTools_WriteConfig(const gchar *path,
GKeyFile *config,
#ifndef _WIPER_H_
# define _WIPER_H_
-
#if defined(_WIN32) && defined(_MSC_VER)
#include <windows.h>
#endif
-
#include "vm_basic_types.h"
+#include "dbllnklst.h"
typedef enum {
+ PARTITION_UNSUPPORTED = 0,
PARTITION_EXT2,
PARTITION_EXT3,
PARTITION_REISERFS,
typedef struct WiperPartition {
unsigned char mountPoint[NATIVE_MAX_PATH];
- /*
- * Empty if type is set, otherwise describes why the partition can not be
- * wiped
- */
- char *comment;
-
- /* Type of the partition we know how to wipe */
+ /* Type of the partition */
WiperPartition_Type type;
+ /*
+ * NULL if type is not PARTITION_UNSUPPORTED, otherwise describes
+ * why the partition can not be wiped.
+ */
+ const char *comment;
+
#if defined(_WIN32)
/* Private flags used by the Win32 implementation */
DWORD flags;
#endif
-#if defined(N_PLAT_NLM)
- unsigned long volumeNumber;
-#endif
+ DblLnkLst_Links link;
} WiperPartition;
typedef struct WiperPartition_List {
- WiperPartition *partitions;
- unsigned int size;
+ DblLnkLst_Links link;
} WiperPartition_List;
typedef struct WiperInitData {
} WiperInitData;
Bool Wiper_Init(WiperInitData *clientData);
-WiperPartition_List *WiperPartition_Open(void);
+Bool WiperPartition_Open(WiperPartition_List *pl);
void WiperPartition_Close(WiperPartition_List *pl);
-WiperPartition *SingleWiperPartition_Open(const char *mntpt);
-void SingleWiperPartition_Close(WiperPartition *pl);
+WiperPartition *WiperSinglePartition_Allocate(void);
+WiperPartition *WiperSinglePartition_Open(const char *mntpt);
+void WiperSinglePartition_Close(WiperPartition *);
-unsigned char *WiperSinglePartition_GetSpace(const WiperPartition *p,
- uint64 *free,
- uint64 *total);
+unsigned char *WiperSinglePartition_GetSpace(const WiperPartition *p,
+ uint64 *free,
+ uint64 *total);
/* External definition of the wiper state */
struct Wiper_State;
#include "includeCheck.h"
#include "vm_basic_types.h"
+#include "community_source.h"
/*
* The linux kernel's ptrace.h stupidly defines the bare
* during power-on/migration. Any level which is marked as FALSE here
* *must* have all field masks defined as IGNORE in CPUID_FIELD_DATA.
* A static assert in lib/cpuidcompat/cpuidcompat.c will check this.
- *
- * IMPORTANT: WHEN ADDING A NEW FIELD TO THE CACHED LEVELS, make sure
- * you update vmcore/vmm/cpu/priv.c:Priv_CPUID() and vmcore/vmm64/bt/
- * cpuid_shared.S (and geninfo) to include the new level.
*/
#define CPUID_CACHED_LEVELS \
CPUIDLEVEL(FALSE,410, 0x40000010) \
CPUIDLEVEL(FALSE, 80, 0x80000000) \
CPUIDLEVEL(TRUE, 81, 0x80000001) \
+ CPUIDLEVEL(FALSE, 87, 0x80000007) \
CPUIDLEVEL(FALSE, 88, 0x80000008) \
CPUIDLEVEL(TRUE, 8A, 0x8000000A)
CPUIDLEVEL(FALSE, 4, 4) \
CPUIDLEVEL(FALSE, 6, 6) \
CPUIDLEVEL(FALSE, A, 0xA) \
- CPUIDLEVEL(FALSE, 86, 0x80000006) \
- CPUIDLEVEL(FALSE, 87, 0x80000007) \
+ CPUIDLEVEL(FALSE, 86, 0x80000006)
#define CPUID_ALL_LEVELS \
CPUID_CACHED_LEVELS \
CPUID_NUM_LEVELS
} CpuidLevels;
+
+/* SVM CPUID feature leaf */
+#define CPUID_SVM_FEATURES 0x8000000a
+
+
/*
* CPUID result registers
*/
#define CPUID_MODEL_NEHALEM_1A 0x1a // Nehalem / Gainestown
#define CPUID_MODEL_ATOM_1C 0x1c // Silverthorne / Diamondville
#define CPUID_MODEL_CORE_1D 0x1d // Dunnington
+#define CPUID_MODEL_NEHALEM_1E 0x1e // Lynnfield
#define CPUID_MODEL_PIII_07 7
#define CPUID_MODEL_PIII_08 8
return CPUID_FAMILY_IS_P6(v) &&
(
+ effectiveModel == CPUID_MODEL_NEHALEM_1E ||
effectiveModel == CPUID_MODEL_NEHALEM_1A);
}
+
+
+
static INLINE Bool
CPUID_FAMILY_IS_K7(uint32 _eax)
{
* Wrapper for XdrUtil_ArrayAppend that automatically populates the arguments
* from a given XDR array.
*/
-#define XDRUTIL_ARRAYAPPEND(ptr, field, cnt) \
- XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \
- &(ptr)->field.field##_len, \
- sizeof *(ptr)->field.field##_val, \
- (cnt));
+#ifdef __GNUC__
+# define XDRUTIL_ARRAYAPPEND(ptr, field, cnt) \
+ (typeof ((ptr)->field.field##_val)) \
+ XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \
+ &(ptr)->field.field##_len, \
+ sizeof *(ptr)->field.field##_val, \
+ (cnt))
+#else
+# define XDRUTIL_ARRAYAPPEND(ptr, field, cnt) \
+ XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \
+ &(ptr)->field.field##_len, \
+ sizeof *(ptr)->field.field##_val, \
+ (cnt))
+#endif
void *
XdrUtil_ArrayAppend(void **array, u_int *arrayLen, size_t elemSz, u_int elemCnt);
static const wchar_t nul = L'\0';
#endif
+#ifndef USE_ICONV
+static Bool CodeSetOldIso88591ToUtf8Db(char const *bufIn, size_t sizeIn,
+ unsigned int flags, DynBuf *db);
+#endif
/*
*-----------------------------------------------------------------------------
uint8 *e;
uint32 c;
int len;
-
ASSERT(string < end);
c = *p;
if (c < 0x80) {
- // ASCII
+ // ASCII: U+0000 - U+007F: 1 byte of UTF-8.
len = 1;
goto out;
}
- if (c < 0xc2) {
+ if ((c < 0xc2) || (c > 0xf4)) {
// 0x81 to 0xbf are not valid first bytes
// 0xc0 and 0xc1 cannot appear in UTF-8, see below
+ // leading char can not be > 0xf4, illegal as well
return 0;
}
if (c < 0xe0) {
+ // U+0080 - U+07FF: 2 bytes of UTF-8.
c -= 0xc0;
len = 2;
- } else if (c <= 0xf0) {
+ } else if (c < 0xf0) {
+ // U+0800 - U+FFFF: 3 bytes of UTF-8.
c -= 0xe0;
len = 3;
- } else if (c <= 0xf8) {
+ } else {
+ // U+10000 - U+10FFFF: 4 bytes of UTF-8.
c -= 0xf0;
len = 4;
- } else {
- // bad first byte
- return 0;
}
if ((e = p + len) > (uint8 *) end) {
} else {
goto exit;
}
+ } else if (STRING_ENCODING_ISO_8859_1 == encIn) {
+ if (STRING_ENCODING_UTF8 == encOut) {
+ if (!CodeSetOldIso88591ToUtf8Db(bufIn, sizeIn, flags, db)) {
+ goto exit;
+ }
+ } else {
+ goto exit;
+ }
} else {
goto exit;
}
}
+#ifndef USE_ICONV
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CodeSetOldIso88591ToUtf8Db --
+ *
+ * Convert ISO-8859-1 to UTF-8
+ *
+ * Results:
+ * On success, TRUE and conversion result appended to db.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CodeSetOldIso88591ToUtf8Db(char const *bufIn, // IN
+ size_t sizeIn, // IN
+ unsigned int flags, // IN
+ DynBuf *db) // OUT
+{
+ size_t i;
+ size_t last = 0;
+
+ for (i = 0; i < sizeIn; i++) {
+ unsigned int c = (unsigned char)bufIn[i];
+ if (UNLIKELY(c >= 0x80)) {
+ unsigned char buf[2];
+
+ buf[0] = 0xC0 | (c >> 6);
+ buf[1] = 0x80 | (c & 0x3F);
+ DynBuf_Append(db, bufIn + last, i - last);
+ DynBuf_Append(db, buf, sizeof buf);
+ last = i + 1;
+ }
+ }
+ DynBuf_Append(db, bufIn + last, i - last);
+ return TRUE;
+}
+#endif
+
+
#if defined(_WIN32)
/*
*-----------------------------------------------------------------------------
#include <mach/mach_init.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
+#include <sys/mman.h>
#elif defined(__FreeBSD__)
#if !defined(RLIMIT_AS)
# if defined(RLIMIT_VMEM)
#if defined(__APPLE__)
#define SYS_NMLN _SYS_NAMELEN
#endif
-static int hostinfoOSVersion[3];
+static int hostinfoOSVersion[4];
static char hostinfoOSVersionString[SYS_NMLN];
#define DISTRO_BUF_SIZE 255
Str_Strcpy(hostinfoOSVersionString, u.release, SYS_NMLN);
- ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 3);
+ ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 4);
if (sscanf(u.release, "%d.%d.%d%s",
&hostinfoOSVersion[0], &hostinfoOSVersion[1],
&hostinfoOSVersion[2], extra) < 1) {
NOT_IMPLEMENTED();
}
+ /* If there is a 4th number, use it, otherwise use 0. */
+ if (sscanf(extra, ".%d%*s", &hostinfoOSVersion[3]) < 1) {
+ hostinfoOSVersion[3] = 0;
+ }
+
hostinfoOSVersionInitialized = TRUE;
}
int s, fd;
struct sigaction sa;
struct rlimit rlim;
-#ifdef __linux__
- int err;
- uid_t euid;
-#endif
/*
* Disable itimers before resetting the signal handlers.
#ifdef __linux__
/*
* Drop iopl to its default value.
+ * iopl() is not implemented in userworlds
*/
- euid = Id_GetEUid();
- /* At this point, _unless we are running as root_, we shouldn't have root
- privileges --hpreg */
- ASSERT(euid != 0 || getuid() == 0);
- Id_SetEUid(0);
- err = iopl(0);
- Id_SetEUid(euid);
- ASSERT_NOT_IMPLEMENTED(err == 0);
+ if (!vmx86_server) {
+ int err;
+ uid_t euid;
+
+ euid = Id_GetEUid();
+ /* At this point, _unless we are running as root_, we shouldn't have root
+ privileges --hpreg */
+ ASSERT(euid != 0 || getuid() == 0);
+ Id_SetEUid(0);
+ err = iopl(0);
+ Id_SetEUid(euid);
+ ASSERT_NOT_IMPLEMENTED(err == 0);
+ }
#endif
}
return 0;
}
}
+
+
+#ifdef __APPLE__
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Hostinfo_GetKernelZoneElemSize --
+ *
+ * Retrieve the size of the elements in a named kernel zone.
+ *
+ * We used to do it like zprint (see
+ * darwinsource-10.4.5/system_cmds-336.10/zprint.tproj/zprint.c::main()),
+ * i.e. by calling host_zone_info(), but there are 3 problems with that:
+ *
+ * 1) mach/mach_host.defs defines both arrays passed to host_zone_info()
+ * as 'out' parameters, but the implementation of the function in
+ * xnu-792.13.8/osfmk/kern/zalloc.c clearly expects them as 'inout'
+ * parameters. This issue is confirmed in practice: the input values
+ * passed by the user process are ignored. Now comes the scary part: is
+ * the input of the kernel function deterministically invalid, or is it
+ * some non-deterministic garbage (in which case the user process can
+ * corrupt its address space)? The answer is in the Mach IPC code. A
+ * cursory kernel debugging session seems to imply that the input
+ * pointer values are garbage, but the input size values are always 0.
+ * So the function seems safe to use in practice.
+ *
+ * 2) Starting with Mac OS 10.6, host_zone_info() always returns
+ * KERN_NOT_SUPPORTED when the sizes of the user and kernel virtual
+ * address spaces (32-bit or 64-bit) do not match. Was bug 377049.
+ *
+ * 3) Apple broke the ABI: For 64-bit code, the 'zone_info.zi_*_size'
+ * fields are 32-bit in the Mac OS 10.5 SDK, but 64-bit in the Mac OS
+ * 10.6 SDK. So a 64-bit VMX compiled against the Mac OS 10.5 SDK works
+ * with the Mac OS 10.5 (32-bit) kernel but fails with the Mac OS 10.6
+ * 64-bit kernel.
+ *
+ * So now we just let Apple deal with their own mess: we invoke zprint,
+ * and we parse its non-localized output. Should Apple stop shipping
+ * zprint, we can always ship our own replacement for it.
+ *
+ * Results:
+ * On success: the size (in bytes) > 0.
+ * On failure: 0.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+size_t
+Hostinfo_GetKernelZoneElemSize(char const *name) // IN: Kernel zone name
+{
+ size_t retval = 0;
+ struct {
+ size_t retval;
+ } volatile *shared;
+ pid_t child;
+ pid_t pid;
+
+ /*
+ * popen(3) incorrectly executes the shell with the identity of the calling
+ * process, ignoring a potential per-thread identity. And starting with
+ * Mac OS 10.6 it is even worse: if there is a per-thread identity, popen(3)
+ * removes it!
+ *
+ * So we run this code in a separate process which runs with the same
+ * identity as the current thread.
+ */
+
+ shared = mmap(NULL, sizeof *shared, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_SHARED, -1, 0);
+ if (shared == (void *)-1) {
+ Warning("%s: mmap error %d.\n", __FUNCTION__, errno);
+ return retval;
+ }
+
+ // In case the child is terminated before it can set it.
+ shared->retval = retval;
+
+ child = fork();
+ if (child == (pid_t)-1) {
+ Warning("%s: fork error %d.\n", __FUNCTION__, errno);
+ munmap((void *)shared, sizeof *shared);
+ return retval;
+ }
+
+ // This executes only in the child process.
+ if (!child) {
+ size_t nameLen;
+ FILE *stream;
+ Bool parsingProperties = FALSE;
+
+ ASSERT(name);
+
+ nameLen = strlen(name);
+ ASSERT(nameLen && *name != '\t');
+
+ stream = popen("/usr/bin/zprint -C", "r");
+ if (!stream) {
+ Warning("%s: popen error %d.\n", __FUNCTION__, errno);
+ exit(EXIT_SUCCESS);
+ }
+
+ for (;;) {
+ char *line;
+ size_t lineLen;
+
+ if (StdIO_ReadNextLine(stream, &line, 0, &lineLen) != StdIO_Success) {
+ break;
+ }
+
+ if (parsingProperties) {
+ if ( // Not a property line anymore. Property not found.
+ lineLen < 1 || memcmp(line, "\t", 1)
+ // Property found.
+ || sscanf(line, " elem_size: %"FMTSZ"u bytes",
+ &shared->retval) == 1) {
+ free(line);
+ break;
+ }
+ } else if (!( lineLen < nameLen + 6
+ || memcmp(line, name, nameLen)
+ || memcmp(line + nameLen, " zone:", 6))) {
+ // Zone found.
+ parsingProperties = TRUE;
+ }
+
+ free(line);
+ }
+
+ pclose(stream);
+ exit(EXIT_SUCCESS);
+ }
+
+ /*
+ * This executes only in the parent process.
+ * Wait for the child to terminate, and return its retval.
+ */
+
+ do {
+ int status;
+
+ pid = waitpid(child, &status, 0);
+ } while (pid == -1 && errno == EINTR);
+ ASSERT_NOT_IMPLEMENTED(pid == child);
+
+ retval = shared->retval;
+ munmap((void *)shared, sizeof *shared);
+ return retval;
+}
+#endif /* __APPLE__ */
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/ioctl.h>
+#include <net/if_arp.h> // for ARPHRD_ETHER
#if defined(__FreeBSD__) || defined(__APPLE__)
#include "ifaddrs.h"
}
# endif // ifdef DUMMY_NETUTIL
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * NetUtil_GetHardwareAddress --
+ *
+ * Given an interface name, return its hardware/link layer address.
+ *
+ * Results:
+ * Returns TRUE and populates hwAddr on success.
+ * Returns FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+size_t
+NetUtil_GetHardwareAddress(int ifIndex, // IN
+ char *hwAddr, // OUT
+ size_t hwAddrSize, // IN
+ IanaIfType *ifType) // OUT
+{
+ struct ifreq ifreq;
+ int fd = -1;
+ size_t ret = 0;
+
+ if (hwAddrSize < IFHWADDRLEN) {
+ return FALSE;
+ }
+
+ ASSERT(sizeof ifreq.ifr_name >= IF_NAMESIZE);
+
+ memset(&ifreq, 0, sizeof ifreq);
+ if (if_indextoname(ifIndex, ifreq.ifr_name) == NULL) {
+ return FALSE;
+ }
+
+ if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
+ return FALSE;
+ }
+
+ if (ioctl(fd, SIOCGIFHWADDR, &ifreq) == 0 &&
+ ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
+ memcpy(hwAddr, ifreq.ifr_hwaddr.sa_data, IFHWADDRLEN);
+ *ifType = IANA_IFTYPE_ETHERNETCSMACD;
+ ret = IFHWADDRLEN;
+ }
+
+ close(fd);
+
+ return ret;
+}
+
+
#endif // if defined(linux)
* None
*
* Side effects:
- * None
+ * If converting from a lower true-color depth to 32-bpp, fills the
+ * alpha values of the destination rectangle to 0xFF.
*
*----------------------------------------------------------------------
*/
* None
*
* Side effects:
- * None
+ * Fills the alpha values of the destination rectangle to 0xFF.
*
*----------------------------------------------------------------------
*/
for (i=0; i<h; i++) {
for (j=0; j<w; j++) {
uint32 pix = srcptr[j];
- dstptr[j] = (REDMASK_32 &
+ dstptr[j] = (0xFF << 24) |
+ (REDMASK_32 &
((((pix & redMask) >> redShift1) |
((pix & redMask) >> redShift2)) << 16)) |
(GREENMASK_32 &
* None
*
* Side effects:
- * None
+ * Fills the alpha values of the destination rectangle to 0xFF.
*
*----------------------------------------------------------------------
*/
uint8 blue = srcptr[k++];
uint8 green = srcptr[k++];
uint8 red = srcptr[k++];
- dstptr[j] = ((red << 16) & REDMASK_32) |
+ dstptr[j] = (0xFF << 24) |
+ ((red << 16) & REDMASK_32) |
((green << 8) & GREENMASK_32) |
(blue & BLUEMASK_32);
}
* None
*
* Side effects:
- * None
+ * None
*
*----------------------------------------------------------------------
*/
*/
#include <string.h>
+#include "vm_assert.h"
#include "dynxdr.h"
#include "rpcChannelInt.h"
#include "str.h"
status = rpc->callback(data);
}
- g_assert(data->result != NULL);
+ ASSERT(data->result != NULL);
exit:
data->name = NULL;
RpcChannel_RegisterCallback(RpcChannel *chan,
RpcChannelCallback *rpc)
{
- g_assert(rpc->name != NULL && strlen(rpc->name) > 0);
- g_assert(rpc->callback);
- g_assert(rpc->xdrIn == NULL || rpc->xdrInSize > 0);
+ ASSERT(rpc->name != NULL && strlen(rpc->name) > 0);
+ ASSERT(rpc->callback);
+ ASSERT(rpc->xdrIn == NULL || rpc->xdrInSize > 0);
if (chan->rpcs == NULL) {
chan->rpcs = g_hash_table_new(g_str_hash, g_str_equal);
}
--- /dev/null
+################################################################################
+### Copyright 2007 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libSlashProc.la
+
+libSlashProc_la_SOURCES =
+libSlashProc_la_SOURCES += net.c
+
+libSlashProc_la_CPPFLAGS =
+libSlashProc_la_CPPFLAGS += @GLIB2_CPPFLAGS@
+
+AM_CFLAGS = $(DNET_CPPFLAGS)
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file net.c
+ *
+ * Parses assorted /proc/net nodes.
+ */
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "vmware.h"
+#include "panic.h"
+#include "slashProc.h"
+#include "slashProcNetInt.h"
+#include "netutil.h"
+
+
+/*
+ * Local data.
+ */
+
+
+#define PROC_NET_SNMP "/proc/net/snmp"
+#define PROC_NET_SNMP6 "/proc/net/snmp6"
+#define PROC_NET_ROUTE "/proc/net/route"
+#define PROC_NET_ROUTE6 "/proc/net/ipv6_route"
+
+
+/**
+ * @brief Evaluate an expression with a regular expression match.
+ *
+ * Convenience wrapper to fetch a regular expression match result, evaluate
+ * it as an argument in some expression, and then free it.
+ *
+ * @param[in] matchInfo GMatchInfo RE context.
+ * @param[in] matchIndex Match index.
+ * @param[in] expr Expression to evaluate. Must contain @c MATCH as
+ * placeholder where matched value will be inserted.
+ */
+#define MATCHEXPR(matchInfo, matchIndex, expr) do { \
+ gchar *MATCH = g_match_info_fetch(matchInfo, matchIndex); \
+ expr; \
+ g_free(MATCH); \
+} while(0)
+
+
+/**
+ * Override-able @c /proc/net/snmp path. Useful for debugging.
+ */
+static const char *pathToNetSnmp = PROC_NET_SNMP;
+
+
+/**
+ * Override-able @c /proc/net/snmp6 path. Useful for debugging.
+ */
+static const char *pathToNetSnmp6 = PROC_NET_SNMP6;
+
+
+/**
+ * Override-able @c /proc/net/route path. Useful for debugging.
+ */
+static const char *pathToNetRoute = PROC_NET_ROUTE;
+
+
+/**
+ * Override-able @c /proc/net/ipv6_route path. Useful for debugging.
+ */
+static const char *pathToNetRoute6 = PROC_NET_ROUTE6;
+
+
+/*
+ * Private function prototypes.
+ */
+
+static void Ip6StringToIn6Addr(const char *ip6String,
+ struct in6_addr *in6_addr);
+static guint64 MatchToGuint64(const GMatchInfo *matchInfo,
+ const gint matchIndex,
+ gint base);
+
+
+/*
+ * Library private functions.
+ */
+
+
+#ifdef VMX86_DEVEL
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathSnmp -- */ /**
+ *
+ * @brief Overrides @ref pathToNetSnmp. Useful for debugging.
+ *
+ * @param[in] newPathToNetSnmp New path to used in place of @ref PROC_NET_SNMP.
+ * If @c NULL, @ref pathToNewSnmp reverts to @ref
+ * PROC_NET_SNMP.
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathSnmp(const char *newPathToNetSnmp)
+{
+ pathToNetSnmp = newPathToNetSnmp ? newPathToNetSnmp : PROC_NET_SNMP;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathSnmp6 -- */ /**
+ *
+ * @brief Overrides @ref pathToNetSnmp6. Useful for debugging.
+ *
+ * @sa SlashProcNetSetPathSnmp
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathSnmp6(const char *newPathToNetSnmp6)
+{
+ pathToNetSnmp6 = newPathToNetSnmp6 ? newPathToNetSnmp6 : PROC_NET_SNMP6;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathRoute -- */ /**
+ *
+ * @brief Overrides @ref pathToNetRoute. Useful for debugging.
+ *
+ * @sa SlashProcNetSetPathSnmp
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathRoute(const char *newPathToNetRoute)
+{
+ pathToNetRoute = newPathToNetRoute ? newPathToNetRoute : PROC_NET_ROUTE;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathRoute6 -- */ /**
+ *
+ * @brief Overrides @ref pathToNetRoute6. Useful for debugging.
+ *
+ * @sa SlashProcNetSetPathSnmp
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathRoute6(const char *newPathToNetRoute6)
+{
+ pathToNetRoute6 = newPathToNetRoute6 ? newPathToNetRoute6 : PROC_NET_ROUTE6;
+}
+#endif // ifdef VMX86_DEVEL
+
+
+/*
+ * Library public functions.
+ */
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetSnmp -- */ /**
+ *
+ * @brief Reads @ref pathToNetSnmp and returns contents as a
+ * <tt>GHashTable(gchar *key, guint64 *value)</tt>.
+ *
+ * Example usage:
+ * @code
+ * GHashTable *netSnmp = SlashProcNet_GetSnmp();
+ * guint64 *inDiscards = g_hash_table_lookup(netSnmp, "IpInDiscards");
+ * @endcode
+ *
+ * @note Caller should free the returned @c GHashTable with
+ * @c g_hash_table_destroy.
+ * @note This routine creates persistent GLib GRegexs.
+ *
+ * @return On failure, NULL. On success, a valid @c GHashTable.
+ * @todo Provide a case-insensitive key comparison function.
+ * @todo Consider init/cleanup routines to not "leak" GRegexs.
+ *
+ ******************************************************************************
+ */
+
+GHashTable *
+SlashProcNet_GetSnmp(void)
+{
+ GHashTable *myHashTable = NULL;
+ GIOChannel *myChannel = NULL;
+ GIOStatus keyIoStatus;
+ GIOStatus valIoStatus;
+ gchar *myKeyLine = NULL;
+ gchar *myValLine = NULL;
+ Bool parseError = FALSE;
+ int fd = -1;
+
+ static GRegex *myKeyRegex = NULL;
+ static GRegex *myValRegex = NULL;
+
+ if (myKeyRegex == NULL) {
+ myKeyRegex = g_regex_new("^(\\w+): (\\w+ )*(\\w+)$", G_REGEX_OPTIMIZE,
+ 0, NULL);
+ myValRegex = g_regex_new("^(\\w+): (-?\\d+ )*(-?\\d+)$", G_REGEX_OPTIMIZE,
+ 0, NULL);
+ ASSERT(myKeyRegex);
+ ASSERT(myValRegex);
+ }
+
+ if ((fd = g_open(pathToNetSnmp, O_RDONLY)) == -1) {
+ return NULL;
+ }
+
+ myChannel = g_io_channel_unix_new(fd);
+
+ myHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+ /*
+ * Expected format:
+ *
+ * pfx0: key0 key1 key2 ... keyN
+ * pfx0: val0 val1 val2 ... valN
+ * ...
+ * pfxN: ...
+ */
+
+ while ((keyIoStatus = g_io_channel_read_line(myChannel, &myKeyLine, NULL, NULL,
+ NULL)) == G_IO_STATUS_NORMAL &&
+ (valIoStatus = g_io_channel_read_line(myChannel, &myValLine, NULL, NULL,
+ NULL)) == G_IO_STATUS_NORMAL) {
+
+ GMatchInfo *keyMatchInfo = NULL;
+ GMatchInfo *valMatchInfo = NULL;
+
+ gchar **myKeys = NULL;
+ gchar **myVals = NULL;
+
+ gchar **myKey = NULL;
+ gchar **myVal = NULL;
+
+ gchar *keyPrefix = NULL;
+ gchar *valPrefix = NULL;
+
+ /*
+ * Per format above, we expect a pair of lines with a matching prefix.
+ */
+ {
+ if (!g_regex_match(myKeyRegex, myKeyLine, 0, &keyMatchInfo) ||
+ !g_regex_match(myValRegex, myValLine, 0, &valMatchInfo)) {
+ parseError = TRUE;
+ goto badIteration;
+ }
+
+ keyPrefix = g_match_info_fetch(keyMatchInfo, 1);
+ valPrefix = g_match_info_fetch(valMatchInfo, 1);
+
+ ASSERT(keyPrefix);
+ ASSERT(valPrefix);
+
+ if (strcmp(keyPrefix, valPrefix)) {
+ parseError = TRUE;
+ goto badIteration;
+ }
+ }
+
+ myKeys = g_strsplit(myKeyLine, " ", 0);
+ myVals = g_strsplit(myValLine, " ", 0);
+
+ /*
+ * Iterate over the columns, combining the column keys with the prefix
+ * to form the new key name. (I.e., "Ip: InDiscards" => "IpInDiscards".)
+ */
+ for (myKey = &myKeys[1], myVal = &myVals[1];
+ *myKey && *myVal;
+ myKey++, myVal++) {
+ gchar *hashKey;
+ guint64 *myIntVal = NULL;
+
+ hashKey = g_strjoin(NULL, keyPrefix, *myKey, NULL);
+ g_strstrip(hashKey);
+
+ /*
+ * By virtue of having matched the above regex, this conversion
+ * must hold.
+ */
+ myIntVal = g_new(guint64, 1);
+ *myIntVal = g_ascii_strtoull(*myVal, NULL, 10);
+
+ /*
+ * If our input contains duplicate keys, which I really don't see
+ * happening, the latter value overrides the former.
+ *
+ * NB: myHashTable claims ownership of hashKey.
+ */
+ g_hash_table_insert(myHashTable, hashKey, myIntVal);
+ }
+
+ /*
+ * Make sure the column counts matched. If we succeeded, both pointers
+ * should now be NULL.
+ */
+ if (*myKey || *myVal) {
+ parseError = TRUE;
+ }
+
+badIteration:
+ g_match_info_free(keyMatchInfo);
+ g_match_info_free(valMatchInfo);
+
+ g_free(keyPrefix);
+ g_free(valPrefix);
+
+ g_strfreev(myKeys);
+ g_strfreev(myVals);
+
+ g_free(myKeyLine);
+ g_free(myValLine);
+ myKeyLine = NULL;
+ myValLine = NULL;
+
+ if (parseError) {
+ break;
+ }
+ }
+
+ /*
+ * Error conditions:
+ * Hash table empty: Unable to parse any input.
+ * myKeyLine != NULL: Failed to read "key" and "value" lines during
+ * same loop iteration.
+ * parseError == TRUE: See loop body above.
+ */
+ if (keyIoStatus == G_IO_STATUS_ERROR ||
+ valIoStatus == G_IO_STATUS_ERROR ||
+ g_hash_table_size(myHashTable) == 0 ||
+ parseError) {
+ g_hash_table_destroy(myHashTable);
+ myHashTable = NULL;
+ }
+
+ g_free(myKeyLine);
+ g_free(myValLine);
+ myKeyLine = NULL;
+ myValLine = NULL;
+
+ close(fd);
+
+ g_free(myChannel);
+
+ return myHashTable;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetSnmp6 -- */ /**
+ *
+ * @brief Reads @ref pathToNetSnmp6 and returns contents as a
+ * <tt>GHashTable(gchar *key, guint64 *value)</tt>.
+ *
+ * Example usage:
+ * @code
+ * GHashTable *netSnmp6 = SlashProcNet_GetSnmp6();
+ * guint64 *raw6Discards = g_hash_table_lookup(netSnmp6, "Ip6InDiscards");
+ * @endcode
+ *
+ * @note Caller should free the returned @c GHashTable with
+ * @c g_hash_table_destroy.
+ * @note This routine creates persistent GLib GRegexs.
+ *
+ * @return On failure, NULL. On success, a valid @c GHashTable.
+ * @todo Provide a case-insensitive key comparison function.
+ * @todo Consider init/cleanup routines to not "leak" GRegexs.
+ *
+ ******************************************************************************
+ */
+
+GHashTable *
+SlashProcNet_GetSnmp6(void)
+{
+ GHashTable *myHashTable = NULL;
+ GIOChannel *myChannel = NULL;
+ GIOStatus ioStatus;
+ gchar *myInputLine = NULL;
+ Bool parseError = FALSE;
+ int fd = -1;
+
+ static GRegex *myRegex = NULL;
+
+ if (myRegex == NULL) {
+ myRegex = g_regex_new("^(\\w+)\\s+(-?\\d+)\\s*$", G_REGEX_OPTIMIZE,
+ 0, NULL);
+ ASSERT(myRegex);
+ }
+
+ if ((fd = g_open(pathToNetSnmp6, O_RDONLY)) == -1) {
+ return NULL;
+ }
+
+ myChannel = g_io_channel_unix_new(fd);
+
+ myHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+ /*
+ * Expected format:
+ *
+ * key1 value1
+ * key2 value2
+ * ...
+ * keyN valueN
+ */
+
+ while ((ioStatus = g_io_channel_read_line(myChannel, &myInputLine, NULL,
+ NULL, NULL)) == G_IO_STATUS_NORMAL) {
+ GMatchInfo *matchInfo = NULL;
+
+ if (g_regex_match(myRegex, myInputLine, 0, &matchInfo)) {
+ gchar *myKey = NULL;
+ gchar *myVal = NULL;
+ guint64 *myIntVal = NULL;
+
+ myKey = g_match_info_fetch(matchInfo, 1);
+ myVal = g_match_info_fetch(matchInfo, 2);
+
+ /*
+ * By virtue of having matched the above regex, this conversion
+ * must hold.
+ */
+ myIntVal = g_new(guint64, 1);
+ *myIntVal = g_ascii_strtoull(myVal, NULL, 10);
+
+ /*
+ * The hash table will take ownership of myKey and myIntVal. We're
+ * still responsible for myVal.
+ */
+ g_hash_table_insert(myHashTable, myKey, myIntVal);
+ g_free(myVal);
+ } else {
+ parseError = TRUE;
+ }
+
+ g_match_info_free(matchInfo);
+ g_free(myInputLine);
+ myInputLine = NULL;
+
+ if (parseError) {
+ break;
+ }
+ }
+
+ if (ioStatus == G_IO_STATUS_ERROR ||
+ g_hash_table_size(myHashTable) == 0 ||
+ parseError) {
+ g_hash_table_destroy(myHashTable);
+ myHashTable = NULL;
+ }
+
+ close(fd);
+
+ g_free(myChannel);
+
+ return myHashTable;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetRoute -- */ /**
+ *
+ * @brief Reads @ref pathToNetRoute and returns a @c GPtrArray of
+ * <tt>struct rtentry</tt>s.
+ *
+ * Example usage:
+ * @code
+ * GPtrArray *rtArray;
+ * guint i;
+ * rtArray = SlashProcNet_GetRoute();
+ * for (i = 0; i < rtArray->len; i++) {
+ * struct rtentry *myRoute = g_ptr_array_index(rtArray, i);
+ * // Do something with myRoute->rt_dst.
+ * }
+ * SlashProcNet_FreeRoute(rtArray);
+ * @endcode
+ *
+ * @note Caller is responsible for freeing the @c GPtrArray with
+ * SlashProcNet_FreeRoute.
+ * @note This routine creates persistent GLib GRegexs.
+ *
+ * @return On failure, NULL. On success, a valid @c GPtrArray.
+ * @todo Consider init/cleanup routines to not "leak" GRegexs.
+ * @todo Consider rewriting, integrating with libdnet.
+ *
+ ******************************************************************************
+ */
+
+GPtrArray *
+SlashProcNet_GetRoute(void)
+{
+ GIOChannel *myChannel = NULL;
+ GIOStatus myIoStatus;
+ GPtrArray *myArray = NULL;
+ gchar *myLine = NULL;
+ int fd = -1;
+
+ static GRegex *myFieldsRE = NULL;
+ static GRegex *myValuesRE = NULL;
+
+ if (myFieldsRE == NULL) {
+ myFieldsRE = g_regex_new("^Iface\\s+Destination\\s+Gateway\\s+Flags\\s+"
+ "RefCnt\\s+Use\\s+Metric\\s+Mask\\s+MTU\\s+"
+ "Window\\s+IRTT\\s*$", 0, 0, NULL);
+ myValuesRE = g_regex_new("^(\\w+)\\s+([[:xdigit:]]{8})\\s+"
+ "([[:xdigit:]]{8})\\s+([[:xdigit:]]{4})\\s+"
+ "\\d+\\s+\\d+\\s+(\\d+)\\s+"
+ "([[:xdigit:]]{8})\\s+(\\d+)\\s+\\d+\\s+(\\d+)\\s*$",
+ 0, 0, NULL);
+ ASSERT(myFieldsRE);
+ ASSERT(myValuesRE);
+ }
+
+ /*
+ * 1. Open pathToNetRoute, associate it with a GIOChannel.
+ */
+
+ if ((fd = g_open(pathToNetRoute, O_RDONLY)) == -1) {
+ Warning("%s: open(%s): %s\n", __func__, pathToNetRoute,
+ g_strerror(errno));
+ return NULL;
+ }
+
+ myChannel = g_io_channel_unix_new(fd);
+
+ /*
+ * 2. Sanity check the header, making sure it matches what we expect.
+ * (It's -extremely- unlikely this will change, but we should check
+ * anyway.)
+ */
+
+ myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL, NULL);
+ if (myIoStatus != G_IO_STATUS_NORMAL ||
+ g_regex_match(myFieldsRE, myLine, 0, NULL) == FALSE) {
+ goto out;
+ }
+
+ g_free(myLine);
+ myLine = NULL;
+
+ myArray = g_ptr_array_new();
+
+ /*
+ * 3. For each line...
+ */
+
+ while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL,
+ NULL)) == G_IO_STATUS_NORMAL) {
+ GMatchInfo *myMatchInfo = NULL;
+ struct rtentry *myEntry = NULL;
+ struct sockaddr_in *sin = NULL;
+ Bool parseError = FALSE;
+
+ /*
+ * 3a. Validate with regex.
+ */
+ if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) {
+ parseError = TRUE;
+ goto badIteration;
+ }
+
+ /*
+ * 3b. Allocate new rtentry, add to array. This simplifies the cleanup
+ * code path.
+ */
+ myEntry = g_new0(struct rtentry, 1);
+ g_ptr_array_add(myArray, myEntry);
+
+ /*
+ * 3c. Copy contents to new struct rtentry.
+ */
+ myEntry->rt_dev = g_match_info_fetch(myMatchInfo, 1);
+
+ sin = (struct sockaddr_in *)&myEntry->rt_dst;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 2, 16);
+
+ sin = (struct sockaddr_in *)&myEntry->rt_gateway;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 3, 16);
+
+ sin = (struct sockaddr_in *)&myEntry->rt_genmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 6, 16);
+
+ myEntry->rt_flags = MatchToGuint64(myMatchInfo, 4, 16);
+ myEntry->rt_metric = MatchToGuint64(myMatchInfo, 5, 10);
+ myEntry->rt_mtu = MatchToGuint64(myMatchInfo, 7, 10);
+ myEntry->rt_irtt = MatchToGuint64(myMatchInfo, 8, 10);
+
+badIteration:
+ g_free(myLine);
+ myLine = NULL;
+
+ g_match_info_free(myMatchInfo);
+ myMatchInfo = NULL;
+
+ if (parseError) {
+ break;
+ }
+ }
+
+ if (myArray && myIoStatus != G_IO_STATUS_EOF) {
+ SlashProcNet_FreeRoute(myArray);
+ myArray = NULL;
+ }
+
+out:
+ g_free(myLine);
+ g_free(myChannel);
+
+ close(fd);
+
+ return myArray;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_FreeRoute -- */ /**
+ *
+ * @brief Frees memory associated with a GPtrArray allocated by
+ * SlashProcNet_GetRoute.
+ *
+ * @param[in] routeArray Array to free.
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNet_FreeRoute(GPtrArray *routeArray)
+{
+ int i;
+
+ if (routeArray == NULL) {
+ return;
+ }
+
+ for (i = 0; i < routeArray->len; i++) {
+ struct rtentry *myEntry = g_ptr_array_index(routeArray, i);
+ ASSERT(myEntry->rt_dev);
+ g_free(myEntry->rt_dev);
+ g_free(myEntry);
+ }
+
+ g_ptr_array_free(routeArray, TRUE);
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetRoute6 -- */ /**
+ *
+ * @brief Reads @ref pathToNetRoute6 and returns a @c GPtrArray of
+ * <tt>struct in6_rtmsg</tt>s.
+ *
+ * Example usage:
+ * @code
+ * GPtrArray *rtArray;
+ * guint i;
+ * rtArray = SlashProcNet_GetRoute6();
+ * for (i = 0; i < rtArray->len; i++) {
+ * struct in6_rtmsg *myRoute = g_ptr_array_index(rtArray, i);
+ * // Do something with myRoute->rtmsg_dst.
+ * }
+ * SlashProcNet_FreeRoute6(rtArray, TRUE);
+ * @endcode
+ *
+ * @note Caller is responsible for freeing the @c GPtrArray with
+ * SlashProcNet_FreeRoute6.
+ * @note This routine creates persistent GLib GRegexs.
+ *
+ * @return On failure, NULL. On success, a valid @c GPtrArray.
+ * @todo Consider init/cleanup routines to not "leak" GRegexs.
+ * @todo Consider rewriting, integrating with libdnet.
+ *
+ ******************************************************************************
+ */
+
+GPtrArray *
+SlashProcNet_GetRoute6(void)
+{
+ GIOChannel *myChannel = NULL;
+ GIOStatus myIoStatus;
+ GPtrArray *myArray = NULL;
+ gchar *myLine = NULL;
+ Bool parseError = FALSE;
+ int fd = -1;
+
+ static GRegex *myValuesRE = NULL;
+
+ if (myValuesRE == NULL) {
+ myValuesRE = g_regex_new("^([[:xdigit:]]{32}) ([[:xdigit:]]{2}) "
+ "([[:xdigit:]]{32}) ([[:xdigit:]]{2}) "
+ "([[:xdigit:]]{32}) ([[:xdigit:]]{8}) "
+ "[[:xdigit:]]{8} [[:xdigit:]]{8} "
+ "([[:xdigit:]]{8})\\s+(\\w+)\\s*$", 0, 0,
+ NULL);
+ ASSERT(myValuesRE);
+ }
+
+ /*
+ * 1. Open pathToNetRoute6, associate it with a GIOChannel.
+ */
+
+ if ((fd = g_open(pathToNetRoute6, O_RDONLY)) == -1) {
+ Warning("%s: open(%s): %s\n", __func__, pathToNetRoute,
+ g_strerror(errno));
+ return NULL;
+ }
+
+ myChannel = g_io_channel_unix_new(fd);
+
+ myArray = g_ptr_array_new();
+
+ while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL,
+ NULL)) == G_IO_STATUS_NORMAL) {
+ struct in6_rtmsg *myEntry = NULL;
+ GMatchInfo *myMatchInfo = NULL;
+
+ if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) {
+ parseError = TRUE;
+ goto badIteration;
+ }
+
+ myEntry = g_new0(struct in6_rtmsg, 1);
+ g_ptr_array_add(myArray, myEntry);
+
+ MATCHEXPR(myMatchInfo, 1, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_dst));
+ MATCHEXPR(myMatchInfo, 3, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_src));
+ MATCHEXPR(myMatchInfo, 5, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_gateway));
+
+ myEntry->rtmsg_dst_len = MatchToGuint64(myMatchInfo, 2, 16);
+ myEntry->rtmsg_src_len = MatchToGuint64(myMatchInfo, 4, 16);
+ myEntry->rtmsg_metric = MatchToGuint64(myMatchInfo, 6, 16);
+ myEntry->rtmsg_flags = MatchToGuint64(myMatchInfo, 7, 16);
+
+ MATCHEXPR(myMatchInfo, 8, myEntry->rtmsg_ifindex = NetUtil_GetIfIndex(MATCH));
+
+badIteration:
+ g_free(myLine);
+ myLine = NULL;
+
+ g_match_info_free(myMatchInfo);
+ myMatchInfo = NULL;
+
+ if (parseError) {
+ break;
+ }
+ }
+
+ if (myArray && myIoStatus != G_IO_STATUS_EOF) {
+ g_ptr_array_free(myArray, TRUE);
+ myArray = NULL;
+ }
+
+ g_free(myLine);
+ myLine = NULL;
+ g_free(myChannel);
+ myChannel = NULL;
+
+ return myArray;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_FreeRoute6 -- */ /**
+ *
+ * @brief Frees memory associated with a GPtrArray allocated by
+ * SlashProcNet_GetRoute6.
+ *
+ * @param[in] routeArray Array to free.
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNet_FreeRoute6(GPtrArray *routeArray)
+{
+ int i;
+
+ if (routeArray == NULL) {
+ return;
+ }
+
+ for (i = 0; i < routeArray->len; i++) {
+ struct rtentry *myEntry = g_ptr_array_index(routeArray, i);
+ g_free(myEntry);
+ }
+
+ g_ptr_array_free(routeArray, TRUE);
+}
+
+
+/*
+ * Private functions.
+ */
+
+
+/*
+ ******************************************************************************
+ * Ip6StringToIn6Addr -- */ /**
+ *
+ * @brief Parses a @c /proc/net/ipv6_route hexadecimal IPv6 address and
+ * records it in a <tt>struct in6_addr</tt>.
+ *
+ * @param[in] ip6String Source string.
+ * @param[out] in6_addr Output struct.
+ *
+ ******************************************************************************
+ */
+
+static void
+Ip6StringToIn6Addr(const char *ip6String,
+ struct in6_addr *in6_addr)
+{
+ unsigned int i;
+
+ ASSERT(strlen(ip6String) == 32);
+
+ for (i = 0; i < 16; i++) {
+ int nmatched;
+ nmatched = sscanf(&ip6String[2 * i], "%2hhx", &in6_addr->s6_addr[i]);
+ ASSERT(nmatched == 1);
+ }
+}
+
+
+/*
+ ******************************************************************************
+ * MatchToGuint64 -- */ /**
+ *
+ * @brief Wrapper around @c g_ascii_strtoull and @c g_match_info_fetch.
+ *
+ * @param[in] matchInfo Source regular expression match context.
+ * @param[in] matchIndex Match number to fetch.
+ * @param[in] base Base represented by matched string.
+ * (See @c g_ascii_strtoull docs.)
+ *
+ ******************************************************************************
+ */
+
+static guint64
+MatchToGuint64(const GMatchInfo *matchInfo,
+ const gint matchIndex,
+ gint base)
+{
+ guint64 retval;
+ MATCHEXPR(matchInfo, matchIndex, retval = g_ascii_strtoull(MATCH, NULL, base));
+ return retval;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file netInt.h
+ *
+ * SlashProcNet internal bits.
+ */
+
+#ifndef _SLASHPROCNETINT_H_
+#define _SLASHPROCNETINT_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#include "includeCheck.h"
+
+#ifdef VMX86_DEVEL
+EXTERN void SlashProcNetSetPathSnmp(const char *newPathToNetSnmp);
+EXTERN void SlashProcNetSetPathSnmp6(const char *newPathToNetSnmp6);
+EXTERN void SlashProcNetSetPathRoute(const char *newPathToNetRoute);
+EXTERN void SlashProcNetSetPathRoute6(const char *newPathToNetRoute6);
+#endif // ifdef VMX86_DEVEL
+
+#endif // ifndef _SLASHPROCNETINT_H_
+
vmimage.bytesPerLine = ximage->bytes_per_line;
vmimage.data = ximage->data;
- if (ImageUtil_ConstructPNGBuffer(&vmimage, imageData)) {
+ if (ImageUtil_ConstructPNGBuffer(&vmimage, NULL, imageData)) {
result = TRUE;
}
case UNITY_UPDATE_CHANGE_ZORDER:
UnityWindowTracker_SetZOrder(tracker, update->u.zorder.ids,
update->u.zorder.count);
+ /*
+ * This function is only every called from the host. Thus, if we get
+ * a zorder changed event from the guest it's safe to blindly trust it
+ * mark the zorder as changed. See bug 409742 for more info.
+ */
+ tracker->zorderChanged = TRUE;
break;
case UNITY_UPDATE_CHANGE_WINDOW_STATE:
#include "cpuid_info.h"
#include "hostinfo.h"
+#include "util.h"
#define LOGLEVEL_MODULE hostinfo
#include "loglevel_user.h"
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * Hostinfo_HypervisorCPUIDSig --
+ *
+ * Get the hypervisor signature string from CPUID.
+ *
+ * Results:
+ * Unqualified 16 byte nul-terminated hypervisor string
+ * String may contain garbage and caller must free
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Hostinfo_HypervisorCPUIDSig(void)
+{
+ CPUIDRegs regs;
+ uint32 *name;
+
+ name = Util_SafeMalloc(4 * sizeof *name);
+
+ __GET_CPUID(0x40000000, ®s);
+ name[0] = regs.ebx;
+ name[1] = regs.ecx;
+ name[2] = regs.edx;
+ name[3] = 0;
+
+ return (char *)name;
+}
+
+
/*
*----------------------------------------------------------------------
*
*
* Check for Xen.
*
- * Official way is to check CPUID function 0x4000 0000, which
- * returns a hypervisor string. See PR156185,
+ * Official way is to call Hostinfo_HypervisorCPUIDSig(), which
+ * returns a hypervisor string. This is a secondary check
+ * that guards against a backdoor failure. See PR156185,
* http://xenbits.xensource.com/xen-unstable.hg?file/6a383beedf83/tools/misc/xen-detect.c
* (Canonical way is /proc/xen, but CPUID is better).
*
Bool
Hostinfo_TouchXen(void)
{
+#ifdef linux
#define XEN_CPUID 0x40000000
#define XEN_STRING "XenVMMXenVMM"
CPUIDRegs regs;
uint32 name[4];
- /*
- * HVM mode: simple cpuid instr
- * Xen hypervisor traps CPUID and adds information leaf(s)
- * at CPUID leaf XEN_CPUID and higher.
- */
- __GET_CPUID(XEN_CPUID, ®s);
- name[0] = regs.ebx;
- name[1] = regs.ecx;
- name[2] = regs.edx;
- name[3] = 0;
- if (0 == strcmp(XEN_STRING, (const char*)name)) {
- return TRUE;
- }
-
-#ifdef linux
/*
* PV mode: ud2a "xen" cpuid (faults on native hardware).
* (Only Linux can run PV, so skip others here).
*/
uint32
-Util_Checksum32(uint32 *buf, int len)
+Util_Checksum32(const uint32 *buf, int len)
{
uint32 checksum = 0;
int i;
*/
uint32
-Util_Checksum(uint8 *buf, int len)
+Util_Checksum(const uint8 *buf, int len)
{
uint32 checksum;
int remainder, shift;
Bool
Util_Data2Buffer(char *buf, // OUT
size_t bufSize, // IN
- const void* data0, // IN
+ const void *data0, // IN
size_t dataSize) // IN
{
- char* cp = buf;
- const uint8* data = (const uint8*) data0;
- size_t n = MIN(dataSize, ((bufSize-1) / 3));
-
- while (n > 0) {
- Str_Sprintf(cp, 4, " %02X", *data);
- cp += 3;
- data++, n--;
+ size_t n;
+
+ /* At least 1 byte (for NUL) must be available. */
+ if (!bufSize) {
+ return FALSE;
+ }
+
+ bufSize = bufSize / 3;
+ n = MIN(dataSize, bufSize);
+ if (n != 0) {
+ const uint8 *data = data0;
+
+ while (n > 0) {
+ static const char digits[] = "0123456789ABCDEF";
+
+ *buf++ = digits[*data >> 4];
+ *buf++ = digits[*data & 0xF];
+ *buf++ = ' ';
+ data++;
+ n--;
+ }
+ buf--;
}
- *cp = '\0';
- return (dataSize <= bufSize);
+ *buf = 0;
+ return dataSize <= bufSize;
}
int err;
/*
- * Check for minimum file descriptor limit. The number 2048 is
+ * Check for minimum file descriptor limit. The number is
* somewhat arbitrary. Trying to do multiple snapshots of a split
* disk can rapidly consume descriptors however, so we ought to
* have a large number. This is only pushing back the problem of
* course. Ideally we'd have a fully scalable solution.
*/
+#if __APPLE__
+ static const rlim_t fdsDesired = 8192;
+#else
static const rlim_t fdsDesired = 2048;
+#endif
err = getrlimit(RLIMIT_NOFILE, &lim);
ASSERT_NOT_IMPLEMENTED(err >= 0);
#include "registryWin32.h"
#include "win32u.h"
#endif /* _WIN32 */
+#include "hgfsHelper.h"
#ifdef linux
#include "mntinfo.h"
static VixError VixTools_Base64EncodeBuffer(char **resultValuePtr, size_t *resultValLengthPtr);
+static VixError VixToolsSetSharedFoldersProperties(VixPropertyListImpl *propList);
+
#if defined(_WIN32)
static HRESULT VixToolsEnableDHCPOnPrimary(void);
goto abort;
}
+ /* Retrieve the share folders UNC root path. */
+ err = VixToolsSetSharedFoldersProperties(&propList);
+
/*
* Serialize the property list to buffer then encode it.
* This is the string we return to the VMX process.
VixPropertyList_Initialize(&propList);
+ /* Retrieve the share folders UNC root path. */
+ err = VixToolsSetSharedFoldersProperties(&propList);
+
/*
* Serialize the property list to buffer then encode it.
* This is the string we return to the VMX process.
} // VixTools_GetToolsPropertiesImpl
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsSetSharedFoldersProperties --
+ *
+ * Set information about the shared folders feature.
+ *
+ * Return value:
+ * VixError
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VixError
+VixToolsSetSharedFoldersProperties(VixPropertyListImpl *propList) // IN
+{
+ VixError err = VIX_OK;
+
+ /* Retrieve the share folders UNC root path. */
+ Unicode hgfsRootPath = NULL;
+
+ if (!HgfsHlpr_QuerySharesDefaultRootPath(&hgfsRootPath)) {
+ /* Exit ok as we have nothing to set from shared folders. */
+ goto exit;
+ }
+
+ ASSERT(hgfsRootPath != NULL);
+
+ err = VixPropertyList_SetString(propList,
+ VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH,
+ UTF8(hgfsRootPath));
+ if (VIX_OK != err) {
+ goto exit;
+ }
+
+exit:
+ if (hgfsRootPath != NULL) {
+ HgfsHlpr_FreeSharesRootPath(hgfsRootPath);
+ }
+ return err;
+}
+
+
#if 0
/*
*-----------------------------------------------------------------------------
#ifdef _WIN32
char *currentUser = NULL;
DWORD currentUserSize = 0;
-
+ DWORD retVal = 0;
+ HANDLE processToken = INVALID_HANDLE_VALUE;
+ PTOKEN_USER processTokenInfo = NULL;
+ DWORD processTokenInfoSize = 0;
+ Unicode sidUserName = NULL;
+ DWORD sidUserNameSize = 0;
+ Unicode sidDomainName = NULL;
+ DWORD sidDomainNameSize = 0;
+ SID_NAME_USE sidNameUse;
+
/*
- * For Windows, get the name of the owner of this process, then
- * compare it to the provided username.
+ * Check to see if the user provided a '<Domain>\<User>' formatted username
*/
- if (!Win32U_GetUserName(currentUser, ¤tUserSize)) {
+ if (NULL != Str_Strchr(username, '\\')) {
+ /*
+ * A '<Domain>\<User>' formatted username was provided.
+ * We must retrieve the domain as well as the username to verify
+ * the current vixtools user matches the username provided
+ */
+ retVal = OpenProcessToken(GetCurrentProcess(),
+ TOKEN_READ,
+ &processToken);
+
+ if (!retVal || !processToken) {
+ Warning("unable to open process token: windows error code %d\n",
+ GetLastError());
+ err = FoundryToolsDaemon_TranslateSystemErr();
+
+ goto abort;
+ }
+
+ // Determine necessary buffer size
+ GetTokenInformation(processToken,
+ TokenUser,
+ NULL,
+ 0,
+ &processTokenInfoSize);
+
if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+ Warning("unable to get token info: windows error code %d\n",
+ GetLastError());
err = FoundryToolsDaemon_TranslateSystemErr();
goto abort;
}
- currentUser = Util_SafeMalloc(currentUserSize);
+ processTokenInfo = Util_SafeMalloc(processTokenInfoSize);
- if (!Win32U_GetUserName(currentUser, ¤tUserSize)) {
+ if (!GetTokenInformation(processToken,
+ TokenUser,
+ processTokenInfo,
+ processTokenInfoSize,
+ &processTokenInfoSize)) {
+ Warning("unable to get token info: windows error code %d\n",
+ GetLastError());
+ err = FoundryToolsDaemon_TranslateSystemErr();
+ goto abort;
+ }
+
+ // Retrieve user name and domain name based on user's SID.
+ Win32U_LookupAccountSid(NULL,
+ processTokenInfo->User.Sid,
+ NULL,
+ &sidUserNameSize,
+ NULL,
+ &sidDomainNameSize,
+ &sidNameUse);
+
+ if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+ Warning("unable to lookup account sid: windows error code %d\n",
+ GetLastError());
err = FoundryToolsDaemon_TranslateSystemErr();
goto abort;
}
+
+ sidUserName = Util_SafeMalloc(sidUserNameSize);
+ sidDomainName = Util_SafeMalloc(sidDomainNameSize);
+
+ if (!Win32U_LookupAccountSid(NULL,
+ processTokenInfo->User.Sid,
+ sidUserName,
+ &sidUserNameSize,
+ sidDomainName,
+ &sidDomainNameSize,
+ &sidNameUse)) {
+ Warning("unable to lookup account sid: windows error code %d\n",
+ GetLastError());
+ err = FoundryToolsDaemon_TranslateSystemErr();
+ goto abort;
+ }
+
+ // Populate currentUser with Domain + '\' + Username
+ currentUser = Str_SafeAsprintf(NULL, "%s\\%s", sidDomainName, sidUserName);
+ } else {
+ /*
+ * For Windows, get the name of the owner of this process, then
+ * compare it to the provided username.
+ */
+ if (!Win32U_GetUserName(currentUser, ¤tUserSize)) {
+ if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+ err = FoundryToolsDaemon_TranslateSystemErr();
+ goto abort;
+ }
+
+ currentUser = Util_SafeMalloc(currentUserSize);
+
+ if (!Win32U_GetUserName(currentUser, ¤tUserSize)) {
+ err = FoundryToolsDaemon_TranslateSystemErr();
+ goto abort;
+ }
+ }
}
if (0 != Unicode_CompareIgnoreCase(username, currentUser)) {
err = VIX_OK;
abort:
+ free(sidDomainName);
+ free(sidUserName);
+ free(processTokenInfo);
+ CloseHandle(processToken);
free(currentUser);
#else /* Below is the POSIX case. */
noinst_LTLIBRARIES = libWiper.la
libWiper_la_SOURCES =
+libWiper_la_SOURCES += wiperCommon.c
libWiper_la_SOURCES += wiperPosix.c
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * wiperCommon.c --
+ *
+ * OS-agnostic parts of the library for wiping a virtual disk.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "dbllnklst.h"
+#include "wiper.h"
+#include "util.h"
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * WiperSinglePartition_Allocate --
+ *
+ * Allocates and initialized empty WiperPartition structure.
+ *
+ * Results:
+ * NULL if there is no memory, otherwise a pointer to newly allocated
+ * WiperPartition structure.
+ *
+ * Side Effects:
+ * Allocates memory.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+WiperPartition *
+WiperSinglePartition_Allocate(void)
+{
+ WiperPartition *p = (WiperPartition *) malloc(sizeof *p);
+
+ if (p != NULL) {
+ memset(p->mountPoint, 0, sizeof p->mountPoint);
+ p->type = PARTITION_UNSUPPORTED;
+ p->comment = NULL;
+ DblLnkLst_Init(&p->link);
+ }
+
+ return p;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * WiperSinglePartition_Close --
+ *
+ * Destroy the information returned by a previous call to
+ * WiperSinglePartition_Allocate(). The partition should be removed
+ * from all lists prior to calling WiperSinglePartition_Close().
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Frees memory occupied by the element.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+WiperSinglePartition_Close(WiperPartition *p) // IN
+{
+ if (p) {
+ free((char *)p->comment); /* Casting away constness */
+ free(p);
+ }
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * WiperPartition_Close --
+ *
+ * Destroy the information collected by previous call to
+ * WiperPartition_Open().
+ *
+ * Results:
+ * None
+ *
+ * Side Effects:
+ * Frees memory occupied by elements of the list.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+WiperPartition_Close(WiperPartition_List *pl) // IN/OUT
+{
+ DblLnkLst_Links *curr, *next;
+
+ DblLnkLst_ForEachSafe(curr, next, &pl->link) {
+ WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link);
+
+ DblLnkLst_Unlink1(curr);
+ WiperSinglePartition_Close(part);
+ }
+}
+
#include "vmstdio.h"
#include "mntinfo.h"
#include "posix.h"
+#include "util.h"
/* Number of bytes per disk sector */
MNTINFO *mnt) // IN
{
struct stat s;
+ const char *comment = NULL;
+
+ item->type = PARTITION_UNSUPPORTED;
/*
* Let's ignore remote filesystems before we do a stat(2) on the actual
*/
if (strcmp(MNTINFO_FSTYPE(mnt), "autofs") == 0) {
/* XXX Should we look at autofs' config files? --hpreg */
- item->comment = "Not implemented. Contact VMware";
- return;
- }
+ comment = "Not implemented. Contact VMware";
- if (strcmp(MNTINFO_FSTYPE(mnt), "vmhgfs") == 0) {
- item->comment = "Remote partition";
- return;
- }
+ } else if (strcmp(MNTINFO_FSTYPE(mnt), "vmhgfs") == 0) {
+ comment = "Remote partition";
- if (strcmp(MNTINFO_FSTYPE(mnt), "nfs") == 0) {
- item->comment = "Remote filesystem";
- return;
- }
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "nfs") == 0) {
+ comment = "Remote filesystem";
- if (strcmp(MNTINFO_FSTYPE(mnt), "smbfs") == 0) {
- item->comment = "Remote filesystem";
- return;
- }
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "smbfs") == 0) {
+ comment = "Remote filesystem";
- if (strcmp(MNTINFO_FSTYPE(mnt), "swap") == 0) {
- item->comment = "Swap partition";
- return;
- }
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "swap") == 0) {
+ comment = "Swap partition";
- if (strcmp(MNTINFO_FSTYPE(mnt), PROCFS) == 0) {
- item->comment = "Proc partition";
- return;
- }
+ } if (strcmp(MNTINFO_FSTYPE(mnt), PROCFS) == 0) {
+ comment = "Proc partition";
- if (strcmp(MNTINFO_FSTYPE(mnt), "devpts") == 0) {
- item->comment = "Devpts partition";
- return;
- }
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "devpts") == 0) {
+ comment = "Devpts partition";
- if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) {
- item->comment = "Unknown device";
- return;
- }
+ } if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) {
+ comment = "Unknown device";
#if defined(sun) || defined(__linux__)
- if (! S_ISBLK(s.st_mode)) {
- item->comment = "Not a block device";
- return;
- }
+ } else if (! S_ISBLK(s.st_mode)) {
+ comment = "Not a block device";
#endif
- if (!WiperIsDiskDevice(mnt, &s)) {
- item->comment = "Not a disk device";
- return;
- }
+ } else if (!WiperIsDiskDevice(mnt, &s)) {
+ comment = "Not a disk device";
- if (MNTINFO_MNT_IS_RO(mnt)) {
- item->comment = "Not writable";
- return;
- }
+ } if (MNTINFO_MNT_IS_RO(mnt)) {
+ comment = "Not writable";
- if (strcmp(MNTINFO_FSTYPE(mnt), "ext2") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "ext2") == 0) {
item->type = PARTITION_EXT2;
- return;
- }
- if (strcmp(MNTINFO_FSTYPE(mnt), "ext3") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "ext3") == 0) {
item->type = PARTITION_EXT3;
- return;
- }
- if (strcmp(MNTINFO_FSTYPE(mnt), "reiserfs") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "reiserfs") == 0) {
item->type = PARTITION_REISERFS;
- return;
- }
- if (strcmp(MNTINFO_FSTYPE(mnt), "ntfs") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "ntfs") == 0) {
item->type = PARTITION_NTFS;
- return;
- }
- if (strcmp(MNTINFO_FSTYPE(mnt), "vfat") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "vfat") == 0) {
item->type = PARTITION_FAT;
- return;
- }
- if (strcmp(MNTINFO_FSTYPE(mnt), "ufs") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "ufs") == 0) {
item->type = PARTITION_UFS;
- return;
- }
- if (strcmp(MNTINFO_FSTYPE(mnt), "pcfs") == 0) {
- item->comment = "";
+ } if (strcmp(MNTINFO_FSTYPE(mnt), "pcfs") == 0) {
item->type = PARTITION_PCFS;
- return;
- }
- item->comment = "Unknown filesystem. Contact VMware";
- return;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * SingleWiperPartition_Close --
- *
- * Destroy the information returned by a previous call to
- * SingleWiperPartition_Open().
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
+ } else {
+ comment = "Unknown filesystem. Contact VMware";
+ }
-void
-SingleWiperPartition_Close(WiperPartition *p) // IN
-{
- free(p);
+ if (item->type == PARTITION_UNSUPPORTED) {
+ ASSERT(comment);
+ item->comment = Util_SafeStrdup(comment);
+ }
}
/*
*-----------------------------------------------------------------------------
*
- * SingleWiperPartition_Open --
+ * WiperSinglePartition_Open --
*
* Return information about the input 'mountPoint' partition.
*
*/
WiperPartition *
-SingleWiperPartition_Open(const char *mountPoint) // IN
+WiperSinglePartition_Open(const char *mountPoint) // IN
{
char *mntpt = NULL;
MNTHANDLE fp;
int len = 0;
DECLARE_MNTINFO(mnt);
- WiperPartition *p;
+ WiperPartition *p = NULL;
ASSERT(initDone);
- fp = NULL;
- p = (WiperPartition *) malloc(sizeof *p);
- if (p == NULL) {
- Log("Not enough memory while opening a partition.\n");
- goto error;
- }
fp = OPEN_MNTFILE("r");
if (fp == NULL) {
Log("Could not open %s\n", MNTFILE);
- goto error;
+ return NULL;
}
mntpt = Util_SafeStrdup(mountPoint);
len = strlen(mntpt);
while (GETNEXT_MNTINFO(fp, mnt)) {
if (strncmp(MNTINFO_MNTPT(mnt), mntpt, len) == 0) {
- if (Str_Snprintf(p->mountPoint, NATIVE_MAX_PATH,
- "%s", MNTINFO_MNTPT(mnt)) == -1) {
+
+ p = WiperSinglePartition_Allocate();
+ if (p == NULL) {
+ Log("Not enough memory while opening a partition.\n");
+ } else if (Str_Snprintf(p->mountPoint, NATIVE_MAX_PATH,
+ "%s", MNTINFO_MNTPT(mnt)) == -1) {
Log("NATIVE_MAX_PATH is too small.\n");
- goto error;
+ WiperSinglePartition_Close(p);
+ p = NULL;
+ } else {
+ WiperCollectDiskMajors();
+ WiperPartitionFilter(p, mnt);
}
- WiperCollectDiskMajors();
- WiperPartitionFilter(p, mnt);
- (void) CLOSE_MNTFILE(fp);
-
- fp = NULL;
-
- free(mntpt);
- return p;
+ goto out;
}
}
Log("Could not find a mount point for %s in %s\n", mntpt, MNTFILE);
- error:
- SingleWiperPartition_Close(p);
- if (fp != NULL) {
- (void) CLOSE_MNTFILE(fp);
- fp = NULL;
- }
+ out:
free(mntpt);
- return NULL;
+ (void) CLOSE_MNTFILE(fp);
+ return p;
}
/*
*-----------------------------------------------------------------------------
*/
-WiperPartition_List *
-WiperPartition_Open(void)
+Bool
+WiperPartition_Open(WiperPartition_List *pl)
{
- WiperPartition_List *pl;
MNTHANDLE fp;
DECLARE_MNTINFO(mnt);
+ Bool rc = TRUE;
ASSERT(initDone);
- fp = NULL;
- pl = (WiperPartition_List *)malloc(sizeof *pl);
- if (pl == NULL) {
- Log("Not enough memory while opening a partition.\n");
- goto error;
- }
-
- pl->partitions = NULL;
- pl->size = 0;
+ DblLnkLst_Init(&pl->link);
/* Basically call functions to parse /etc/mtab ... */
fp = OPEN_MNTFILE("r");
if (fp == NULL) {
Log("Unable to open mount file.\n");
- goto error;
+ return FALSE;
}
WiperCollectDiskMajors();
while (GETNEXT_MNTINFO(fp, mnt)) {
- WiperPartition item;
-
- if (Str_Snprintf(item.mountPoint, NATIVE_MAX_PATH, "%s",
- MNTINFO_MNTPT(mnt)) == -1) {
- Log("NATIVE_MAX_PATH is too small.\n");
- goto error;
- }
-
- WiperPartitionFilter(&item, mnt);
+ WiperPartition *part = WiperSinglePartition_Allocate();
- /* Add the partition to the list */
- pl->partitions = (WiperPartition *)realloc(pl->partitions,
- (pl->size + 1) *
- sizeof *pl->partitions);
- if (pl->partitions == NULL) {
+ if (part == NULL) {
Log("Not enough memory while opening a partition.\n");
- goto error;
+ rc = FALSE;
+ break;
}
- pl->partitions[pl->size] = item;
- pl->size++;
- }
-
- (void) CLOSE_MNTFILE(fp);
- fp = NULL;
-
- return pl;
+ if (Str_Snprintf(part->mountPoint, NATIVE_MAX_PATH, "%s",
+ MNTINFO_MNTPT(mnt)) == -1) {
+ Log("NATIVE_MAX_PATH is too small.\n");
+ WiperSinglePartition_Close(part);
+ rc = FALSE;
+ break;
+ }
-error:
- WiperPartition_Close(pl);
- pl = NULL;
- if (fp != NULL) {
- (void) CLOSE_MNTFILE(fp);
- fp = NULL;
+ WiperPartitionFilter(part, mnt);
+ DblLnkLst_LinkLast(&pl->link, &part->link);
}
- return NULL;
-}
+ if (!rc)
+ WiperPartition_Close(pl);
-/*
- *-----------------------------------------------------------------------------
- *
- * WiperPartition_Close --
- *
- * Destroy the information returned by a previous call to
- * WiperPartition_Open()
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-WiperPartition_Close(WiperPartition_List *pl) // IN/OUT
-{
- if (pl != NULL) {
- free(pl->partitions);
- pl->partitions = NULL;
- free(pl);
- }
+ (void) CLOSE_MNTFILE(fp);
+ return rc;
}
-
-
/*
*-----------------------------------------------------------------------------
*
libvmtools_la_LIBADD += @GLIB2_LIBS@
libvmtools_la_LIBADD += @ICU_LIBS@
+if LINUX
+libvmtools_la_LIBADD += ../lib/slashProc/libSlashProc.la
+endif
+
libvmtools_la_SOURCES =
libvmtools_la_SOURCES += signalSource.c
libvmtools_la_SOURCES += vmtools.c
* used for reliable event delivery.
*/
+#include "vm_assert.h"
#include "vmtools.h"
#include <errno.h>
#include <fcntl.h>
return;
} else {
/* XXX: Maybe we should handle this in some other way? */
- g_assert(nbytes == sizeof info);
+ ASSERT(nbytes == sizeof info);
}
memcpy(&gHandler.currSignal, &info, sizeof info);
gHandler.signals[info.si_signo] = SIG_SRC_SIGNALED;
* have to be created...
*/
g_warning("Too many signals queued, this shouldn't happen.\n");
- g_assert(FALSE);
+ ASSERT(FALSE);
} else {
g_warning("Could not queue signal %d (error %d: %s)\n",
signum, errno, strerror(errno));
};
SignalSource *ret;
- g_assert(signum < MAX_SIGNALS);
- g_assert(signum != SIGKILL && signum != SIGSTOP);
+ ASSERT(signum < MAX_SIGNALS);
+ ASSERT(signum != SIGKILL && signum != SIGSTOP);
G_LOCK(gLock);
if (!gHandler.initialized) {
if (pipe(gHandler.wakeupPipe) == -1 ||
fcntl(gHandler.wakeupPipe[0], F_SETFL, O_RDONLY | O_NONBLOCK) < 0 ||
fcntl(gHandler.wakeupPipe[1], F_SETFL, O_WRONLY | O_NONBLOCK) < 0) {
- g_assert(FALSE);
+ ASSERT(FALSE);
}
gHandler.wakeupFd.fd = gHandler.wakeupPipe[0];
gHandler.wakeupFd.events = G_IO_IN | G_IO_ERR;
VM_EMBED_VERSION(VMTOOLSLIB_VERSION_STRING);
#endif
-extern void VMTools_ResetLogging(gboolean cleanDefault);
-
/**
* A convenience function for wrapping an array with a GArray instance.
VMTools_ResetLogging(FALSE);
wiperData.resourceModule = lib;
success = (NetUtil_LoadIpHlpApiDll() == ERROR_SUCCESS);
- g_assert(success);
+ ASSERT(success);
success = Wiper_Init(&wiperData);
- g_assert(success);
+ ASSERT(success);
#else
VMTools_ResetLogging(FALSE);
success = Wiper_Init(NULL);
* and vmware-user. Instead of baking in the library whether we're
* running one or the other, separate the two configurations, so that
* the user can choose a different location for one or another.
+ *
+ * Also append the PID to the vmusr log path, since the old code did
+ * that automatically.
*/
gchar *userlog;
g_key_file_set_string(cfg, entry->destGroup,
VMTOOLS_GUEST_SERVICE ".data", value);
- userlog = g_strdup_printf("%s.user", value);
+ userlog = g_strdup_printf("%s.user.${PID}", value);
g_key_file_set_string(cfg, entry->destGroup,
VMTOOLS_USER_SERVICE ".handler", "file");
g_key_file_set_string(cfg, entry->destGroup,
g_key_file_set_string(cfg, entry->destGroup,
VMTOOLS_USER_SERVICE ".data", userlog);
+ /*
+ * Keep the log.file entry since vmware-user is still using the old-style
+ * config. This can go away once it's ported over.
+ */
+ g_key_file_set_string(cfg, entry->destGroup, CONFNAME_LOGFILE, value);
+
g_free(userlog);
}
for (entry = entries; entry->key != NULL; entry++) {
const char *value = GuestApp_GetDictEntry(old, entry->key);
const char *dfltValue = GuestApp_GetDictEntryDefault(old, entry->key);
-
+
if (value == NULL || (dfltValue != NULL && strcmp(value, dfltValue) == 0)) {
continue;
}
+
switch (entry->type) {
case CFG_BOOLEAN:
{
}
case CFG_STRING:
- {
- const char *val = GuestApp_GetDictEntry(old, entry->key);
- if (val != NULL) {
- g_key_file_set_string(dst, entry->destGroup, entry->destKey, val);
- }
- break;
- }
+ g_key_file_set_string(dst, entry->destGroup, entry->destKey, value);
+ break;
case CFG_CALLBACK:
- {
- const char *val = GuestApp_GetDictEntry(old, entry->key);
- if (val != NULL) {
- g_assert(entry->data);
- ((CfgCallback)entry->data)(dst, entry, val);
- }
- break;
- }
+ ASSERT(entry->data);
+ ((CfgCallback)entry->data)(dst, entry, value);
+ break;
default:
- g_assert_not_reached();
+ NOT_REACHED();
}
}
}
*/
if (confPath == NULL) {
confPath = GuestApp_GetConfPath();
- g_assert(confPath != NULL);
+ ASSERT(confPath != NULL);
}
confFilePath = g_strdup_printf("%s%c%s", confPath, DIRSEPC, CONF_FILE);
free(confPath);
gboolean ret = FALSE;
GKeyFile *newConfig = NULL;
- g_assert(config != NULL);
- g_assert(mtime != NULL);
+ ASSERT(config != NULL);
+ ASSERT(mtime != NULL);
if (g_stat(path, &confStat) == -1) {
- g_warning("Failed to stat conf file: %s\n", strerror(errno));
+ g_debug("Failed to stat conf file: %s\n", strerror(errno));
goto exit;
}
FILE *out = NULL;
GError *lerr = NULL;
- g_assert(path != NULL);
- g_assert(config != NULL);
+ ASSERT(path != NULL);
+ ASSERT(config != NULL);
localPath = VMTOOLS_GET_FILENAME_LOCAL(path, &lerr);
if (lerr != NULL) {
gpointer _data);
#endif
-void VMTools_ResetLogging(gboolean cleanDefault);
-
typedef struct LogHandlerData {
gchar *domain;
GLogLevelFlags mask;
FILE *file;
gchar *path;
+ gboolean append;
guint handlerId;
gboolean inherited;
} LogHandlerData;
* present. Only one old log file is preserved.
*
* @param[in] path Path to log file.
+ * @param[in] append Whether to open the log for appending (if TRUE, a backup
+ * file is not generated).
*
* @return File pointer for writing to the file (NULL on error).
*/
static FILE *
-VMToolsLogOpenFile(const gchar *path)
+VMToolsLogOpenFile(const gchar *path,
+ gboolean append)
{
FILE *logfile = NULL;
gchar *pathLocal;
ASSERT(path != NULL);
pathLocal = VMTOOLS_GET_FILENAME_LOCAL(path, NULL);
- if (g_file_test(path, G_FILE_TEST_EXISTS)) {
+ if (!append && g_file_test(path, G_FILE_TEST_EXISTS)) {
/* Back up existing log file. */
gchar *bakFile = g_strdup_printf("%s.old", pathLocal);
if (!g_file_test(bakFile, G_FILE_TEST_IS_DIR) &&
g_free(bakFile);
}
- logfile = g_fopen(pathLocal, "w");
+ logfile = g_fopen(pathLocal, append ? "a" : "w");
VMTOOLS_RELEASE_FILENAME_LOCAL(pathLocal);
return logfile;
}
FILE *dest;
data = data->inherited ? gDefaultData : data;
if (data->file == NULL && data->path != NULL) {
- data->file = VMToolsLogOpenFile(data->path);
+ data->file = VMToolsLogOpenFile(data->path, data->append);
if (data->file == NULL) {
g_warning("Unable to open log file %s for domain %s.\n",
data->domain, data->path);
}
} else if (strcmp(handler, "std") == 0) {
handlerFn = VMToolsLogFile;
- } else if (strcmp(handler, "file") == 0) {
+ } else if (strcmp(handler, "file") == 0 ||
+ strcmp(handler, "file+") == 0) {
/* Don't set up the file sink if logging is disabled. */
if (strcmp(level, "none") != 0) {
handlerFn = VMToolsLogFile;
data->domain = g_strdup(domain);
data->mask = levelsMask;
data->path = logpath;
+ data->append = (handler != NULL && strcmp(handler, "file+") == 0);
logpath = NULL;
if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) {
- /* Replace the default log configuration before freeing the old data. */
+ /*
+ * Replace the global log configuration. If the default log domain was
+ * logging to a file and the file path hasn't changed, then keep the old
+ * file handle open, instead of rotating the log.
+ */
LogHandlerData *old = gDefaultData;
- LogHandlerData *gdata = g_malloc0(sizeof *gdata);
- memcpy(gdata, data, sizeof *gdata);
- g_log_set_default_handler(handlerFn, gdata);
+ if (old->file != NULL) {
+ ASSERT(old->path);
+ if (data->path != NULL && strcmp(data->path, old->path) == 0) {
+ g_free(data->path);
+ data->file = old->file;
+ data->path = old->path;
+ old->path = NULL;
+ } else {
+ fclose(old->file);
+ g_free(old->path);
+ }
+ }
- gDefaultData = gdata;
+ g_log_set_default_handler(handlerFn, data);
+ gDefaultData = data;
+ data = NULL;
gDefaultLogFunc = handlerFn;
g_free(old);
} else if (handler == NULL) {
data->inherited = TRUE;
}
- if (gDomains == NULL) {
- gDomains = g_ptr_array_new();
+ if (data != NULL) {
+ if (gDomains == NULL) {
+ gDomains = g_ptr_array_new();
+ }
+ g_ptr_array_add(gDomains, data);
+ data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS | G_LOG_FATAL_MASK,
+ handlerFn, data);
}
- g_ptr_array_add(gDomains, data);
- data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS | G_LOG_FATAL_MASK,
- handlerFn, data);
exit:
g_free(handler);
void
VMTools_SetDefaultLogDomain(const gchar *domain)
{
- g_assert(domain != NULL);
+ ASSERT(domain != NULL);
if (gLogDomain != NULL) {
g_free(gLogDomain);
}
VMTools_ResetLogging(gboolean cleanDefault)
{
gboolean oldLogEnabled = gLogEnabled;
+ gchar *currentPath = NULL;
+ FILE *currentFile = NULL;
/* Disable logging while we're playing with the configuration. */
gLogEnabled = FALSE;
}
if (gDefaultData != NULL) {
+ currentFile = gDefaultData->file;
+ currentPath = gDefaultData->path;
g_free(gDefaultData);
gDefaultData = NULL;
}
#if defined(VMX86_DEBUG)
gDefaultData->mask |= G_LOG_LEVEL_MESSAGE;
#endif
+ gDefaultData->file = currentFile;
+ gDefaultData->path = currentPath;
gLogEnabled = oldLogEnabled;
g_log_set_default_handler(gDefaultLogFunc, gDefaultData);
+ } else {
+ if (currentFile != NULL) {
+ fclose(currentFile);
+ }
+ g_free(currentPath);
}
}
#include <sys/param.h>
#include "compat_vop.h"
+#include "compat_mount.h"
+#include "compat_priv.h"
/*
* FreeBSD version 8 and above uses the kproc API instead of the kthread API in its
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*********************************************************
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of VMware Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission of VMware Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_MOUNT_H__
+# define __COMPAT_MOUNT_H__ 1
+
+#if __FreeBSD_version >= 800011
+#define COMPAT_VFS_STATFS(mp, sbp, threadvar) VFS_STATFS((mp), (sbp))
+#define compat_td curthread
+#else
+#define COMPAT_VFS_STATFS(mp, sbp, threadvar) VFS_STATFS((mp), (sbp), (threadvar))
+#define compat_td td
+#endif
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*********************************************************
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of VMware Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission of VMware Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_PRIV_H__
+# define __COMPAT_PRIV_H__ 1
+
+#if __FreeBSD_version >= 800011
+#define compat_priv_check(td, priv) priv_check((td), (priv))
+#else
+#define compat_priv_check(td, priv) suser(td)
+#endif
+
+#endif
#define compat_lockstatus(lock, threadvar) lockstatus((lock))
#define compat_lockmgr(lock, flags, randompointerparam, threadval) lockmgr((lock), (flags), (randompointerparam))
#define compat_vn_lock(vp, flags, threadval) vn_lock((vp), (flags))
+#define compat_accmode_t accmode_t
+#define compat_a_accmode a_accmode
#else
#define COMPAT_THREAD_VAR(varname, varval) struct thread *varname = varval
#define COMPAT_VOP_LOCK(vop, flags, threadvar) VOP_LOCK((vop), (flags), (threadvar))
#define compat_lockstatus(lock, threadvar) lockstatus((lock), (threadvar))
#define compat_vn_lock(vp, flags, threadval) vn_lock((vp), (flags), (threadval))
#define compat_lockmgr(lock, flags, randompointerparam, threadval) lockmgr((lock), (flags), (randompointerparam), (threadval))
+#define compat_accmode_t mode_t
+#define compat_a_accmode a_mode
#endif
/*
#include <sys/vnode.h>
#include <sys/file.h>
+#include "compat_freebsd.h"
+
#include "vmblock_k.h"
#include "block.h"
VMBlockHashGet(struct mount *mp, // IN: vmblock file system information
struct vnode *lowervp) // IN: lower vnode to search for
{
- struct thread *td = curthread; /* XXX */
struct nodeHashHead *hd;
struct VMBlockNode *a;
struct vnode *vp;
- int error;
ASSERT_VOP_LOCKED(lowervp, "hashEntryget");
mtx_lock(&hashMutex);
LIST_FOREACH(a, hd, hashEntry) {
if (a->lowerVnode == lowervp && VMBTOVP(a)->v_mount == mp) {
- vp = VMBTOVP(a);
- VI_LOCK(vp);
- mtx_unlock(&hashMutex);
- /*
- * We need to clear the OWEINACT flag here as this may lead vget()
- * to try to lock our vnode which is already locked via lowervp.
- */
- vp->v_iflag &= ~VI_OWEINACT;
- error = vget(vp, LK_INTERLOCK, td);
/*
* Since we have the lower node locked the nullfs node can not be
* in the process of recycling. If it had been recycled before we
* grabed the lower lock it would not have been found on the hash.
*/
- if (error) {
- panic("hashEntryget: vget error %d", error);
- }
+ vp = VMBTOVP(a);
+ vref(vp);
+ mtx_unlock(&hashMutex);
return vp;
}
}
VMBlockHashInsert(struct mount *mp, // IN: VMBlock file system info
struct VMBlockNode *xp) // IN: node to insert into hash
{
- struct thread *td = curthread; /* XXX */
struct nodeHashHead *hd;
struct VMBlockNode *oxp;
struct vnode *ovp;
- int error;
hd = VMBLOCK_NHASH(xp->lowerVnode);
mtx_lock(&hashMutex);
* operation.
*/
ovp = VMBTOVP(oxp);
- VI_LOCK(ovp);
+ vref(ovp);
mtx_unlock(&hashMutex);
- ovp->v_iflag &= ~VI_OWEINACT;
- error = vget(ovp, LK_INTERLOCK, td);
- if (error) {
- panic("hashEntryins: vget error %d", error);
- }
return ovp;
}
}
{
vp->v_data = NULL;
vp->v_vnlock = &vp->v_lock;
- FREE(xp, M_VMBLOCKFSNODE);
+ free(xp, M_VMBLOCKFSNODE);
vp->v_op = &dead_vnodeops;
- (void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+ (void) compat_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
vgone(vp);
vput(vp);
}
#ifdef DIAGNOSTIC /* if (DIAGNOSTIC) { */
-#ifdef KDB /* if (KDB) { */
-# define VMBlockCheckVp_barrier 1
-#else
-# define VMBlockCheckVp_barrier 0
-#endif /* } */
-
-
/*
*-----------------------------------------------------------------------------
*
*/
if (vp->v_op != null_vnodeop_p) {
printf ("VMBlockCheckVp: on non-null-node\n");
- while (VMBlockCheckVp_barrier) /*WAIT*/ ;
panic("VMBlockCheckVp");
};
#endif
printf(" %lx", p[i]);
}
printf("\n");
- /* wait for debugger */
- while (VMBlockCheckVp_barrier) /*WAIT*/ ;
panic("VMBlockCheckVp");
}
if (vrefcnt(a->lowerVnode) < 1) {
printf(" %lx", p[i]);
}
printf("\n");
- /* wait for debugger */
- while (VMBlockCheckVp_barrier) /*WAIT*/ ;
panic ("null with unref'ed lowervp");
};
#ifdef notyet
*/
static int
-VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters
- struct thread *td) // IN: caller's kernel thread context
+#if __FreeBSD_version >= 800011
+VMBlockVFSMount(struct mount *mp) // IN: mount(2) parameters
+#else
+VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters
+ struct thread *td) // IN: caller's thread context
+#endif
{
struct VMBlockMount *xmp;
struct nameidata nd, *ndp = &nd;
/*
* Find lower node and lock if not already locked.
*/
- NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, td);
+
+ NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, compat_td);
error = namei(ndp);
if (error) {
NDFREE(ndp, 0);
* Make sure the node alias worked
*/
if (error) {
- COMPAT_VOP_UNLOCK(vp, 0, td);
+ COMPAT_VOP_UNLOCK(vp, 0, compat_td);
vrele(lowerrootvp);
free(xmp, M_VMBLOCKFSMNT); /* XXX */
return error;
/*
* Unlock the node (either the lower or the alias)
*/
- COMPAT_VOP_UNLOCK(vp, 0, td);
+ COMPAT_VOP_UNLOCK(vp, 0, compat_td);
/*
* If the staging area is a local filesystem, reflect that here, too. (We
*/
static int
-VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount
- int mntflags, // IN: unmount(2) flags (ex: MNT_FORCE)
- struct thread *td) // IN: caller's kernel thread context
+#if __FreeBSD_version >= 800011
+VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount
+ int mntflags) // IN: unmount(2) flags (ex: MNT_FORCE)
+#else
+VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount
+ int mntflags, // IN: unmount(2) flags (ex: MNT_FORCE)
+ struct thread *td) // IN: caller's kernel thread context
+#endif
{
struct VMBlockMount *xmp;
struct vnode *vp;
* transfer will happen atomically. (Er, at least within the scope of
* the vnode subsystem.)
*/
- COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, td);
+ COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, compat_td);
removed = BlockRemoveAllBlocks(OS_UNKNOWN_BLOCKER);
VI_LOCK(vp);
vp->v_usecount -= removed;
VI_UNLOCK(vp);
- COMPAT_VOP_UNLOCK(vp, 0, td);
+ COMPAT_VOP_UNLOCK(vp, 0, compat_td);
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
}
/* There is 1 extra root vnode reference (xmp->rootVnode). */
- error = vflush(mp, 1, flags, td);
+ error = vflush(mp, 1, flags, compat_td);
if (error) {
return error;
}
*/
static int
+#if __FreeBSD_version >= 800011
+VMBlockVFSRoot(struct mount *mp, // IN: vmblock file system
+ int flags, // IN: lockmgr(9) flags
+ struct vnode **vpp) // OUT: root vnode
+#else
VMBlockVFSRoot(struct mount *mp, // IN: vmblock file system
int flags, // IN: lockmgr(9) flags
struct vnode **vpp, // OUT: root vnode
struct thread *td) // IN: caller's thread context
+#endif
{
struct vnode *vp;
*/
vp = MNTTOVMBLOCKMNT(mp)->rootVnode;
VREF(vp);
- compat_vn_lock(vp, flags | LK_RETRY, td);
+ compat_vn_lock(vp, flags | LK_RETRY, compat_td);
*vpp = vp;
return 0;
}
*/
static int
+#if __FreeBSD_version >= 800011
+VMBlockVFSStatFS(struct mount *mp, // IN: vmblock file system
+ struct statfs *sbp) // OUT: statfs(2) arg container
+#else
VMBlockVFSStatFS(struct mount *mp, // IN: vmblock file system
struct statfs *sbp, // OUT: statfs(2) arg container
struct thread *td) // IN: caller's thread context
+#endif
{
int error;
struct statfs mstat;
bzero(&mstat, sizeof mstat);
- error = VFS_STATFS(MNTTOVMBLOCKMNT(mp)->mountVFS, &mstat, td);
+ error = COMPAT_VFS_STATFS(MNTTOVMBLOCKMNT(mp)->mountVFS, &mstat, compat_td);
if (error) {
return error;
}
*/
static int
+#if __FreeBSD_version >= 800011
+VMBlockVFSSync(struct mount *mp, // Ignored
+ int waitfor) // Ignored
+#else
VMBlockVFSSync(struct mount *mp, // Ignored
int waitfor, // Ignored
struct thread *td) // Ignored
+#endif
{
return 0;
}
*
* NB: Allowing only the superuser to open this directory breaks
* readdir() of the filesystem root for non-privileged users.
+ *
+ * Also, on FreeBSD 8.0 and newer we check for a specific module priv
+ * because none of the existing privs seemed to match very well.
*/
- if ((retval = suser(ap->a_td)) == 0) {
+ if ((retval = compat_priv_check(ap->a_td, PRIV_DRIVER)) == 0) {
#if __FreeBSD_version >= 700055
fp = ap->a_fp;
#else
*/
{
struct vnode *vp = ap->a_vp;
- mode_t mode = ap->a_mode;
+ compat_accmode_t mode = ap->compat_a_accmode;
/*
* Disallow write attempts on read-only layers; unless the file is a
*
*********************************************************/
-/*
+/*
* os.c --
*
- * Wrappers for FreeBSD system functions required by "vmmemctl".
- * This allows customers to build their own vmmemctl driver for
- * custom FreeBSD kernels without the need for source code.
+ * Wrappers for FreeBSD system functions required by "vmmemctl".
*/
/*
volatile int stop;
/* registered state */
- os_timer_handler handler;
+ OSTimerHandler *handler;
void *data;
int period;
} os_timer;
typedef struct {
/* registered state */
- os_status_handler handler;
+ OSStatusHandler *handler;
const char *name_verbose;
const char *name;
} os_status;
static void vmmemctl_init_sysctl(void);
static void vmmemctl_deinit_sysctl(void);
+
/*
- * Simple Wrappers
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Malloc --
+ *
+ * Allocates kernel memory.
+ *
+ * Results:
+ * On success: Pointer to allocated memory
+ * On failure: NULL
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-void *os_kmalloc_nosleep(unsigned int size)
+void *
+OS_Malloc(size_t size) // IN
{
return(malloc(size, M_VMMEMCTL, M_NOWAIT));
}
-void os_kfree(void *obj, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Free --
+ *
+ * Free allocated kernel memory.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Free(void *ptr, // IN
+ size_t size) // IN
{
- free(obj, M_VMMEMCTL);
+ free(ptr, M_VMMEMCTL);
}
-void os_bzero(void *b, unsigned int len)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemZero --
+ *
+ * Fill a memory location with 0s.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemZero(void *ptr, // OUT
+ size_t size) // IN
{
- bzero(b, len);
+ bzero(ptr, size);
}
-void os_memcpy(void *dest, const void *src, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemCopy --
+ *
+ * Copy a memory portion into another location.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemCopy(void *dest, // OUT
+ const void *src, // IN
+ size_t size) // IN
{
memcpy(dest, src, size);
}
return word;
}
-int os_sprintf(char *str, const char *format, ...)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Snprintf --
+ *
+ * Print a string into a bounded memory location.
+ *
+ * Results:
+ * Number of character printed including trailing \0.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+OS_Snprintf(char *buf, // OUT
+ size_t size, // IN
+ const char *format, // IN
+ ...) // IN
{
+ int result;
va_list args;
+
va_start(args, format);
- return(vsprintf(str, format, args));
+ result = vsnprintf(buf, size, format, args);
+ va_end(args);
+
+ return result;
}
/*
* System-Dependent Operations
*/
-char *os_identity(void)
+const char *
+OS_Identity(void)
{
return("bsd");
}
*
* Currently we just return the total memory pages.
*/
-unsigned int os_predict_max_balloon_pages(void)
+unsigned int
+OS_PredictMaxReservedPages(void)
{
return(cnt.v_page_count);
}
-unsigned long os_addr_to_ppn(unsigned long addr)
+unsigned long
+OS_AddrToPPN(unsigned long addr)
{
return (((vm_page_t)addr)->phys_addr) >> PAGE_SHIFT;
}
static void os_balloonobject_create(void)
{
- global_state.vmobject = vm_object_allocate(OBJT_DEFAULT,
+ global_state.vmobject = vm_object_allocate(OBJT_DEFAULT,
OFF_TO_IDX(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS));
}
-unsigned long os_alloc_reserved_page(int can_sleep)
+unsigned long
+OS_AllocReservedPage(int canSleep)
{
- return (unsigned long)os_kmem_alloc(can_sleep);
+ return (unsigned long)os_kmem_alloc(canSleep);
}
-void os_free_reserved_page(unsigned long page)
+void
+OS_FreeReservedPage(unsigned long page)
{
os_kmem_free((vm_page_t)page);
}
}
}
-void os_timer_init(os_timer_handler handler, void *data, int period)
+void
+OS_TimerInit(OSTimerHandler *handler, // IN
+ void *clientData, // IN
+ int period) // IN
{
os_timer *t = &global_state.timer;
callout_handle_init(&t->callout_handle);
t->handler = handler;
- t->data = data;
+ t->data = clientData;
t->period = period;
t->stop = 0;
}
-void os_timer_start(void)
+void
+OS_TimerStart(void)
{
os_timer *t = &global_state.timer;
t->callout_handle = timeout(os_timer_internal, t, t->period);
}
-void os_timer_stop(void)
+void
+OS_TimerStop(void)
{
os_timer *t = &global_state.timer;
untimeout(os_timer_internal, t, t->callout_handle);
}
-unsigned int os_timer_hz(void)
+unsigned int
+OS_TimerHz(void)
{
return hz;
}
-void os_yield(void)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Yield --
+ *
+ * Yield the CPU, if needed.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Yield(void)
{
/* Do nothing. */
}
-void os_init(const char *name,
- const char *name_verbose,
- os_status_handler handler)
+void
+OS_Init(const char *name,
+ const char *name_verbose,
+ OSStatusHandler *handler)
{
os_state *state = &global_state;
os_pmap *pmap = &state->pmap;
printf("%s initialized\n", state->status.name_verbose);
}
-void os_cleanup(void)
+void
+OS_Cleanup(void)
{
os_state *state = &global_state;
os_pmap *pmap = &state->pmap;
char stats[PAGE_SIZE];
size_t len;
- len = 1 + global_state.status.handler(stats);
+ len = 1 + global_state.status.handler(stats, PAGE_SIZE);
return SYSCTL_OUT(req, stats, len);
}
*
*********************************************************/
-/*
+/*
* os.h --
*
- * Definitions for OS-specific wrapper functions required
- * by "vmmemctl". This allows customers to build their own
- * vmmemctl driver for custom versioned kernels without the
- * need for source code.
+ * Definitions for OS-specific wrapper functions required by "vmmemctl".
*/
#ifndef OS_H
#define OS_H
-/*
- * Needs fixing for 64bit OSes
- */
-#ifndef __x86_64__
-#define CDECL __attribute__((cdecl, regparm(0)))
-#else
-#define CDECL
-#endif
-
/*
* Types
*/
-typedef void CDECL (*os_timer_handler)(void *);
-typedef int CDECL (*os_status_handler)(char *);
+typedef void OSTimerHandler(void *clientData);
+typedef int OSStatusHandler(char *buf, size_t size);
/*
* Operations
*/
-extern void CDECL *os_kmalloc_nosleep(unsigned int size);
-extern void CDECL os_kfree(void *obj, unsigned int size);
-extern void CDECL os_yield(void);
-extern void CDECL os_bzero(void *s, unsigned int n);
-extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size);
-extern int CDECL os_sprintf(char *str, const char *format, ...);
-
-extern unsigned long CDECL os_addr_to_ppn(unsigned long addr);
-extern unsigned long CDECL os_alloc_reserved_page(int can_sleep);
-extern void CDECL os_free_reserved_page(unsigned long page);
+extern void OS_Init(const char *name,
+ const char *nameVerbose,
+ OSStatusHandler *handler);
+extern void OS_Cleanup(void);
+extern const char *OS_Identity(void);
-extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period);
-extern void CDECL os_timer_start(void);
-extern void CDECL os_timer_stop(void);
+extern void OS_MemZero(void *ptr, size_t size);
+extern void OS_MemCopy(void *dest, const void *src, size_t size);
+extern int OS_Snprintf(char *buf, size_t size, const char *format, ...);
-extern void CDECL os_init(const char *name,
- const char *name_verbose,
- os_status_handler handler);
-extern void CDECL os_cleanup(void);
+extern void *OS_Malloc(size_t size);
+extern void OS_Free(void *ptr, size_t size);
-extern char CDECL *os_identity(void);
+extern void OS_Yield(void);
-extern unsigned int CDECL os_predict_max_balloon_pages(void);
+extern unsigned int OS_TimerHz(void);
+extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
+extern void OS_TimerStart(void);
+extern void OS_TimerStop(void);
-extern unsigned int CDECL os_timer_hz(void);
+extern unsigned int OS_PredictMaxReservedPages(void);
+extern unsigned long OS_AddrToPPN(unsigned long addr);
+extern unsigned long OS_AllocReservedPage(int canSleep);
+extern void OS_FreeReservedPage(unsigned long page);
#endif /* OS_H */
*
*********************************************************/
-/*
+/*
* vmballoon.c --
*
- * VMware server physical memory management driver for Unix-ish
- * (Linux, FreeBSD, Solaris) guests. The driver acts like a
- * "balloon" that can be inflated to reclaim physical pages by
- * reserving them in the guest and invalidating them in the
- * monitor, freeing up the underlying machine pages so they can
- * be allocated to other guests. The balloon can also be
- * deflated to allow the guest to use more physical memory.
- * Higher level policies can control the sizes of balloons in VMs
- * in order to manage physical memory resources.
+ * VMware physical memory management driver for Unix-ish
+ * (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like
+ * a "balloon" that can be inflated to reclaim physical pages by
+ * reserving them in the guest and invalidating them in the
+ * monitor, freeing up the underlying machine pages so they can
+ * be allocated to other guests. The balloon can also be
+ * deflated to allow the guest to use more physical memory.
+ * Higher level policies can control the sizes of balloons in VMs
+ * in order to manage physical memory resources.
*/
#ifdef __cplusplus
* Compile-Time Options
*/
-#define BALLOON_RATE_ADAPT (1)
+#define BALLOON_RATE_ADAPT (1)
-#define BALLOON_DEBUG (1)
-#define BALLOON_DEBUG_VERBOSE (0)
+#define BALLOON_DEBUG (1)
+#define BALLOON_DEBUG_VERBOSE (0)
-#define BALLOON_STATS
+#define BALLOON_STATS
#define BALLOON_STATS_PROCFS
/*
#define NULL 0
#endif
-#define BALLOON_NAME "vmmemctl"
-#define BALLOON_NAME_VERBOSE "VMware memory control driver"
+#define BALLOON_NAME "vmmemctl"
+#define BALLOON_NAME_VERBOSE "VMware memory control driver"
-#define BALLOON_PROTOCOL_VERSION (2)
+#define BALLOON_PROTOCOL_VERSION (2)
-#define BALLOON_CHUNK_PAGES (1000)
+#define BALLOON_CHUNK_PAGES (1000)
-#define BALLOON_NOSLEEP_ALLOC_MAX (16384)
+#define BALLOON_NOSLEEP_ALLOC_MAX (16384)
-#define BALLOON_RATE_ALLOC_MIN (512)
-#define BALLOON_RATE_ALLOC_MAX (2048)
-#define BALLOON_RATE_ALLOC_INC (16)
+#define BALLOON_RATE_ALLOC_MIN (512)
+#define BALLOON_RATE_ALLOC_MAX (2048)
+#define BALLOON_RATE_ALLOC_INC (16)
-#define BALLOON_RATE_FREE_MIN (512)
-#define BALLOON_RATE_FREE_MAX (16384)
-#define BALLOON_RATE_FREE_INC (16)
+#define BALLOON_RATE_FREE_MIN (512)
+#define BALLOON_RATE_FREE_MAX (16384)
+#define BALLOON_RATE_FREE_INC (16)
-#define BALLOON_ERROR_PAGES (16)
+#define BALLOON_ERROR_PAGES (16)
-/*
+/*
* When guest is under memory pressure, use a reduced page allocation
* rate for next several cycles.
*/
-#define SLOW_PAGE_ALLOCATION_CYCLES (4)
+#define SLOW_PAGE_ALLOCATION_CYCLES (4)
-/*
+/*
* Move it to bora/public/balloon_def.h later, if needed. Note that
* BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
* distinguishing page allocation failures from monitor-backdoor errors.
* We use value 1000 because all monitor-backdoor error codes are < 1000.
*/
-#define BALLOON_PAGE_ALLOC_FAILURE (1000)
+#define BALLOON_PAGE_ALLOC_FAILURE (1000)
// Maximum number of page allocations without yielding processor
#define BALLOON_ALLOC_YIELD_THRESHOLD (1024)
static int BalloonGuestType(void);
static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void BalloonPrimFreePage(unsigned long page);
+static void BalloonPrimFreePage(unsigned long page);
static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
static int Balloon_FreePage(Balloon *b, int monitorUnlock);
static void Balloon_StartTimer(Balloon *b);
static void Balloon_StopTimer(Balloon *b);
-static void CDECL Balloon_BH(void *data);
+static void BalloonTimerHandler(void *clientData);
static int Balloon_MonitorStart(Balloon *b);
static int Balloon_MonitorGuestType(Balloon *b);
* Macros
*/
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef BALLOON_STATS
-#define STATS_INC(stat) (stat)++
+#ifdef BALLOON_STATS
+#define STATS_INC(stat) (stat)++
#else
-#define STATS_INC(stat)
+#define STATS_INC(stat)
#endif
/*
* Macros to generate operations for simple lists of OBJ.
* OBJ must contain next and prev fields.
- *
*/
-#define GENERATE_LIST_INSERT(OBJ) \
-static void OBJ ## _Insert(OBJ **head, OBJ *obj) \
-{ \
- OBJ *h = *head; \
- \
- /* add element to head of list */ \
- obj->next = h; \
- if (h != NULL) { \
- h->prev = obj; \
- } \
- *head = obj; \
- obj->prev = NULL; \
+#define GENERATE_LIST_INSERT(OBJ) \
+static void OBJ ## _Insert(OBJ **head, OBJ *obj) \
+{ \
+ OBJ *h = *head; \
+ \
+ /* add element to head of list */ \
+ obj->next = h; \
+ if (h != NULL) { \
+ h->prev = obj; \
+ } \
+ *head = obj; \
+ obj->prev = NULL; \
}
-#define GENERATE_LIST_REMOVE(OBJ) \
-static void OBJ ## _Remove(OBJ **head, OBJ *obj) \
-{ \
- /* splice element out of list */ \
- if (obj->prev != NULL) { \
- obj->prev->next = obj->next; \
- } else { \
- *head = obj->next; \
- } \
- if (obj->next != NULL) { \
- obj->next->prev = obj->prev; \
- } \
+#define GENERATE_LIST_REMOVE(OBJ) \
+static void OBJ ## _Remove(OBJ **head, OBJ *obj) \
+{ \
+ /* splice element out of list */ \
+ if (obj->prev != NULL) { \
+ obj->prev->next = obj->next; \
+ } else { \
+ *head = obj->next; \
+ } \
+ if (obj->next != NULL) { \
+ obj->next->prev = obj->prev; \
+ } \
}
/*
* Procfs Operations
*/
+
/*
*----------------------------------------------------------------------
*
* BalloonProcRead --
*
* Ballon driver status reporting routine. Note that this is only
- * used for Linux.
+ * used for Linux.
*
* Results:
* Writes ASCII status information into "buf".
- * Returns number of bytes written.
+ * Returns number of bytes written.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
-static int CDECL
-BalloonProcRead(char *buf)
+
+static int
+BalloonProcRead(char *buf, // OUT
+ size_t size) // IN
{
int len = 0;
BalloonStats stats;
BalloonGetStats(&stats);
/* format size info */
- len += os_sprintf(buf + len,
+ len += OS_Snprintf(buf + len, size - len,
"target: %8d pages\n"
"current: %8d pages\n",
stats.nPagesTarget,
stats.nPages);
/* format rate info */
- len += os_sprintf(buf + len,
+ len += OS_Snprintf(buf + len, size - len,
"rateNoSleepAlloc: %8d pages/sec\n"
"rateSleepAlloc: %8d pages/sec\n"
"rateFree: %8d pages/sec\n",
stats.rateAlloc,
stats.rateFree);
-#ifdef BALLOON_STATS_PROCFS
- len += os_sprintf(buf + len,
+#ifdef BALLOON_STATS_PROCFS
+ len += OS_Snprintf(buf + len, size - len,
"\n"
"timer: %8u\n"
"start: %8u (%4u failed)\n"
stats.primErrorPageFree);
#endif
- return(len);
+ return len;
}
/*
* AddrToPPN --
*
* Return the physical page number corresponding to the specified
- * Linux kernel-mapped address.
+ * kernel-mapped address.
*
* Results:
* Returns PPN for "addr".
static inline unsigned long
AddrToPPN(unsigned long addr)
{
- return(os_addr_to_ppn(addr));
+ return OS_AddrToPPN(addr);
}
/*
*
* Attempts to allocate and reserve a physical page.
*
- * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- * The allocation can wait (sleep) for page writeout (swap)
- * by the guest.
- * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- * If allocation of a page requires disk writeout, then
- * just fail. DON'T sleep.
+ * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ * The allocation can wait (sleep) for page writeout (swap)
+ * by the guest.
+ * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ * If allocation of a page requires disk writeout, then
+ * just fail. DON'T sleep.
*
* Results:
* Returns the physical address of the allocated page, or 0 if error.
static unsigned long
BalloonPrimAllocPage(BalloonPageAllocType canSleep)
{
- return(os_alloc_reserved_page(canSleep));
+ return OS_AllocReservedPage(canSleep);
}
/*
static void
BalloonPrimFreePage(unsigned long page)
{
- return(os_free_reserved_page(page));
+ return OS_FreeReservedPage(page);
}
/*
* BalloonGuestType --
*
* Return balloon guest OS identifier obtained by parsing
- * system-dependent identity string.
+ * system-dependent identity string.
*
* Results:
* Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
static int
BalloonGuestType(void)
{
- char *identity;
+ const char *identity;
/* obtain OS identify string */
- identity = os_identity();
-
+ identity = OS_Identity();
+
/* unknown if not specified */
if (identity == NULL) {
return(BALLOON_GUEST_UNKNOWN);
switch (identity[0]) {
case 'l':
case 'L':
- return(BALLOON_GUEST_LINUX);
+ return BALLOON_GUEST_LINUX;
case 'b':
case 'B':
- return(BALLOON_GUEST_BSD);
+ return BALLOON_GUEST_BSD;
case 's':
case 'S':
- return(BALLOON_GUEST_SOLARIS);
+ return BALLOON_GUEST_SOLARIS;
default:
break;
}
/* unknown */
- return(BALLOON_GUEST_UNKNOWN);
+ return BALLOON_GUEST_UNKNOWN;
}
/*
/*
* Copy statistics out of global structure.
*/
- os_memcpy(stats, &b->stats, sizeof (BalloonStats));
+ OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
/*
* Fill in additional information about size and rates, which is
* BalloonChunk_Create --
*
* Creates a new BalloonChunk object capable of tracking
- * BALLOON_CHUNK_PAGES PPNs.
+ * BALLOON_CHUNK_PAGES PPNs.
*
- * We do not bother to define two versions (NOSLEEP and CANSLEEP)
- * of os_kmalloc because Chunk_Create does not require a new page
- * often.
+ * We do not bother to define two versions (NOSLEEP and CANSLEEP)
+ * of OS_Malloc because Chunk_Create does not require a new page
+ * often.
*
* Results:
- * Returns initialized BalloonChunk, or NULL if error.
+ * On success: initialized BalloonChunk
+ * On failure: NULL
*
* Side effects:
- * None.
+ * None
*
*----------------------------------------------------------------------
*/
+
static BalloonChunk *
BalloonChunk_Create(void)
{
BalloonChunk *chunk;
/* allocate memory, fail if unable */
- if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
- return(NULL);
+ chunk = OS_Malloc(sizeof *chunk);
+ if (chunk == NULL) {
+ return NULL;
}
/* initialize */
- os_bzero(chunk, sizeof(BalloonChunk));
+ OS_MemZero(chunk, sizeof *chunk);
/* everything OK */
- return(chunk);
+ return chunk;
}
+
/*
*----------------------------------------------------------------------
*
BalloonChunk_Destroy(BalloonChunk *chunk)
{
/* reclaim storage */
- os_kfree(chunk, sizeof (BalloonChunk));
+ OS_Free(chunk, sizeof *chunk);
}
/*
Balloon_Init(Balloon *b)
{
/* clear state */
- os_bzero(b, sizeof(Balloon));
+ OS_MemZero(b, sizeof *b);
/* initialize rates */
b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
(void) Balloon_FreePage(b, FALSE);
if (++cnt >= b->rateFree) {
cnt = 0;
- os_yield();
+ OS_Yield();
}
}
}
* Balloon_Reset --
*
* Resets balloon "b" to empty state. Frees all allocated pages
- * and attempts to reset contact with the monitor.
+ * and attempts to reset contact with the monitor.
*
* Results:
* None.
/*
*----------------------------------------------------------------------
*
- * Balloon_BH --
+ * BalloonTimerHandler --
*
* Balloon bottom half handler. Contacts monitor via backdoor
- * to obtain balloon size target, and starts adjusting balloon
- * size to achieve target by allocating or deallocating pages.
- * Resets balloon if requested by the monitor.
+ * to obtain balloon size target, and starts adjusting balloon
+ * size to achieve target by allocating or deallocating pages.
+ * Resets balloon if requested by the monitor.
*
* Results:
* None.
*
*----------------------------------------------------------------------
*/
-static void CDECL
-Balloon_BH(void *data)
+static void
+BalloonTimerHandler(void *clientData)
{
- Balloon *b = (Balloon *) data;
+ Balloon *b = (Balloon *) clientData;
uint32 target;
int status;
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
Balloon_StartTimer(Balloon *b)
{
- os_timer_start();
+ OS_TimerStart();
}
/*
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
Balloon_StopTimer(Balloon *b)
{
- os_timer_stop();
+ OS_TimerStop();
}
* Balloon_ErrorPagesAlloc --
*
* Attempt to add "page" to list of non-balloonable pages
- * associated with "b".
+ * associated with "b".
*
* Results:
- * Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
- * if non-balloonable page list is already full.
+ * On success: BALLOON_SUCCESS
+ * On failure: BALLOON_FAILURE (non-balloonable page list is already full)
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_ErrorPagesFree --
*
* Deallocates all pages on the list of non-balloonable pages
- * associated with "b".
+ * associated with "b".
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
/* free all non-balloonable "error" pages */
for (i = 0; i < b->errors.nextPage; i++) {
- BalloonPrimFreePage(b->errors.page[i]);
+ BalloonPrimFreePage(b->errors.page[i]);
b->errors.page[i] = 0;
STATS_INC(b->stats.primErrorPageFree);
}
* Balloon_AllocPage --
*
* Attempts to allocate a physical page, inflating balloon "b".
- * Informs monitor of PPN for allocated page via backdoor.
+ * Informs monitor of PPN for allocated page via backdoor.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_FreePage --
*
* Attempts to deallocate a physical page, deflating balloon "b".
- * Informs monitor of PPN for deallocated page via backdoor if
- * "monitorUnlock" is specified.
+ * Informs monitor of PPN for deallocated page via backdoor if
+ * "monitorUnlock" is specified.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* BalloonDecreaseRateAlloc --
*
- * Wrapper to quickly reduce the page allocation rate. This function
- * is called only when a CANSLEEP allocation fails. This implies severe
- * memory pressure inside the guest, so quickly decrease the rateAlloc.
+ * Wrapper to quickly reduce the page allocation rate. This function
+ * is called only when a CANSLEEP allocation fails. This implies severe
+ * memory pressure inside the guest, so quickly decrease the rateAlloc.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* BalloonIncreaseRateAlloc --
*
- * Wrapper to increase the page allocation rate.
+ * Wrapper to increase the page allocation rate.
*
- * This function is called when the balloon target is met or
- * b->rateAlloc (or more) pages have been successfully allocated.
- * This implies that the guest may not be under high memory
- * pressure. So let us increase the rateAlloc.
+ * This function is called when the balloon target is met or
+ * b->rateAlloc (or more) pages have been successfully allocated.
+ * This implies that the guest may not be under high memory
+ * pressure. So let us increase the rateAlloc.
*
- * If meeting balloon target requires less than b->rateAlloc
- * pages, then we do not change the page allocation rate.
+ * If meeting balloon target requires less than b->rateAlloc
+ * pages, then we do not change the page allocation rate.
*
- * If the number of pages successfully allocated (nAlloc) is far
- * higher than b->rateAlloc, then it implies that NOSLEEP
- * allocations are highly successful. Therefore, we predict that
- * the guest is under no memory pressure, and so increase
- * b->rateAlloc quickly.
+ * If the number of pages successfully allocated (nAlloc) is far
+ * higher than b->rateAlloc, then it implies that NOSLEEP
+ * allocations are highly successful. Therefore, we predict that
+ * the guest is under no memory pressure, and so increase
+ * b->rateAlloc quickly.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
{
if (BALLOON_RATE_ADAPT) {
if (nAlloc >= b->rateAlloc) {
- uint32 mult = nAlloc / b->rateAlloc;
+ uint32 mult = nAlloc / b->rateAlloc;
b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
BALLOON_RATE_ALLOC_MAX);
}
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
int status, allocations = 0;
uint32 i, nAllocNoSleep, nAllocCanSleep;
- /*
+ /*
* First try NOSLEEP page allocations to inflate balloon.
*
* If we do not throttle nosleep allocations, we can drain all
* As a side-effect, draining free pages helps to inform (force)
* the guest to start swapping if balloon target is not met yet,
* which is a desired behavior. However, balloon driver can consume
- * all available CPU cycles if too many pages are allocated in a
- * second. Therefore, we throttle nosleep allocations even when
- * the guest is not under memory pressure. OTOH, if we have already
- * predicted that the guest is under memory pressure, then we
+ * all available CPU cycles if too many pages are allocated in a
+ * second. Therefore, we throttle nosleep allocations even when
+ * the guest is not under memory pressure. OTOH, if we have already
+ * predicted that the guest is under memory pressure, then we
* slowdown page allocations considerably.
*/
if (b->slowPageAllocationCycles > 0) {
status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
if (status != BALLOON_SUCCESS) {
if (status != BALLOON_PAGE_ALLOC_FAILURE) {
- /*
+ /*
* Not a page allocation failure, so release non-balloonable
* pages, and fail.
*/
Balloon_ErrorPagesFree(b);
return(status);
}
- /*
- * NOSLEEP page allocation failed, so the guest is under memory
- * pressure. Let us slowdown page allocations for next few
+ /*
+ * NOSLEEP page allocation failed, so the guest is under memory
+ * pressure. Let us slowdown page allocations for next few
* cycles so that the guest gets out of memory pressure.
*/
b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
}
if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
- os_yield();
+ OS_Yield();
allocations = 0;
}
}
- /*
+ /*
* Check whether nosleep allocation successfully zapped nAllocNoSleep
* pages.
*/
Balloon_ErrorPagesFree(b);
return(BALLOON_SUCCESS);
} else {
- /*
+ /*
* NOSLEEP allocation failed, so the guest is under memory pressure.
* If already b->rateAlloc pages were zapped, then succeed. Otherwise,
* try CANSLEEP allocation.
}
}
- /*
+ /*
* Use CANSLEEP page allocation to inflate balloon if below target.
*
* Sleep allocations are required only when nosleep allocation fails.
* This implies that the guest is already under memory pressure, so
* let us always throttle canSleep allocations. The total number pages
- * allocated using noSleep and canSleep methods is throttled at
- * b->rateAlloc per second when the guest is under memory pressure.
+ * allocated using noSleep and canSleep methods is throttled at
+ * b->rateAlloc per second when the guest is under memory pressure.
*/
nAllocCanSleep = target - b->nPages;
nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
if(status != BALLOON_SUCCESS) {
if (status == BALLOON_PAGE_ALLOC_FAILURE) {
- /*
+ /*
* CANSLEEP page allocation failed, so guest is under severe
* memory pressure. Quickly decrease rateAlloc.
*/
}
if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
- os_yield();
+ OS_Yield();
allocations = 0;
}
}
- /*
+ /*
* Either met the balloon target or b->rateAlloc pages have been
* successfully zapped.
*/
BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
-
+
/* release non-balloonable pages, succeed */
Balloon_ErrorPagesFree(b);
return(BALLOON_SUCCESS);
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
{
int status, i;
uint32 nFree = b->nPages - target;
-
+
/* limit deallocation rate */
nFree = MIN(nFree, b->rateFree);
/* everything OK */
return(BALLOON_SUCCESS);
}
-
+
/*
*----------------------------------------------------------------------
*
* Balloon_AdjustSize --
*
* Attempts to allocate or deallocate physical pages in order
- * to reach desired "target" size for balloon "b".
+ * to reach desired "target" size for balloon "b".
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Attempts to contact monitor via backdoor to begin operation.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Attempts to contact monitor and report guest OS identity.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_MonitorGetTarget --
*
* Attempts to contact monitor via backdoor to obtain desired
- * balloon size.
+ * balloon size.
*
- * Predicts the maximum achievable balloon size and sends it
- * to vmm => vmkernel via vEbx register.
+ * Predicts the maximum achievable balloon size and sends it
+ * to vmm => vmkernel via vEbx register.
*
- * os_predict_max_balloon_pages() returns either predicted max balloon
- * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
- * vmkernel uses global config options for determining a guest's max
- * balloon size. Note that older vmballoon drivers set vEbx to
- * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
- * will fallback to config-based max balloon size estimation.
+ * OS_PredictMaxReservedPages() returns either predicted max balloon
+ * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
+ * vmkernel uses global config options for determining a guest's max
+ * balloon size. Note that older vmballoon drivers set vEbx to
+ * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
+ * will fallback to config-based max balloon size estimation.
*
* Results:
- * If successful, sets "target" to value obtained from monitor,
+ * If successful, sets "target" to value obtained from monitor,
* and returns BALLOON_SUCCESS. Otherwise returns error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
- bp.in.size = os_predict_max_balloon_pages();
+ bp.in.size = OS_PredictMaxReservedPages();
/* invoke backdoor */
Backdoor_Balloon(&bp);
*
* Balloon_MonitorLockPage --
*
- * Attempts to contact monitor and add PPN containing "addr"
- * to set of "balloon locked" pages.
+ * Attempts to contact monitor and add PPN containing "addr"
+ * to set of "balloon locked" pages.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* Balloon_MonitorUnlockPage --
*
- * Attempts to contact monitor and remove PPN containing "addr"
- * from set of "balloon locked" pages.
+ * Attempts to contact monitor and remove PPN containing "addr"
+ * from set of "balloon locked" pages.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
return(BALLOON_FAILURE);
}
+ /* os-specific initialization */
+ OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
+
/* initialize global state */
Balloon_Init(b);
- /* os-specific initialization */
- os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
- os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
-
/* start timer */
+ OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
Balloon_StartTimer(b);
/* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
static void
Balloon_Deallocate(b);
/* os-specific cleanup */
- os_cleanup();
-}
+ OS_Cleanup();
+}
int init_module(void)
{
PACKAGE_NAME=open-vm-tools
-PACKAGE_VERSION=2009.07.22
+PACKAGE_VERSION=2009.08.24
MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \
MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build"
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 2009.07.22."
+ echo "The script will create an 'open-vm-tools' module with version 2009.08.24."
exit 1
fi
src=$1
-dst=$2/open-vm-tools-2009.07.22
+dst=$2/open-vm-tools-2009.08.24
SHARED_HEADERS="backdoor_def.h"
SHARED_HEADERS="$SHARED_HEADERS backdoor_types.h"
SHARED_HEADERS="$SHARED_HEADERS circList.h"
+SHARED_HEADERS="$SHARED_HEADERS community_source.h"
SHARED_HEADERS="$SHARED_HEADERS dbllnklst.h"
SHARED_HEADERS="$SHARED_HEADERS guest_msg_def.h"
SHARED_HEADERS="$SHARED_HEADERS includeCheck.h"
if (pdev->vendor != PCI_VENDOR_ID_VMWARE)
goto out_disable_device;
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0 &&
- pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 &&
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
printk(KERN_INFO "pvscsi: using 64bit dma\n");
- } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) == 0 &&
- pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) == 0) {
+ } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 &&
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) {
printk(KERN_INFO "pvscsi: using 32bit dma\n");
} else {
printk(KERN_ERR "pvscsi: failed to set DMA mask\n");
#include "vm_basic_defs.h" // for offsetof()
+#define SCSI_MIN_CMD_LEN 6
#define SCSI_MAX_CMD_LEN 16
/*
* NB: Command descriptions come from the "SCSI Book" and not
* from the SCSI specifications (YMMV).
*/
-#define SCSI_CMD_TEST_UNIT_READY 0x00 // test if LUN ready to accept a command
-#define SCSI_CMD_REZERO_UNIT 0x01 // seek to track 0
-#define SCSI_CMD_REQUEST_SENSE 0x03 // return detailed error information
-#define SCSI_CMD_FORMAT_UNIT 0x04 //
-#define SCSI_CMD_READ_BLOCKLIMITS 0x05 //
-#define SCSI_CMD_REASSIGN_BLOCKS 0x07 //
-#define SCSI_CMD_INIT_ELEMENT_STATUS 0x07 // Media changer
-#define SCSI_CMD_READ6 0x08 // read w/ limited addressing
-#define SCSI_CMD_WRITE6 0x0a // write w/ limited addressing
-#define SCSI_CMD_PRINT 0x0a // print data
-#define SCSI_CMD_SEEK6 0x0b // seek to LBN
-#define SCSI_CMD_SLEW_AND_PRINT 0x0b // advance and print
-#define SCSI_CMD_READ_REVERSE 0x0f // read backwards
-#define SCSI_CMD_WRITE_FILEMARKS 0x10 //
-#define SCSI_CMD_SYNC_BUFFER 0x10 // print contents of buffer
-#define SCSI_CMD_SPACE 0x11 //
-#define SCSI_CMD_INQUIRY 0x12 // return LUN-specific information
-#define SCSI_CMD_RECOVER_BUFFERED 0x14 // recover buffered data
-#define SCSI_CMD_MODE_SELECT 0x15 // set device parameters
-#define SCSI_CMD_RESERVE_UNIT 0x16 // make LUN accessible only to certain initiators
-#define SCSI_CMD_RELEASE_UNIT 0x17 // make LUN accessible to other initiators
-#define SCSI_CMD_COPY 0x18 // autonomous copy from/to another device
-#define SCSI_CMD_ERASE 0x19 //
-#define SCSI_CMD_MODE_SENSE 0x1a // read device parameters
-#define SCSI_CMD_START_UNIT 0x1b // load/unload medium
-#define SCSI_CMD_SCAN 0x1b // perform scan
-#define SCSI_CMD_STOP_PRINT 0x1b // interrupt printing
-#define SCSI_CMD_RECV_DIAGNOSTIC 0x1c // read self-test results
-#define SCSI_CMD_SEND_DIAGNOSTIC 0x1d // initiate self-test
-#define SCSI_CMD_MEDIUM_REMOVAL 0x1e // lock/unlock door
-#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 // read format capacities
-#define SCSI_CMD_SET_WINDOW 0x24 // set scanning window
-#define SCSI_CMD_GET_WINDOW 0x25 // get scanning window
-#define SCSI_CMD_READ_CAPACITY 0x25 // read number of logical blocks
-#define SCSI_CMD_READ10 0x28 // read
-#define SCSI_CMD_READ_GENERATION 0x29 // read max generation address of LBN
-#define SCSI_CMD_WRITE10 0x2a // write
-#define SCSI_CMD_SEEK10 0x2b // seek LBN
-#define SCSI_CMD_POSITION_TO_ELEMENT 0x2b // media changer
-#define SCSI_CMD_ERASE10 0x2c
-#define SCSI_CMD_READ_UPDATED_BLOCK 0x2d // read specific version of changed block
-#define SCSI_CMD_WRITE_VERIFY 0x2e // write w/ verify of success
-#define SCSI_CMD_VERIFY 0x2f // verify success
-#define SCSI_CMD_SEARCH_DATA_HIGH 0x30 // search for data pattern
-#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 // search for data pattern
-#define SCSI_CMD_SEARCH_DATA_LOW 0x32 // search for data pattern
-#define SCSI_CMD_SET_LIMITS 0x33 // define logical block boundaries
-#define SCSI_CMD_PREFETCH 0x34 // read data into buffer
-#define SCSI_CMD_READ_POSITION 0x34 // read current tape position
-#define SCSI_CMD_SYNC_CACHE 0x35 // re-read data into buffer
-#define SCSI_CMD_LOCKUNLOCK_CACHE 0x36 // lock/unlock data in cache
-#define SCSI_CMD_READ_DEFECT_DATA 0x37 //
-#define SCSI_CMD_MEDIUM_SCAN 0x38 // search for free area
-#define SCSI_CMD_COMPARE 0x39 // compare data
-#define SCSI_CMD_COPY_VERIFY 0x3a // autonomous copy w/ verify
-#define SCSI_CMD_WRITE_BUFFER 0x3b // write data buffer
-#define SCSI_CMD_READ_BUFFER 0x3c // read data buffer
-#define SCSI_CMD_UPDATE_BLOCK 0x3d // substitute block with an updated one
-#define SCSI_CMD_READ_LONG 0x3e // read data and ECC
-#define SCSI_CMD_WRITE_LONG 0x3f // write data and ECC
-#define SCSI_CMD_CHANGE_DEF 0x40 // set SCSI version
-#define SCSI_CMD_WRITE_SAME 0x41 //
-#define SCSI_CMD_READ_SUBCHANNEL 0x42 // read subchannel data and status
-#define SCSI_CMD_READ_TOC 0x43 // read contents table
-#define SCSI_CMD_READ_HEADER 0x44 // read LBN header
-#define SCSI_CMD_PLAY_AUDIO10 0x45 // audio playback
-#define SCSI_CMD_GET_CONFIGURATION 0x46 // get configuration (SCSI-3)
-#define SCSI_CMD_PLAY_AUDIO_MSF 0x47 // audio playback starting at MSF address
-#define SCSI_CMD_PLAY_AUDIO_TRACK 0x48 // audio playback starting at track/index
-#define SCSI_CMD_PLAY_AUDIO_RELATIVE 0x49 // audio playback starting at relative track
-#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
-#define SCSI_CMD_PAUSE 0x4b // audio playback pause/resume
-#define SCSI_CMD_LOG_SELECT 0x4c // select statistics
-#define SCSI_CMD_LOG_SENSE 0x4d // read statistics
-#define SCSI_CMD_STOP_PLAY 0x4e // audio playback stop
-#define SCSI_CMD_READ_DISC_INFO 0x51 // info on CDRs
-#define SCSI_CMD_READ_TRACK_INFO 0x52 // track info on CDRs
-#define SCSI_CMD_RESERVE_TRACK 0x53 // leave space for data on CDRs
-#define SCSI_CMD_SEND_OPC_INFORMATION 0x54 // Optimum Power Calibration
-#define SCSI_CMD_MODE_SELECT10 0x55 // set device parameters
-#define SCSI_CMD_RESERVE_UNIT10 0x56 //
-#define SCSI_CMD_RELEASE_UNIT10 0x57 //
-#define SCSI_CMD_REPAIR_TRACK 0x58
-#define SCSI_CMD_MODE_SENSE10 0x5a // read device parameters
-#define SCSI_CMD_CLOSE_SESSION 0x5b // close area/sesssion (recordable)
-#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5c // CDR burning info.
-#define SCSI_CMD_SEND_CUE_SHEET 0x5d // (CDR Related?)
-#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e //
-#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f //
-#define SCSI_CMD_XDWRITE_EXTENDED 0x80
-#define SCSI_CMD_REBUILD 0x81
-#define SCSI_CMD_REGENERATE 0x82
-#define SCSI_CMD_EXTENDED_COPY 0x83 // extended copy
-#define SCSI_CMD_RECEIVE_COPY_RESULTS 0x84 // receive copy results
-#define SCSI_CMD_READ16 0x88 // read data
-#define SCSI_CMD_WRITE16 0x8a // write data
-#define SCSI_CMD_ORWRITE16 0x8b
-#define SCSI_CMD_READ_ATTRIBUTE 0x8c // read attribute
-#define SCSI_CMD_WRITE_ATTRIBUTE 0x8d // write attribute
-#define SCSI_CMD_WRITE_VERIFY16 0x8e
-#define SCSI_CMD_VERIFY16 0x8f
-#define SCSI_CMD_PREFETCH16 0x90
-#define SCSI_CMD_SYNC_CACHE16 0x91
-#define SCSI_CMD_WRITE_SAME16 0x93
-#define SCSI_CMD_READ_CAPACITY16 0x9e // read number of logical blocks
-#define SCSI_CMD_WRITE_LONG16 0x9f
-#define SCSI_CMD_REPORT_LUNS 0xa0 //
-#define SCSI_CMD_BLANK 0xa1 // erase RW media
-#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xa2 //
-#define SCSI_CMD_MAINTENANCE_IN 0xa3 // service actions define reports
-#define SCSI_CMD_MAINTENANCE_OUT 0xa4 // service actions define changes
-#define SCSI_CMD_SEND_KEY 0xa3
-#define SCSI_CMD_REPORT_KEY 0xa4 // report key (SCSI-3)
-#define SCSI_CMD_MOVE_MEDIUM 0xa5 //
-#define SCSI_CMD_PLAY_AUDIO12 0xa5 // audio playback
-#define SCSI_CMD_EXCHANGE_MEDIUM 0xa6 //
-#define SCSI_CMD_LOADCD 0xa6 //
-#define SCSI_CMD_SET_READ_AHEAD 0xa7
-#define SCSI_CMD_READ12 0xa8 // read (SCSI-3)
-#define SCSI_CMD_PLAY_TRACK_RELATIVE 0xa9 // audio playback starting at relative track
-#define SCSI_CMD_WRITE12 0xaa // write data
-#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab //
-#define SCSI_CMD_ERASE12 0xac // erase logical block
-#define SCSI_CMD_GET_PERFORMANCE 0xac //
-#define SCSI_CMD_READ_DVD_STRUCTURE 0xad // read DVD structure (SCSI-3)
-#define SCSI_CMD_WRITE_VERIFY12 0xae // write logical block, verify success
-#define SCSI_CMD_VERIFY12 0xaf // verify data
-#define SCSI_CMD_SEARCH_DATA_HIGH12 0xb0 // search data pattern
-#define SCSI_CMD_SEARCH_DATA_EQUAL12 0xb1 // search data pattern
-#define SCSI_CMD_SEARCH_DATA_LOW12 0xb2 // search data pattern
-#define SCSI_CMD_SET_LIMITS12 0xb3 // set block limits
+#define SCSI_CMD_TEST_UNIT_READY 0x00 // test if LUN ready to accept a command
+#define SCSI_CMD_REZERO_UNIT 0x01 // seek to track 0
+#define SCSI_CMD_REQUEST_SENSE 0x03 // return detailed error information
+#define SCSI_CMD_FORMAT_UNIT 0x04 //
+#define SCSI_CMD_READ_BLOCKLIMITS 0x05 //
+#define SCSI_CMD_REASSIGN_BLOCKS 0x07 //
+#define SCSI_CMD_INIT_ELEMENT_STATUS 0x07 // Media changer
+#define SCSI_CMD_READ6 0x08 // read w/ limited addressing
+#define SCSI_CMD_WRITE6 0x0a // write w/ limited addressing
+#define SCSI_CMD_PRINT 0x0a // print data
+#define SCSI_CMD_SEEK6 0x0b // seek to LBN
+#define SCSI_CMD_SLEW_AND_PRINT 0x0b // advance and print
+#define SCSI_CMD_READ_REVERSE 0x0f // read backwards
+#define SCSI_CMD_WRITE_FILEMARKS 0x10 //
+#define SCSI_CMD_SYNC_BUFFER 0x10 // print contents of buffer
+#define SCSI_CMD_SPACE 0x11 //
+#define SCSI_CMD_INQUIRY 0x12 // return LUN-specific information
+#define SCSI_CMD_RECOVER_BUFFERED 0x14 // recover buffered data
+#define SCSI_CMD_MODE_SELECT 0x15 // set device parameters
+#define SCSI_CMD_RESERVE_UNIT 0x16 // make LUN accessible only to certain initiators
+#define SCSI_CMD_RELEASE_UNIT 0x17 // make LUN accessible to other initiators
+#define SCSI_CMD_COPY 0x18 // autonomous copy from/to another device
+#define SCSI_CMD_ERASE 0x19 //
+#define SCSI_CMD_MODE_SENSE 0x1a // read device parameters
+#define SCSI_CMD_START_UNIT 0x1b // load/unload medium
+#define SCSI_CMD_SCAN 0x1b // perform scan
+#define SCSI_CMD_STOP_PRINT 0x1b // interrupt printing
+#define SCSI_CMD_RECV_DIAGNOSTIC 0x1c // read self-test results
+#define SCSI_CMD_SEND_DIAGNOSTIC 0x1d // initiate self-test
+#define SCSI_CMD_MEDIUM_REMOVAL 0x1e // lock/unlock door
+#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 // read format capacities
+#define SCSI_CMD_SET_WINDOW 0x24 // set scanning window
+#define SCSI_CMD_GET_WINDOW 0x25 // get scanning window
+#define SCSI_CMD_READ_CAPACITY 0x25 // read number of logical blocks
+#define SCSI_CMD_READ10 0x28 // read
+#define SCSI_CMD_READ_GENERATION 0x29 // read max generation address of LBN
+#define SCSI_CMD_WRITE10 0x2a // write
+#define SCSI_CMD_SEEK10 0x2b // seek LBN
+#define SCSI_CMD_POSITION_TO_ELEMENT 0x2b // media changer
+#define SCSI_CMD_ERASE10 0x2c //
+#define SCSI_CMD_READ_UPDATED_BLOCK 0x2d // read specific version of changed block
+#define SCSI_CMD_WRITE_VERIFY 0x2e // write w/ verify of success
+#define SCSI_CMD_VERIFY 0x2f // verify success
+#define SCSI_CMD_SEARCH_DATA_HIGH 0x30 // search for data pattern
+#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 // search for data pattern
+#define SCSI_CMD_SEARCH_DATA_LOW 0x32 // search for data pattern
+#define SCSI_CMD_SET_LIMITS 0x33 // define logical block boundaries
+#define SCSI_CMD_PREFETCH 0x34 // read data into buffer
+#define SCSI_CMD_READ_POSITION 0x34 // read current tape position
+#define SCSI_CMD_SYNC_CACHE 0x35 // re-read data into buffer
+#define SCSI_CMD_LOCKUNLOCK_CACHE 0x36 // lock/unlock data in cache
+#define SCSI_CMD_READ_DEFECT_DATA 0x37 //
+#define SCSI_CMD_MEDIUM_SCAN 0x38 // search for free area
+#define SCSI_CMD_COMPARE 0x39 // compare data
+#define SCSI_CMD_COPY_VERIFY 0x3a // autonomous copy w/ verify
+#define SCSI_CMD_WRITE_BUFFER 0x3b // write data buffer
+#define SCSI_CMD_READ_BUFFER 0x3c // read data buffer
+#define SCSI_CMD_UPDATE_BLOCK 0x3d // substitute block with an updated one
+#define SCSI_CMD_READ_LONG 0x3e // read data and ECC
+#define SCSI_CMD_WRITE_LONG 0x3f // write data and ECC
+#define SCSI_CMD_CHANGE_DEF 0x40 // set SCSI version
+#define SCSI_CMD_WRITE_SAME 0x41 //
+#define SCSI_CMD_READ_SUBCHANNEL 0x42 // read subchannel data and status
+#define SCSI_CMD_READ_TOC 0x43 // read contents table
+#define SCSI_CMD_READ_HEADER 0x44 // read LBN header
+#define SCSI_CMD_PLAY_AUDIO10 0x45 // audio playback
+#define SCSI_CMD_GET_CONFIGURATION 0x46 // get configuration (SCSI-3)
+#define SCSI_CMD_PLAY_AUDIO_MSF 0x47 // audio playback starting at MSF address
+#define SCSI_CMD_PLAY_AUDIO_TRACK 0x48 // audio playback starting at track/index
+#define SCSI_CMD_PLAY_AUDIO_RELATIVE 0x49 // audio playback starting at relative track
+#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a //
+#define SCSI_CMD_PAUSE 0x4b // audio playback pause/resume
+#define SCSI_CMD_LOG_SELECT 0x4c // select statistics
+#define SCSI_CMD_LOG_SENSE 0x4d // read statistics
+#define SCSI_CMD_STOP_PLAY 0x4e // audio playback stop
+#define SCSI_CMD_READ_DISC_INFO 0x51 // info on CDRs
+#define SCSI_CMD_READ_TRACK_INFO 0x52 // track info on CDRs
+#define SCSI_CMD_RESERVE_TRACK 0x53 // leave space for data on CDRs
+#define SCSI_CMD_SEND_OPC_INFORMATION 0x54 // Optimum Power Calibration
+#define SCSI_CMD_MODE_SELECT10 0x55 // set device parameters
+#define SCSI_CMD_RESERVE_UNIT10 0x56 //
+#define SCSI_CMD_RELEASE_UNIT10 0x57 //
+#define SCSI_CMD_REPAIR_TRACK 0x58 //
+#define SCSI_CMD_MODE_SENSE10 0x5a // read device parameters
+#define SCSI_CMD_CLOSE_SESSION 0x5b // close area/sesssion (recordable)
+#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5c // CDR burning info.
+#define SCSI_CMD_SEND_CUE_SHEET 0x5d // (CDR Related?)
+#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e //
+#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f //
+#define SCSI_CMD_XDWRITE_EXTENDED 0x80 //
+#define SCSI_CMD_REBUILD 0x81 //
+#define SCSI_CMD_REGENERATE 0x82 //
+#define SCSI_CMD_EXTENDED_COPY 0x83 // extended copy
+#define SCSI_CMD_RECEIVE_COPY_RESULTS 0x84 // receive copy results
+#define SCSI_CMD_READ16 0x88 // read data
+#define SCSI_CMD_WRITE16 0x8a // write data
+#define SCSI_CMD_ORWRITE16 0x8b //
+#define SCSI_CMD_READ_ATTRIBUTE 0x8c // read attribute
+#define SCSI_CMD_WRITE_ATTRIBUTE 0x8d // write attribute
+#define SCSI_CMD_WRITE_VERIFY16 0x8e //
+#define SCSI_CMD_VERIFY16 0x8f //
+#define SCSI_CMD_PREFETCH16 0x90 //
+#define SCSI_CMD_SYNC_CACHE16 0x91 //
+#define SCSI_CMD_WRITE_SAME16 0x93 //
+#define SCSI_CMD_READ_CAPACITY16 0x9e // read number of logical blocks
+#define SCSI_CMD_WRITE_LONG16 0x9f //
+#define SCSI_CMD_REPORT_LUNS 0xa0 //
+#define SCSI_CMD_BLANK 0xa1 // erase RW media
+#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xa2 //
+#define SCSI_CMD_MAINTENANCE_IN 0xa3 // service actions define reports
+#define SCSI_CMD_MAINTENANCE_OUT 0xa4 // service actions define changes
+#define SCSI_CMD_SEND_KEY 0xa3 //
+#define SCSI_CMD_REPORT_KEY 0xa4 // report key (SCSI-3)
+#define SCSI_CMD_MOVE_MEDIUM 0xa5 //
+#define SCSI_CMD_PLAY_AUDIO12 0xa5 // audio playback
+#define SCSI_CMD_EXCHANGE_MEDIUM 0xa6 //
+#define SCSI_CMD_LOADCD 0xa6 //
+#define SCSI_CMD_SET_READ_AHEAD 0xa7 //
+#define SCSI_CMD_READ12 0xa8 // read (SCSI-3)
+#define SCSI_CMD_PLAY_TRACK_RELATIVE 0xa9 // audio playback starting at relative track
+#define SCSI_CMD_WRITE12 0xaa // write data
+#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab //
+#define SCSI_CMD_ERASE12 0xac // erase logical block
+#define SCSI_CMD_GET_PERFORMANCE 0xac //
+#define SCSI_CMD_READ_DVD_STRUCTURE 0xad // read DVD structure (SCSI-3)
+#define SCSI_CMD_WRITE_VERIFY12 0xae // write logical block, verify success
+#define SCSI_CMD_VERIFY12 0xaf // verify data
+#define SCSI_CMD_SEARCH_DATA_HIGH12 0xb0 // search data pattern
+#define SCSI_CMD_SEARCH_DATA_EQUAL12 0xb1 // search data pattern
+#define SCSI_CMD_SEARCH_DATA_LOW12 0xb2 // search data pattern
+#define SCSI_CMD_SET_LIMITS12 0xb3 // set block limits
#define SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR 0xb5 //
-#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5
-#define SCSI_CMD_SEND_VOLUME_TAG 0xb6 //
-#define SCSI_CMD_SET_STREAMING 0xb6 // For avoiding over/underrun
-#define SCSI_CMD_READ_DEFECT_DATA12 0xb7 // read defect data information
-#define SCSI_CMD_READ_ELEMENT_STATUS 0xb8 // read element status
-#define SCSI_CMD_SELECT_CDROM_SPEED 0xb8 // set data rate
-#define SCSI_CMD_READ_CD_MSF 0xb9 // read CD information (all formats, MSF addresses)
-#define SCSI_CMD_AUDIO_SCAN 0xba // fast audio playback
-#define SCSI_CMD_SET_CDROM_SPEED 0xbb // (proposed)
-#define SCSI_CMD_SEND_CDROM_XA_DATA 0xbc
-#define SCSI_CMD_PLAY_CD 0xbc
-#define SCSI_CMD_MECH_STATUS 0xbd
-#define SCSI_CMD_READ_CD 0xbe // read CD information (all formats, MSF addresses)
-#define SCSI_CMD_SEND_DVD_STRUCTURE 0xbf // burning DVDs?
+#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5 //
+#define SCSI_CMD_SEND_VOLUME_TAG 0xb6 //
+#define SCSI_CMD_SET_STREAMING 0xb6 // For avoiding over/underrun
+#define SCSI_CMD_READ_DEFECT_DATA12 0xb7 // read defect data information
+#define SCSI_CMD_READ_ELEMENT_STATUS 0xb8 // read element status
+#define SCSI_CMD_SELECT_CDROM_SPEED 0xb8 // set data rate
+#define SCSI_CMD_READ_CD_MSF 0xb9 // read CD information (all formats, MSF addresses)
+#define SCSI_CMD_AUDIO_SCAN 0xba // fast audio playback
+#define SCSI_CMD_SET_CDROM_SPEED 0xbb // (proposed)
+#define SCSI_CMD_SEND_CDROM_XA_DATA 0xbc //
+#define SCSI_CMD_PLAY_CD 0xbc //
+#define SCSI_CMD_MECH_STATUS 0xbd //
+#define SCSI_CMD_READ_CD 0xbe // read CD information (all formats, MSF addresses)
+#define SCSI_CMD_SEND_DVD_STRUCTURE 0xbf // burning DVDs?
/*
- * A workaround for a specific scanner (NIKON LS-2000).
+ * A workaround for a specific scanner (NIKON LS-2000).
* Can be removed once Linux backend uses 2.4.x interface
*/
#define SCSI_CMD_VENDOR_NIKON_UNKNOWN 0xe1
-#define SCSI_SENSE_KEY_NONE 0x0 // there is no sense information
+#define SCSI_SENSE_KEY_NONE 0x0 // there is no sense information
#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x1 // the last command completed succesfully but used error correction in the process
#define SCSI_SENSE_KEY_NOT_READY 0x2 // the addressed LUN is not ready to be accessed
#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x3 // the target detected a data error on the medium
#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x9 // report vendor specific condition
#define SCSI_SENSE_KEY_COPY_ABORTED 0xa // COPY, COMPARE, or COPY AND VERIFY was aborted
#define SCSI_SENSE_KEY_ABORTED_CMD 0xb // the target aborted the command
-#define SCSI_SENSE_KEY_EQUAL 0xc // comparison for SEARCH DATA was unsuccessful
+#define SCSI_SENSE_KEY_EQUAL 0xc // comparison for SEARCH DATA was unsuccessful
#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0xd // the medium is full
#define SCSI_SENSE_KEY_MISCOMPARE 0xe // source and data on the medium do not agree
/*
- * The Additional Sense Code - ASC and
- * Additional Sense Code Qualifiers - ASCQ
- * always come in pairs.
+ * The Additional Sense Code - ASC
+ * and Additional Sense Code Qualifiers - ASCQ
+ * always come in pairs.
*
* Note:
* These values are found at senseBuffer[12} and senseBuffer[13].
* You may see references to these in legacy code. New code should make an
* attempt to use the ASC/ASCQ syntax.
*/
-#define SCSI_ASC_LU_NOT_READY 0x04 // logical unit not ready
-#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY 0x01
-#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED 0x02 // initializing command required
-#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03
-#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION 0x0a // an ascq
-#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE 0x0b // an ascq
-#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION 0x05 // logical unit doesn't respond to selection
-#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06
-#define SCSI_ASC_WRITE_ERROR 0x0c // Write error
-#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11 // Unrecovered read error
-#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR 0x1a // parameter list length error
-#define SCSI_ASC_RECOVERED_DATA 0x17
-#define SCSI_ASC_INVALID_COMMAND_OPERATION 0x20 // invalid command operation code
-#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 // Invalid LBA
-#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
-#define SCSI_ASC_LU_NOT_SUPPORTED 0x25 // LU has been removed
-#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26
-#define SCSI_ASC_WRITE_PROTECTED 0x27 // device is write protected
-#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 // after changing medium
-#define SCSI_ASC_POWER_ON_OR_RESET 0x29 // device power-on or SCSI reset
-#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED 0x2a
-#define SCSI_ASC_INCOMPATIBLE_MEDIUM 0x30 // Generic bad medium error
-#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 // Saving parameters not supported
-#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a // changing medium
-#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN 0x02 // an ascq
-#define SCSI_ASC_INVALID_MESSAGE_ERROR 0x49
-#define SCSI_ASC_COMMAND_PHASE_ERROR 0x4a
-#define SCSI_ASC_DATA_PHASE_ERROR 0x4b
-#define SCSI_ASC_MEDIUM_REMOVAL_FAILED 0x53 // w/ 0x4 it is failed, 0x5 is prevented
-#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES 0x55 // during persistent reservations
-#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES 0x04
-#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06
-#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE 0x0b
-#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE 0x0c
-#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK 0x64
-
-#define SCSI_TAG_ENABLE 0x20 // Set to indicate tag is valid
-#define SCSI_TAG_SIMPLE (SCSI_TAG_ENABLE|0x0) // No constraint
-#define SCSI_TAG_HEAD (SCSI_TAG_ENABLE|0x1) // Always first
-#define SCSI_TAG_ORDER (SCSI_TAG_ENABLE|0x2) // Syncronizing
+#define SCSI_ASC_LU_NOT_READY 0x04 // logical unit not ready
+#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY 0x01
+#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED 0x02 // initializing command required
+#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03
+#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION 0x0a // an ascq
+#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE 0x0b // an ascq
+#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION 0x05 // logical unit doesn't respond to selection
+#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06
+#define SCSI_ASC_WRITE_ERROR 0x0c // Write error
+#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11 // Unrecovered read error
+#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR 0x1a // parameter list length error
+#define SCSI_ASC_RECOVERED_DATA 0x17
+#define SCSI_ASC_INVALID_COMMAND_OPERATION 0x20 // invalid command operation code
+#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 // Invalid LBA
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_LU_NOT_SUPPORTED 0x25 // LU has been removed
+#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26
+#define SCSI_ASC_WRITE_PROTECTED 0x27 // device is write protected
+#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 // after changing medium
+#define SCSI_ASC_POWER_ON_OR_RESET 0x29 // device power-on or SCSI reset
+#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED 0x2a
+#define SCSI_ASC_INCOMPATIBLE_MEDIUM 0x30 // Generic bad medium error
+#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 // Saving parameters not supported
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a // changing medium
+#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN 0x02 // an ascq
+#define SCSI_ASC_INVALID_MESSAGE_ERROR 0x49
+#define SCSI_ASC_COMMAND_PHASE_ERROR 0x4a
+#define SCSI_ASC_DATA_PHASE_ERROR 0x4b
+#define SCSI_ASC_MEDIUM_REMOVAL_FAILED 0x53 // w/ 0x4 it is failed, 0x5 is prevented
+#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES 0x55 // during persistent reservations
+#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES 0x04
+#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06
+#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE 0x0b
+#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE 0x0c
+#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK 0x64
+
+#define SCSI_TAG_ENABLE 0x20 // Set to indicate tag is valid
+#define SCSI_TAG_SIMPLE (SCSI_TAG_ENABLE|0x0) // No constraint
+#define SCSI_TAG_HEAD (SCSI_TAG_ENABLE|0x1) // Always first
+#define SCSI_TAG_ORDER (SCSI_TAG_ENABLE|0x2) // Syncronizing
#define SCSI_CMD_START_UNIT_START_BIT 0x01 // Value of Start bit for SCSI_CMD_START_UNIT
* We do not support 16-byte CDB's, only 6-, 10-, and 12-byte versions.
*/
typedef struct {
- uint32 opcode:8, // operation code
- lun:3, // logical unit number
- lbn:21; // logical block number
- uint8 len; // data length
- uint8 ctrl; // control byte
+ uint8 opcode; // operation code
+ uint8 lbnhi:5, // top 5 bits of logical block number
+ lun:3; // logical unit number
+ uint16 lbnlo; // bottom 16 bits of logical block number
+ uint8 length; // data length
+ uint8 control; // control byte
} SCSICDB6;
typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
uint8 :5,
- lun:3;
+ lun:3;
uint32 lbn;
uint8 reserved;
- uint16 len;
- uint8 ctrl;
+ uint16 length;
+ uint8 control;
}
#include "vmware_pack_end.h"
SCSICDB10;
struct {
uint8 opcode;
uint8 :5,
- lun:3;
+ lun:3;
uint32 lbn;
- uint32 len;
+ uint32 length;
uint8 reserved;
- uint8 ctrl;
+ uint8 control;
}
#include "vmware_pack_end.h"
SCSICDB12;
resv12:3,
lun :3;
uint8 pagecode; // only valid when cmddt or evdp is set
- uint8 reserved;
- uint8 len;
- uint8 ctrl;
+ uint8 reserved;
+ uint8 length;
+ uint8 control;
} SCSIInquiryCmd;
-/*
- * Format of the SCSI-3 INQUIRY command as defined in SPC-3
+/*
+ * Format of the SCSI-3 INQUIRY command as defined in SPC-3
*/
typedef struct {
uint8 opcode; // INQUIRY (0x12)
obslt :1, // Obsolete as per SPC-3
resv :6; // The remaining bits are all RESERVED
uint8 pagecode; // Only valid when evpd is set
- uint8 lenMSB; // The SPC-3 spec has a 2 byte len field
- uint8 len;
- uint8 ctrl;
+ uint8 lengthMSB; // The SPC-3 spec has a 2 byte len field
+ uint8 length;
+ uint8 control;
} SCSI3InquiryCmd;
typedef struct {
uint8 devclass :5, // SCSI device class
-#define SCSI_CLASS_DISK 0x00 // disk drive
-#define SCSI_CLASS_TAPE 0x01 // tape drive
-#define SCSI_CLASS_PRINTER 0x02 // printer
-#define SCSI_CLASS_CPU 0x03 // processor device
-#define SCSI_CLASS_WORM 0x04 // WORM drive
-#define SCSI_CLASS_CDROM 0x05 // CD-ROM drive
-#define SCSI_CLASS_SCANNER 0x06 // scanner
-#define SCSI_CLASS_OPTICAL 0x07 // optical disk
-#define SCSI_CLASS_MEDIA 0x08 // media changer
-#define SCSI_CLASS_COM 0x09 // communication device
-#define SCSI_CLASS_RAID 0x0c // RAID controller (SCSI-3, reserved in SCSI-2)
-#define SCSI_CLASS_SES 0x0d // SCSI Enclosure Services device (t10 SES)
-#define SCSI_CLASS_UNKNOWN 0x1f // unknown device
- pqual :3; // peripheral qualifier
-#define SCSI_PQUAL_CONNECTED 0 // device described is connected to the LUN
-#define SCSI_PQUAL_NOTCONNECTED 1 // target supports such a device, but none is connected
-#define SCSI_PQUAL_NODEVICE 3 // target does not support a physical device for this LUN
- uint8 :7, // reserved for SCSI-1
- rmb:1; // removable bit
- uint8 ansi :3, // ANSI version
-#define SCSI_ANSI_SCSI1 0x0 // device supports SCSI-1
-#define SCSI_ANSI_CCS 0x1 // device supports the CCS
-#define SCSI_ANSI_SCSI2 0x2 // device supports SCSI-2
+#define SCSI_CLASS_DISK 0x00 // disk drive
+#define SCSI_CLASS_TAPE 0x01 // tape drive
+#define SCSI_CLASS_PRINTER 0x02 // printer
+#define SCSI_CLASS_CPU 0x03 // processor device
+#define SCSI_CLASS_WORM 0x04 // WORM drive
+#define SCSI_CLASS_CDROM 0x05 // CD-ROM drive
+#define SCSI_CLASS_SCANNER 0x06 // scanner
+#define SCSI_CLASS_OPTICAL 0x07 // optical disk
+#define SCSI_CLASS_MEDIA 0x08 // media changer
+#define SCSI_CLASS_COM 0x09 // communication device
+#define SCSI_CLASS_RAID 0x0c // RAID controller (SCSI-3, reserved in SCSI-2)
+#define SCSI_CLASS_SES 0x0d // SCSI Enclosure Services device (t10 SES)
+#define SCSI_CLASS_UNKNOWN 0x1f // unknown device
+ pqual :3; // peripheral qualifier
+#define SCSI_PQUAL_CONNECTED 0 // device described is connected to the LUN
+#define SCSI_PQUAL_NOTCONNECTED 1 // target supports such a device, but none is connected
+#define SCSI_PQUAL_NODEVICE 3 // target does not support a physical device for this LUN
+ uint8 :7, // reserved for SCSI-1
+ rmb :1; // removable bit
+ uint8 ansi :3, // ANSI version
+#define SCSI_ANSI_SCSI1 0x0 // device supports SCSI-1
+#define SCSI_ANSI_CCS 0x1 // device supports the CCS
+#define SCSI_ANSI_SCSI2 0x2 // device supports SCSI-2
#define SCSI_ANSI_SCSI3_SPC 0x3 // device supports SCSI-3 version SPC
#define SCSI_ANSI_SCSI3_SPC2 0x4 // device supports SCSI-3 version SPC-2
#define SCSI_ANSI_SCSI3_SPC3 0x5 // device supports SCSI-3 version SPC-3
#define SCSI_ANSI_SCSI3_SPC4 0x6 // device supports SCSI-3 version SPC-4
- ecma :3, // ECMA version
- iso :2; // ISO version
+ ecma :3, // ECMA version
+ iso :2; // ISO version
uint8 dataformat :4, // format of the following standard data
- :1,
- naca :1,
- tio :1, // device supports TERMINATE I/O PROCESS message
- aen :1; // asynchronous event notification capability
- uint8 optlen; // length of additional data that follows
- uint8 :4,
- tpgs :2, // Target Portal Group Support
- :2;
+ :1,
+ naca :1,
+ tio :1, // device supports TERMINATE I/O PROCESS message
+ aen :1; // asynchronous event notification capability
+ uint8 optlen; // length of additional data that follows
+ uint8 :4,
+ tpgs :2, // Target Portal Group Support
+ :2;
#define SCSI_TPGS_NONE 0x0
#define SCSI_TPGS_IMPLICIT_ONLY 0x1
-#define SCSI_TPGS_IMPLICIT SCSI_TPGS_IMPLICIT_ONLY
+#define SCSI_TPGS_IMPLICIT SCSI_TPGS_IMPLICIT_ONLY
#define SCSI_TPGS_EXPLICIT_ONLY 0x2
#define SCSI_TPGS_EXPLICIT SCSI_TPGS_EXPLICIT_ONLY
#define SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT 0x3
#define SCSI_TPGS_BOTH SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT
- uint8 adr16 :1, // device supports 16-bit wide SCSI addresses
- adr32 :1, // device supports 32-bit wide SCSI addresses
- arq :1,
- mchngr :1, // device has attached media changer (SCSI-3)
- dualp :1, // device is dual-ported (SCSI-3)
- port :1, // port A or port B when dual-ported (SCSI-3)
- :2;
- uint8 sftr :1, // device supports soft reset capability
- que :1, // device supports tagged commands
- trndis :1, // device supports transfer disable messages (SCSI-3)
- link :1, // device supports linked commands
- sync :1, // device supports synchronous transfers
- w16 :1, // device supports 16-bit wide SCSI data transfers
- w32 :1, // device supports 32-bit wide SCSI data transfers
- rel :1; // device supports relative addressing
+ uint8 adr16 :1, // device supports 16-bit wide SCSI addresses
+ adr32 :1, // device supports 32-bit wide SCSI addresses
+ arq :1,
+ mchngr :1, // device has attached media changer (SCSI-3)
+ dualp :1, // device is dual-ported (SCSI-3)
+ port :1, // port A or port B when dual-ported (SCSI-3)
+ :2;
+ uint8 sftr :1, // device supports soft reset capability
+ que :1, // device supports tagged commands
+ trndis :1, // device supports transfer disable messages (SCSI-3)
+ link :1, // device supports linked commands
+ sync :1, // device supports synchronous transfers
+ w16 :1, // device supports 16-bit wide SCSI data transfers
+ w32 :1, // device supports 32-bit wide SCSI data transfers
+ rel :1; // device supports relative addressing
uint8 manufacturer[8]; // manufacturer's name in ascii
#define SCSI_VENDOR_SZ sizeof(((SCSIInquiryResponse *) 0)->manufacturer)
- uint8 product[16]; // product name in ascii
+ uint8 product[16]; // product name in ascii
#define SCSI_MODEL_SZ sizeof(((SCSIInquiryResponse *) 0)->product)
- uint8 revision[4]; // product version number in ascii
- uint8 vendor1[20]; // vendor unique data (opaque)
+ uint8 revision[4]; // product version number in ascii
+ uint8 vendor1[20]; // vendor unique data (opaque)
uint8 reserved[40];
-} SCSIInquiryResponse; // standard INQUIRY response format
+} SCSIInquiryResponse; // standard INQUIRY response format
/*
* Same as SCSIInquiryResponse, except that only 36 bytes long. See above
*/
typedef struct {
uint8 devclass :5, // SCSI device class
- pqual :3; // peripheral qualifier
- uint8 :7, // reserved for SCSI-1
- rmb:1; // removable bit
- uint8 ansi :3, // ANSI version
- ecma :3, // ECMA version
- iso :2; // ISO version
+ pqual :3; // peripheral qualifier
+ uint8 :7, // reserved for SCSI-1
+ rmb :1; // removable bit
+ uint8 ansi :3, // ANSI version
+ ecma :3, // ECMA version
+ iso :2; // ISO version
uint8 dataformat :4, // format of the following standard data
- :1,
- naca :1,
- tio :1, // device supports TERMINATE I/O PROCESS message
- aen :1; // asynchronous event notification capability
- uint8 optlen; // length of additional data that follows
- uint8 :4,
- tpgs :2, // Target Portal Group Support
- :2;
- uint8 adr16 :1, // device supports 16-bit wide SCSI addresses
- adr32 :1, // device supports 32-bit wide SCSI addresses
- arq :1,
- mchngr :1, // device has attached media changer (SCSI-3)
- dualp :1, // device is dual-ported (SCSI-3)
- port :1, // port A or port B when dual-ported (SCSI-3)
- :2;
- uint8 sftr :1, // device supports soft reset capability
- que :1, // device supports tagged commands
- trndis :1, // device supports transfer disable messages (SCSI-3)
- link :1, // device supports linked commands
- sync :1, // device supports synchronous transfers
- w16 :1, // device supports 16-bit wide SCSI data transfers
- w32 :1, // device supports 32-bit wide SCSI data transfers
- rel :1; // device supports relative addressing
+ :1,
+ naca :1,
+ tio :1, // device supports TERMINATE I/O PROCESS message
+ aen :1; // asynchronous event notification capability
+ uint8 optlen; // length of additional data that follows
+ uint8 :4,
+ tpgs :2, // Target Portal Group Support
+ :2;
+ uint8 adr16 :1, // device supports 16-bit wide SCSI addresses
+ adr32 :1, // device supports 32-bit wide SCSI addresses
+ arq :1,
+ mchngr :1, // device has attached media changer (SCSI-3)
+ dualp :1, // device is dual-ported (SCSI-3)
+ port :1, // port A or port B when dual-ported (SCSI-3)
+ :2;
+ uint8 sftr :1, // device supports soft reset capability
+ que :1, // device supports tagged commands
+ trndis :1, // device supports transfer disable messages (SCSI-3)
+ link :1, // device supports linked commands
+ sync :1, // device supports synchronous transfers
+ w16 :1, // device supports 16-bit wide SCSI data transfers
+ w32 :1, // device supports 32-bit wide SCSI data transfers
+ rel :1; // device supports relative addressing
uint8 manufacturer[8]; // manufacturer's name in ascii
- uint8 product[16]; // product name in ascii
- uint8 revision[4]; // product version number in ascii
+ uint8 product[16]; // product name in ascii
+ uint8 revision[4]; // product version number in ascii
} SCSIInquiry36Response; // standard INQUIRY response format
#define SCSI_STANDARD_INQUIRY_MIN_LENGTH 36
/*
* The following structures define the Page format supported by the
* vscsi layer in vmkernel. The SPC-3 r23 spec defines a very generic
- * layout of these pages, however the structures here are customized
+ * layout of these pages, however the structures here are customized
* for vmkernel.
*/
typedef
#include "vmware_pack_begin.h"
struct SCSIInqPage00ResponseHeader {
- uint8 devClass :5,
- pQual :3;
- uint8 pageCode;
- uint8 reserved1;
- uint8 pageLength;
+ uint8 devClass :5,
+ pQual :3;
+ uint8 pageCode;
+ uint8 reserved1;
+ uint8 pageLength;
}
#include "vmware_pack_end.h"
SCSIInqPage00ResponseHeader;
typedef
#include "vmware_pack_begin.h"
struct SCSIInqPage80ResponseHeader {
- uint8 devClass :5,
- pQual :3;
- uint8 pageCode;
- uint8 reserved1;
- uint8 pageLength;
+ uint8 devClass :5,
+ pQual :3;
+ uint8 pageCode;
+ uint8 reserved1;
+ uint8 pageLength;
}
#include "vmware_pack_end.h"
SCSIInqPage80ResponseHeader;
// Inquiry page 0x83: Identifier Type
-#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC 0x0
-#define SCSI_IDENTIFIERTYPE_T10 0x1
-#define SCSI_IDENTIFIERTYPE_EUI 0x2
-#define SCSI_IDENTIFIERTYPE_NAA 0x3
-#define SCSI_IDENTIFIERTYPE_RTPI 0x4
-#define SCSI_IDENTIFIERTYPE_TPG 0x5
-#define SCSI_IDENTIFIERTYPE_LUG 0x6
-#define SCSI_IDENTIFIERTYPE_MD5 0x7
-#define SCSI_IDENTIFIERTYPE_SNS 0x8
-#define SCSI_IDENTIFIERTYPE_RESERVED 0x9
-#define SCSI_IDENTIFIERTYPE_MAX SCSI_IDENTIFIERTYPE_RESERVED
+#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC 0x0
+#define SCSI_IDENTIFIERTYPE_T10 0x1
+#define SCSI_IDENTIFIERTYPE_EUI 0x2
+#define SCSI_IDENTIFIERTYPE_NAA 0x3
+#define SCSI_IDENTIFIERTYPE_RTPI 0x4
+#define SCSI_IDENTIFIERTYPE_TPG 0x5
+#define SCSI_IDENTIFIERTYPE_LUG 0x6
+#define SCSI_IDENTIFIERTYPE_MD5 0x7
+#define SCSI_IDENTIFIERTYPE_SNS 0x8
+#define SCSI_IDENTIFIERTYPE_RESERVED 0x9
+#define SCSI_IDENTIFIERTYPE_MAX SCSI_IDENTIFIERTYPE_RESERVED
// Inquiry page 0x83: Transport Layer
-#define SCSI_PROTOCOLID_FCP2 0x0
-#define SCSI_PROTOCOLID_SPI5 0x1
-#define SCSI_PROTOCOLID_SSAS3P 0x2
-#define SCSI_PROTOCOLID_SBP3 0x3
-#define SCSI_PROTOCOLID_SRP 0x4
-#define SCSI_PROTOCOLID_ISCSI 0x5
-#define SCSI_PROTOCOLID_SAS 0x6
-#define SCSI_PROTOCOLID_ADT 0x7
-#define SCSI_PROTOCOLID_ATA 0x8
-#define SCSI_PROTOCOLID_RESERVED 0xE
-#define SCSI_PROTOCOLID_NO_PROTOCOL 0xF
+#define SCSI_PROTOCOLID_FCP2 0x0
+#define SCSI_PROTOCOLID_SPI5 0x1
+#define SCSI_PROTOCOLID_SSAS3P 0x2
+#define SCSI_PROTOCOLID_SBP3 0x3
+#define SCSI_PROTOCOLID_SRP 0x4
+#define SCSI_PROTOCOLID_ISCSI 0x5
+#define SCSI_PROTOCOLID_SAS 0x6
+#define SCSI_PROTOCOLID_ADT 0x7
+#define SCSI_PROTOCOLID_ATA 0x8
+#define SCSI_PROTOCOLID_RESERVED 0xE
+#define SCSI_PROTOCOLID_NO_PROTOCOL 0xF
// Inquiry page 0x83: UUID Encoding
-#define SCSI_CODESET_BINARY 0x1
-#define SCSI_CODESET_ASCII 0x2
-#define SCSI_CODESET_UTF8 0x3
-#define SCSI_CODESET_RESERVED 0xF
+#define SCSI_CODESET_BINARY 0x1
+#define SCSI_CODESET_ASCII 0x2
+#define SCSI_CODESET_UTF8 0x3
+#define SCSI_CODESET_RESERVED 0xF
// Inquiry page 0x83: UUID Entity
-#define SCSI_ASSOCIATION_LUN 0x0
-#define SCSI_ASSOCIATION_TARGET_PORT 0x1
-#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2
-#define SCSI_ASSOCIATION_RESERVED 0x3
+#define SCSI_ASSOCIATION_LUN 0x0
+#define SCSI_ASSOCIATION_TARGET_PORT 0x1
+#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2
+#define SCSI_ASSOCIATION_RESERVED 0x3
typedef
#include "vmware_pack_begin.h"
struct SCSIInqPage83ResponseHeader {
- uint8 devClass :5,
- pQual :3;
+ uint8 devClass :5,
+ pQual :3;
uint8 pageCode;
uint16 pageLength;
}
#include "vmware_pack_begin.h"
struct SCSI2InqPage83ResponseDescriptor {
/* Identification Descriptor follows */
- uint8 codeSet :4,
- reserved :4;
- uint8 idType :4,
+ uint8 codeSet :4,
+ reserved :4;
+ uint8 idType :4,
association :2,
- reserved1 :2;
+ reserved1 :2;
uint8 reserved2;
uint8 idLength;
}
* may need them.
*/
typedef struct {
- uint8 opcode; // operation code
- uint8 :3,
- dbd :1, // disable block descriptors
- :1,
- lun :3; // logical unit number
- uint8 page :6, // page code
+ uint8 opcode; // operation code
+ uint8 :3,
+ dbd :1, // disable block descriptors
+ :1,
+ lun :3; // logical unit number
+ uint8 page :6, // page code
#define SCSI_MS_PAGE_VENDOR 0x00 // vendor-specific (ALL)
#define SCSI_MS_PAGE_RWERROR 0x01 // read/write error (DISK/TAPE/CDROM/OPTICAL)
#define SCSI_MS_PAGE_CONNECT 0x02 // disconnect/connect (ALL)
#define SCSI_MS_PAGE_CDCAPS 0x2a // CD-ROM capabilities and mechanical status (CDROM)
// more defined...
#define SCSI_MS_PAGE_ALL 0x3f // all available pages (ALL)
- pcf :2; // page control field
+ pcf :2; // page control field
#define SCSI_MS_PCF_CURRENT 0x00 // current values
#define SCSI_MS_PCF_VOLATILE 0x01 // changeable values
#define SCSI_MS_PCF_DEFAULT 0x02 // default values
#define SCSI_MS_PCF_SAVED 0x03 // saved values
uint8 subpage;
- uint8 length; // data length
- uint8 ctrl; // control byte
+ uint8 length; // data length
+ uint8 control; // control byte
} SCSIModeSenseCmd;
typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // FORMAT UNIT (0x4)
- uint8 dlf :3, // defect list format
- cmplst :1, // complete list
- fmtdata:1, // format data
- lun :3;
+ uint8 opcode; // FORMAT UNIT (0x4)
+ uint8 dlf :3, // defect list format
+ cmplst :1, // complete list
+ fmtdata:1, // format data
+ lun :3;
uint8 vendor;
uint16 interleave;
uint8 control;
* Format Defect List header
*/
typedef struct {
- uint8 reserved;
- uint8 fov :1, // Format options valid
- dpry :1, // disable primary
- dcrt :1, // disable certification
- stpf :1, // stop format
- ip :1, // initialization pattern
- dsp :1, // disable saving parameters
- immed :1, // immediate
- vs :1;
- uint16 length; // Defect list length
+ uint8 reserved;
+ uint8 fov :1, // Format options valid
+ dpry :1, // disable primary
+ dcrt :1, // disable certification
+ stpf :1, // stop format
+ ip :1, // initialization pattern
+ dsp :1, // disable saving parameters
+ immed :1, // immediate
+ vs :1;
+ uint16 length; // Defect list length
} SCSIDefectListHdr;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // operation code
- uint8 :3,
- dbd :1, // disable block descriptors
- :1,
- lun :3; // logical unit number
- uint8 page :6, // page code
- pcf :2; // page control field
+ uint8 opcode; // operation code
+ uint8 :3,
+ dbd :1, // disable block descriptors
+ :1,
+ lun :3; // logical unit number
+ uint8 page :6, // page code
+ pcf :2; // page control field
uint8 reserved[4];
uint16 length; // data length
- uint8 ctrl; // control byte
+ uint8 control; // control byte
}
#include "vmware_pack_end.h"
SCSIModeSense10Cmd;
typedef struct {
- uint8 opcode; // operation code
- uint8 sp :1, // save pages
- :3,
- pf :1, // page format
- lun :3; // logical unit number
+ uint8 opcode; // operation code
+ uint8 sp :1, // save pages
+ :3,
+ pf :1, // page format
+ lun :3; // logical unit number
uint8 reserved[2];
- uint8 len; // data length
- uint8 ctrl; // control byte
+ uint8 length; // data length
+ uint8 control; // control byte
} SCSIModeSelectCmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // operation code
- uint8 sp :1, // save pages
- :3,
- pf :1, // page format
- lun :3; // logical unit number
+ uint8 opcode; // operation code
+ uint8 sp :1, // save pages
+ :3,
+ pf :1, // page format
+ lun :3; // logical unit number
uint8 reserved[5];
- uint16 len; // data length
- uint8 ctrl; // control byte
+ uint16 length; // data length
+ uint8 control; // control byte
}
#include "vmware_pack_end.h"
SCSIModeSelect10Cmd;
typedef struct {
- uint8 len; // data length
+ uint8 len; // data length
uint8 mediaType;
uint8 devSpecific; // device specific
- uint8 bdLen; // block descriptor length
+ uint8 bdLen; // block descriptor length
} SCSIModeHeader6;
typedef struct {
- uint16 len; // data length
+ uint16 len; // data length
uint8 mediaType;
uint8 devSpecific; // device specific
uint16 reserved;
- uint16 bdLen; // block descriptor length
+ uint16 bdLen; // block descriptor length
} SCSIModeHeader10;
typedef struct {
- uint8 reserved1:4;
- uint8 dpofua:1; // disable page out / force unit access
- uint8 reserved2:2;
- uint8 wp:1; // write protected
+ uint8 reserved1:4,
+ dpofua :1, // disable page out / force unit access
+ reserved2:2,
+ wp :1; // write protected
} SCSIBlockModeSenseDeviceParameter;
/*
typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode:8; // operation code
- uint8 ext:1,
- tid:3,
- tparty:1,
- lun:3; // logical unit number
+ uint8 opcode:8; // operation code
+ uint8 ext :1,
+ tid :3,
+ tparty:1,
+ lun :3; // logical unit number
uint8 resid;
uint16 extlen;
uint8 control;
* types (a fourth is added in SCSI-3). The following structures
* define these pages as sent+received with MODE SENSE and SELECT.
*/
-typedef struct { // connect/disconnect page
- uint8 page :6, // page code: 0x02
- :1,
- ps :1;
- uint8 len; // page length (0x0e)
+typedef struct { // connect/disconnect page
+ uint8 page :6, // page code: 0x02
+ :1,
+ ps :1;
+ uint8 len; // page length (0x0e)
uint8 bufFull;
uint8 bufEmpty;
uint16 maxBusInactiveTime;
uint16 maxConnectTime;
uint16 maxBurstLength;
uint8 dtdc :3,
- dimm :1, // disconnect immediate (SCSI-3)
- :3,
- emdp :1; // enable MODIFY DATA POINTER (SCSI-3)
+ dimm :1, // disconnect immediate (SCSI-3)
+ :3,
+ emdp :1; // enable MODIFY DATA POINTER (SCSI-3)
} SCSIConnectPage;
-typedef struct { // peripheral device page
- uint8 page :6, // page code: 0x09
- :1,
- ps :1;
- uint8 len; // page length (n-1)
- uint16 ifID; // physical interface identifier
+typedef struct { // peripheral device page
+ uint8 page :6, // page code: 0x09
+ :1,
+ ps :1;
+ uint8 len; // page length (n-1)
+ uint16 ifID; // physical interface identifier
uint8 reserved[4];
uint8 undefined[1]; // variable-length vendor-specific data
} SCSIPeriphPage;
typedef struct {
- uint8 page :6, // page code: 0x0a
- :1,
- ps :1;
- uint8 len; // page length (0x06)
+ uint8 page :6, // page code: 0x0a
+ :1,
+ ps :1;
+ uint8 len; // page length (0x06)
uint8 rlec :1,
- gltsd :1,
- :2,
- :4;
- uint8 dque :1, // disable tagged queuing
- qerr :1, //
- :2,
- qalg :4; // queue algorithm
- uint8 eaenp :1, // error AEN permission
- uaaenp:1, // unit attention AEN permission
- raenp :1, // ready AEN permission
- :4,
- eeca :1; //
+ gltsd :1,
+ :2,
+ :4;
+ uint8 dque :1, // disable tagged queuing
+ qerr :1, //
+ :2,
+ qalg :4; // queue algorithm
+ uint8 eaenp :1, // error AEN permission
+ uaaenp:1, // unit attention AEN permission
+ raenp :1, // ready AEN permission
+ :4,
+ eeca :1; //
uint8 reserved;
uint16 aenWaitTime; // AEN waiting time after initialization
uint16 busyTimeout; // busy timeout in 100ms (SCSI-3)
} SCSIControlPage;
typedef struct {
- uint8 page :6, // page code: 0x09
- :1,
- ps :1;
- uint8 len; // page length 0x06
- uint8 dcr :1, // error recover parameters
- dte :1, // diable transfer on seeing recovered error
- per :1, // post error: report recovered errors
- :1,
- rc :1, // read continuous: don't delay data transfer to correct errors
- tb :1, // transfer block when unrecovered
- :2;
+ uint8 page :6, // page code: 0x09
+ :1,
+ ps :1;
+ uint8 len; // page length 0x06
+ uint8 dcr :1, // error recover parameters
+ dte :1, // diable transfer on seeing recovered error
+ per :1, // post error: report recovered errors
+ :1,
+ rc :1, // read continuous: don't delay data transfer to correct errors
+ tb :1, // transfer block when unrecovered
+ :2;
uint8 readRetries; // read retry count
uint8 reserved[4];
} SCSIRWErrorPage;
typedef struct {
- uint8 page :6, // page code: 0x0d
- :1,
- ps :1;
- uint8 len; // page length 0x06
- uint8 :8;
- uint8 inactive:4, // head inactivity timeout
- :4;
+ uint8 page :6, // page code: 0x0d
+ :1,
+ ps :1;
+ uint8 len; // page length 0x06
+ uint8 :8;
+ uint8 inactive :4, // head inactivity timeout
+ :4;
uint16 secsPerMinute; // number of MSF seconds per MSF minute
uint16 framesPerSec; // number of MSF frames per MSF second
} SCSICDROMPage;
typedef struct {
- uint8 page :6, // page code: 0x0e
- :1,
- ps :1;
- uint8 len; // page length 0x0e
- uint8 :1,
- sotb :1,
- immediate:1,
- :5;
- uint8 :8;
- uint8 :8;
+ uint8 page :6, // page code: 0x0e
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0e
+ uint8 :1,
+ sotb :1,
+ immediate:1,
+ :5;
+ uint8 :8;
+ uint8 :8;
uint8 lbaFactor:4,
- :3,
- aprv :1;
- uint16 lbaPerSec; // number of LBAs per second
- uint8 port0 :4, // output port 0 select
- :4;
+ :3,
+ aprv :1;
+ uint16 lbaPerSec; // number of LBAs per second
+ uint8 port0 :4, // output port 0 select
+ :4;
uint8 port0Volume;
- uint8 port1 :4, // output port 1 select
- :4;
+ uint8 port1 :4, // output port 1 select
+ :4;
uint8 port1Volume;
- uint8 port2 :4, // output port 2 select
- :4;
+ uint8 port2 :4, // output port 2 select
+ :4;
uint8 port2Volume;
- uint8 port3 :4, // output port 3 select
- :4;
+ uint8 port3 :4, // output port 3 select
+ :4;
uint8 port3Volume;
} SCSICDROMAudioPage;
typedef struct {
- uint8 page :6, // page code: 0x2a
- :1,
- ps :1;
- uint8 len; // page length 0x12
- uint8 cdrRd :1,// CD-R read per Orange Book Part II
- cdeRd :1,// CD-E read per Orange Book Part III
- method2 :1,// CD-R media w/ Addressing Method 2
- :5;
- uint8 cdrWr :1,// CD-R write per Orange Book Part II
- cdeWr :1,// CD-E write per Orange Book Part III
- :6;
- uint8 audioPlay :1,// drive is capable of audio play
- composite :1,// drive is capable of delivering composite audio+video
- digPort1 :1,// drive supports digital output (IEC958) on port 1
- digPort2 :1,// drive supports digital output on port 2
- mode2Form1 :1,// drive reads Mode 2 Form 1 (XA) format
- mode2Form2 :1,// drive reads Mode 2 Form 2 format
- multiSession:1,// drive reads multi-session or Photo-CD discs
- :1;
- uint8 cdDA :1,// CD-DA commands (Red Book) supported
- daAccu :1,// CD-DA stream is accurate
- rwSupported :1,// R-W supported
- rwDeinter :1,// R-W subchannel data de-interleaved and corrected
- c2Ptrs :1,// C2 Error Pointers supported
- isrc :1,// drive returns International Standard Recording Code Info
- upc :1,// drive returns Media Catalog Number
- :1;
- uint8 lock :1,// PREVENT/ALLOW commands lock media into drive
- lockState :1,// current state of drive
- jumpers :1,// state of prevent/allow jumpers
- eject :1,// drive can eject disc via START/STOP command
- :1,
- loadType :3;// loading mechanism type
- uint8 sv :1,// separate volume
- scm :1,// separate channel mute
- sdp :1,// supports disc present in MECHANISM STATUS command
- sss :1,// s/w slot selection w/ LOAD/UNLOCK command
- :4;
- uint16 maxSpeed; // maximum speed supported (in KB/s)
+ uint8 page :6, // page code: 0x2a
+ :1,
+ ps :1;
+ uint8 len; // page length 0x12
+ uint8 cdrRd :1, // CD-R read per Orange Book Part II
+ cdeRd :1, // CD-E read per Orange Book Part III
+ method2 :1, // CD-R media w/ Addressing Method 2
+ :5;
+ uint8 cdrWr :1, // CD-R write per Orange Book Part II
+ cdeWr :1, // CD-E write per Orange Book Part III
+ :6;
+ uint8 audioPlay:1, // drive is capable of audio play
+ composite:1, // drive is capable of delivering composite audio+video
+ digPort1 :1, // drive supports digital output (IEC958) on port 1
+ digPort2 :1, // drive supports digital output on port 2
+ mode2Form1:1, // drive reads Mode 2 Form 1 (XA) format
+ mode2Form2:1, // drive reads Mode 2 Form 2 format
+ multiSession:1,// drive reads multi-session or Photo-CD discs
+ :1;
+ uint8 cdDA :1, // CD-DA commands (Red Book) supported
+ daAccu :1, // CD-DA stream is accurate
+ rwSupported:1, // R-W supported
+ rwDeinter:1, // R-W subchannel data de-interleaved and corrected
+ c2Ptrs :1, // C2 Error Pointers supported
+ isrc :1, // drive returns International Standard Recording Code Info
+ upc :1, // drive returns Media Catalog Number
+ :1;
+ uint8 lock :1, // PREVENT/ALLOW commands lock media into drive
+ lockState:1, // current state of drive
+ jumpers :1, // state of prevent/allow jumpers
+ eject :1, // drive can eject disc via START/STOP command
+ :1,
+ loadType :3; // loading mechanism type
+ uint8 sv :1, // separate volume
+ scm :1, // separate channel mute
+ sdp :1, // supports disc present in MECHANISM STATUS command
+ sss :1, // s/w slot selection w/ LOAD/UNLOCK command
+ :4;
+ uint16 maxSpeed; // maximum speed supported (in KB/s)
uint16 numVolLevels; // number of volume levels supported
- uint16 bufSize; // buffer size supported by drive (KBytes)
- uint16 curSpeed; // current speed selected (in KB/s)
+ uint16 bufSize; // buffer size supported by drive (KBytes)
+ uint16 curSpeed; // current speed selected (in KB/s)
uint8 reserved;
- uint8 :1,// format of digital data output
- bck :1,// data is valid on the falling edge of BCK
- rck :1,// HIGH on LRCK indicates left channel
- lsbf :1,// LSB first
- length :2,
- :2;
+ uint8 :1, // format of digital data output
+ bck :1, // data is valid on the falling edge of BCK
+ rck :1, // HIGH on LRCK indicates left channel
+ lsbf :1, // LSB first
+ length :2,
+ :2;
uint8 reserved2[2];
} SCSICDROMCapabilitiesPage;
typedef struct {
- uint8 page :6, // page code: 0x03
- :1,
- ps :1;
- uint8 len; // page length 0x16
+ uint8 page :6, // page code: 0x03
+ :1,
+ ps :1;
+ uint8 len; // page length 0x16
uint16 tracksPerZone;
uint16 repSectorsPerZone;
uint16 repTracksPerZone;
uint16 interleave;
uint16 trackSkew;
uint16 cylinderSkew;
- uint8 :3,
- surf :1,
- rmb :1,
- hsec :1,
- ssec :1;
+ uint8 :3,
+ surf :1,
+ rmb :1,
+ hsec :1,
+ ssec :1;
uint8 reserved[3];
} SCSIFormatPage;
typedef uint8 uint24[3];
typedef struct {
- uint8 page :6, // page code: 0x04
- :1,
- ps :1;
- uint8 len; // page length 0x16
- uint24 cylinders; // number of cylinders
- uint8 heads; // number of heads
+ uint8 page :6, // page code: 0x04
+ :1,
+ ps :1;
+ uint8 len; // page length 0x16
+ uint24 cylinders; // number of cylinders
+ uint8 heads; // number of heads
uint24 writeCompCylinder; // starting cylinder for write compensation
uint24 writeCurCylinder; // starting cylinder for reduce write current
uint16 stepRate;
- uint24 landingZone; // cylinder number of landing zone
- uint8 rpl :1,
- :7;
- uint8 rotOffset; // rotational offset
- uint8 :8;
- uint16 rotRate; // medium rotation rate
+ uint24 landingZone; // cylinder number of landing zone
+ uint8 rpl :1,
+ :7;
+ uint8 rotOffset; // rotational offset
+ uint8 :8;
+ uint16 rotRate; // medium rotation rate
uint8 reserved[2];
} SCSIGeometryPage;
typedef struct {
- uint8 page :6, // page code: 0x08
- :1,
- ps :1;
- uint8 len; // page length 0x0a (0x12 for SCSI-3)
- uint8 rcd :1,
- mf :1,
- wce :1,
- :5;
- uint8 readPri:4, // read retention priority
- writePri:4; // write retention priority
+ uint8 page :6, // page code: 0x08
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0a (0x12 for SCSI-3)
+ uint8 rcd :1,
+ mf :1,
+ wce :1,
+ :5;
+ uint8 readPri :4, // read retention priority
+ writePri :4; // write retention priority
uint16 prefetchDisable;// disable pre-fetch transfer length
uint16 prefetchMin; // pre-fetch minimum
uint16 prefetchMax; // pre-fetch maximum
} SCSICachePage;
typedef struct {
- uint8 page :6, // page code: 0x08
- :1,
- ps :1;
- uint8 len; // page length 0x16
- uint8 :6,
- lpn :1,
- nd :1;
- uint8 :8;
- uint16 maxNotches; // maximum number of notches
+ uint8 page :6, // page code: 0x08
+ :1,
+ ps :1;
+ uint8 len; // page length 0x16
+ uint8 :6,
+ lpn :1,
+ nd :1;
+ uint8 :8;
+ uint16 maxNotches; // maximum number of notches
uint16 activeNotch;
- uint32 activeStart; // beginning of active notch
- uint32 activeEnd; // end of active notch
+ uint32 activeStart;// beginning of active notch
+ uint32 activeEnd; // end of active notch
} SCSINotchPage;
typedef struct {
- uint8 page :6, // page code: 0x06
- :1,
- ps :1;
- uint8 len; // page length 0x02
+ uint8 page :6, // page code: 0x06
+ :1,
+ ps :1;
+ uint8 len; // page length 0x02
uint8 rubr :1,
- :7;
- uint8 :8;
+ :7;
+ uint8 :8;
} SCSIOpticalPage;
+
typedef struct {
- uint8 page :6, // page code: 0x0f
- :1,
- ps :1;
- uint8 len; // page length 0x0e
- uint8 :6,
- dcc :1,
- dce :1;
- uint8 :5,
- red :2,
- dde :1;
+ uint8 page :6, // page code: 0x0f
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0e
+ uint8 :6,
+ dcc :1,
+ dce :1;
+ uint8 :5,
+ red :2,
+ dde :1;
uint8 compAlg[4];
uint8 decompAlg[4];
uint8 reserved[4];
} SCSICompressionPage;
typedef struct {
- uint8 page :6, // page code: 0x10
- :1,
- ps :1;
- uint8 len; // page length 0x0e
- uint8 format:5, // active format
- car :1,
- cap :1,
- :1;
- uint8 partition; // active partition
- uint8 wbeRatio; // write buffer empty ratio
- uint8 rbeRatio; // read buffer empty ratio
+ uint8 page :6, // page code: 0x10
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0e
+ uint8 format:5, // active format
+ car :1,
+ cap :1,
+ :1;
+ uint8 partition; // active partition
+ uint8 wbeRatio; // write buffer empty ratio
+ uint8 rbeRatio; // read buffer empty ratio
uint16 writeDelay;
- uint8 rew :1,
- rb0 :1,
- sofc :2,
- avc :1,
- rsmk :1,
- bis :1,
- dbr :1;
+ uint8 rew :1,
+ rb0 :1,
+ sofc :2,
+ avc :1,
+ rsmk :1,
+ bis :1,
+ dbr :1;
uint8 gapSize;
- uint8 :3,
- sew :1,
- eeg :1,
- eod :3;
+ uint8 :3,
+ sew :1,
+ eeg :1,
+ eod :3;
uint24 bufSizeAtEW;
uint8 compression;
- uint8 :8;
+ uint8 :8;
} SCSIDeviceConfigPage;
typedef struct {
- uint8 page :6, // page code: 0x03
- :1,
- ps :1;
- uint8 len; // page length 0x06
- uint8 unit; // measurement unit
- uint8 :8;
+ uint8 page :6, // page code: 0x03
+ :1,
+ ps :1;
+ uint8 len; // page length 0x06
+ uint8 unit; // measurement unit
+ uint8 :8;
uint16 divisor;
- uint16 :16;
+ uint16 :16;
} SCSIUnitsPage;
/*
* Format of START STOP UNIT (0x1b).
*/
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // 0x1b
- uint8 immed:1,
- rsvd:7;
+ uint8 opcode; // 0x1b
+ uint8 immed :1,
+ rsvd :7;
uint8 reserved[2];
- uint8 start:1,
- loej:1, // load/eject
- rsvd1:2,
- power:4;
+ uint8 start :1,
+ loej :1, // load/eject
+ rsvd1 :2,
+ power :4;
uint8 control;
}
#include "vmware_pack_end.h"
/*
* Format of ALLOW PREVENT MEDIUM REMOVAL (0x1e).
*/
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // 0x1e
+ uint8 opcode; // 0x1e
uint8 reserved[3];
uint8 prevent:2,
:6;
* These are defined here because multiple SCSI devices
* need them.
*/
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // 0x25
+ uint8 opcode; // 0x25
uint8 rel :1,
- :4,
- lun :3;
+ :4,
+ lun :3;
#define SCSI_RW10_MAX_LBN 0xffffffffu
uint32 lbn;
uint8 reserved[2];
uint8 pmi :1,
- :7;
+ :7;
uint8 control;
}
#include "vmware_pack_end.h"
uint32 blocksize;
} SCSIReadCapacityResponse;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 opcode; // 0x9e
+ uint8 opcode; // 0x9e
#define SCSI_READ_CAPACITY16_SERVICE_ACTION 0x10
uint8 action:5,
- :3;
+ :3;
uint64 lbn;
uint32 len;
uint8 pmi :1,
- rel :1,
- :6;
+ rel :1,
+ :6;
uint8 control;
}
#include "vmware_pack_end.h"
SCSIReadCapacity16Cmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint64 lbn;
* request. These are defined here because multiple SCSI
* devices need them.
*/
-typedef
-#include "vmware_pack_begin.h"
-struct {
- uint32 opcode:8,
- lun:3,
- lbn:21;
- uint8 length;
- uint8 control;
-}
-#include "vmware_pack_end.h"
-SCSIReadWrite6Cmd;
+typedef SCSICDB6 SCSIReadWrite6Cmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
uint8 rel :1,
- :2,
- flua :1,
- dpo :1,
- lun :3;
+ :2,
+ flua :1,
+ dpo :1,
+ lun :3;
uint32 lbn;
uint8 reserved;
uint16 length;
#include "vmware_pack_end.h"
SCSIReadWrite10Cmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
uint8 rel :1,
- :2,
- flua :1,
- dpo :1,
- lun :3;
+ :2,
+ flua :1,
+ dpo :1,
+ lun :3;
uint32 lbn;
uint32 length;
uint8 reserved;
#include "vmware_pack_end.h"
SCSIReadWrite12Cmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
uint8 rel :1,
- :2,
- flua :1,
- dpo :1,
- :3;
+ :2,
+ flua :1,
+ dpo :1,
+ :3;
uint64 lbn;
uint32 length;
uint8 reserved;
#include "vmware_pack_end.h"
SCSIReadWrite16Cmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
- uint8 xtnt :1, // extent-based reservation
- ptyID :3, // 3rd party reservation ID
- pty :1, // 3rd party reservation
- lun :3; // logical unit number
- uint8 resvID; // SCSI-3: reservation ID
- uint16 resvListLen; // SCSI-3: reservation list length
- uint8 ctrl; // control byte
+ uint8 xtnt :1, // extent-based reservation
+ ptyID :3, // 3rd party reservation ID
+ pty :1, // 3rd party reservation
+ lun :3; // logical unit number
+ uint8 resvID; // SCSI-3: reservation ID
+ uint16 resvListLen; // SCSI-3: reservation list length
+ uint8 control; // control byte
}
#include "vmware_pack_end.h"
SCSIReserveUnitCmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
lun :3; // logical unit number
uint8 resvID; // SCSI-3: reservation ID
uint8 reserved[2];
- uint8 ctrl; // control byte
-}
+ uint8 control; // control byte
+}
#include "vmware_pack_end.h"
SCSIReleaseUnitCmd;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
pf :1, // page format
lun :3; // logical unit number
uint8 reserved;
- uint16 len; // data length
- uint8 ctrl; // control byte
+ uint16 length; // data length
+ uint8 control; // control byte
}
#include "vmware_pack_end.h"
SCSISendDiagnosticCmd;
lun :3; // logical unit number
uint32 lbn; // logical block address
uint8 reserved;
- uint16 len; // verification length
- uint8 ctrl; // control byte
+ uint16 length; // verification length
+ uint8 control; // control byte
}
#include "vmware_pack_end.h"
SCSIVerify10Cmd;
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
- uint8 polled :1, // asynchronous or not
+ uint8 polled :1, // asynchronous or not
:7;
uint8 reserved0[2];
#define SCSI_GESN_CLASS_RSVD0 (1 << 0)
#define SCSI_GESN_CLASS_RSVD1 (1 << 7)
uint8 notifyClassReq; // the class of events we are interested in
uint8 reserved1[2];
- uint16 length; // allocation length
+ uint16 length; // allocation length
uint8 control;
}
#include "vmware_pack_end.h"
SCSIGetEventStatusNotificationCmd;
/*
- * Format of Persistent Reservation Commands per SPC-3 r23, required for
+ * Format of Persistent Reservation Commands per SPC-3 r23, required for
* virtualizing reservations.
*/
READ_FULL_STATUS = 0x3
} SCSIPersistentReserveInServiceAction;
-/*
- * Persistent reservation type codes
+/*
+ * Persistent reservation type codes
*/
typedef enum {
WRITE_EXCL = 0x1,
EXCL_ACCESS_ALL_REG = 0x8
} SCSIPersistentReserveTypeCode;
-typedef
+typedef
#include "vmware_pack_begin.h"
-struct {
- uint8 opcode;
+struct {
+ uint8 opcode;
uint8 serviceAction :5,
reserved :3;
uint8 reserved1[5];
uint16 allocationLength;
uint8 control;
-}
+}
#include "vmware_pack_end.h"
SCSIPersistentReserveInCmd;
} SCSIPersistentReserveOutServiceAction;
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
uint8 opcode;
uint8 type :4,
scope :4;
uint8 reserved1[2];
- uint32 parameterListLength;
+ uint32 parameterListLength;
uint8 control;
-}
+}
#include "vmware_pack_end.h"
SCSIPersistentReserveOutCmd;
* following are true:
* a. the SPEC_I_PT but is set to 0
* b. service action is not REGISTER AND MOVE
- *
+ *
* This is currently the only supported mode in the vmkernel,
* so no additional parameter data is included in this struct
*/
-}
+}
#include "vmware_pack_end.h"
SCSIPersistentReserveOutPList;
uint8 type :4,
scope :4;
uint8 obsolete1[2];
-}
+}
#include "vmware_pack_end.h"
SCSIPRReadReservationResp;
* of sense data at a time; the base SCSI device support invalidates
* this data structure before each SCSI operation as needed.
*/
-typedef
+typedef
#include "vmware_pack_begin.h"
struct {
- uint8 error :7, // 0x70 for current command, 0x71 for earlier command
-#define SCSI_SENSE_ERROR_CURCMD 0x70 // sense data is for "current command"
-#define SCSI_SENSE_ERROR_PREVCMD 0x71 // sense data is for an earlier command
- valid :1; // sense data valid
+ uint8 error :7, // 0x70 for current command, 0x71 for earlier command
+#define SCSI_SENSE_ERROR_CURCMD 0x70 // sense data is for "current command"
+#define SCSI_SENSE_ERROR_PREVCMD 0x71 // sense data is for an earlier command
+ valid :1; // sense data valid
/* NB: Please Note that the valid bit above does NOT tell you whether
* the sense is actually valid and thus the name is really badly chosen
* (even though it is the official name from the SCSI II specification).
* we have seen that many tape drives are capable of returning sense
* without this bit set....
*/
- uint8 segment; // segment number
- uint8 key :4, // sense key
- :1,
- ili :1,
- eom :1,
- filmrk :1;
- uint8 info[4]; // general information
- uint8 optLen; // length of optional data that follows
- uint8 cmdInfo[4]; // command-specific information
- uint8 code; // sense code
- uint8 xcode; // extended sense code
- uint8 fru; //
- uint8 bitpos :3,
- bpv :1,
- :2,
- cd :1, // 1 if error in command, 0 if in data
- sksv :1; // sense key specific data is valid
- uint16 epos; // offset of first byte in error
-
+ uint8 segment; // segment number
+ uint8 key :4, // sense key
+ :1,
+ ili :1,
+ eom :1,
+ filmrk :1;
+ uint8 info[4]; // general information
+ uint8 optLen; // length of optional data that follows
+ uint8 cmdInfo[4]; // command-specific information
+ uint8 code; // sense code
+ uint8 xcode; // extended sense code
+ uint8 fru; //
+ uint8 bitpos :3,
+ bpv :1,
+ :2,
+ cd :1, // 1 if error in command, 0 if in data
+ sksv :1; // sense key specific data is valid
+ uint16 epos; // offset of first byte in error
+
// Some vendors want to return additional data which
// requires a sense buffer of up to 64 bytes.
uint8 additional[46];
SCSIRDSDVDPhysicalInfoLeadin;
+/*
+ * MSF structure for CDs.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 minute;
+ uint8 second;
+ uint8 frame;
+}
+#include "vmware_pack_end.h"
+SCSICDMSF;
+
+
+/*
+ * ReadCD packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 obsolete:1,
+ dap:1,
+ expectedSectorType:3,
+ reserved1:3;
+ uint32 lbn;
+ uint8 length[3];
+ uint8 reserved2:1,
+ c2errors:2,
+ mainChannelSelectionBits:5;
+ uint8 subChannelSelectionBits:3,
+ reserved3:5;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadCDCmd;
+
+
+/*
+ * ReadCDMSF packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 obsolete:1,
+ dap:1,
+ expectedSectorType:3,
+ reserved1:3;
+ uint8 reserved;
+ SCSICDMSF start;
+ SCSICDMSF end;
+ uint8 reserved2:1,
+ c2errors:2,
+ mainChannelSelectionBits:5;
+ uint8 subChannelSelectionBits:3,
+ reserved3:5;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadCDMSFCmd;
+
+
+/*
+ * ReadTOC packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 reserved1:1,
+ msf:1,
+ reserved2:6;
+ uint8 format:3, /* MMC says 4 bits for eons. Original ATAPI is only 3 bits. */
+ reserved3:5;
+ uint8 reserved4[3];
+ uint8 trackNumber;
+ uint16 allocationLength;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadTOCCmd;
+
+
+/*
+ * ReadSubChannel packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 reserved1:1,
+ msf:1,
+ reserved2:6;
+ uint8 reserved3:6,
+ subq:1,
+ reserved4:1;
+ uint8 format;
+ uint8 reserved5[2];
+ uint8 trackNumber;
+ uint16 allocationLength;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadSubChannelCmd;
+
+
+/*
+ * PlayMSF packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 reserved[2];
+ SCSICDMSF start;
+ SCSICDMSF end;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIPlayMSFCmd;
+
+
/*
* Host and device status definitions.
*
SDSTAT_CHECK = 0x02, // check condition
SDSTAT_CONDITION_MET = 0x04, // condition met
SDSTAT_BUSY = 0x08, // device busy
- SDSTAT_INTERMEDIATE = 0x10,
+ SDSTAT_INTERMEDIATE = 0x10,
SDSTAT_INTERMEDIATE_CONDITION = 0x14,
SDSTAT_RESERVATION_CONFLICT = 0x18, // device reserved by another host
SDSTAT_COMMAND_TERMINATED = 0x22,
- SDSTAT_TASK_SET_FULL = 0x28,
- SDSTAT_ACA_ACTIVE = 0x30,
- SDSTAT_TASK_ABORTED = 0x40,
+ SDSTAT_TASK_SET_FULL = 0x28,
+ SDSTAT_ACA_ACTIVE = 0x30,
+ SDSTAT_TASK_ABORTED = 0x40,
} SCSIDeviceStatus;
typedef enum {
/*
*---------------------------------------------------------------------------
- *
+ *
* SCSICdb_IsRead --
*
* This function returns TRUE if the scsi command passed as an argument is
static INLINE Bool
SCSICdb_IsRead(uint8 cdb0) // IN
{
- return cdb0 == SCSI_CMD_READ6
+ return cdb0 == SCSI_CMD_READ6
|| cdb0 == SCSI_CMD_READ10
|| cdb0 == SCSI_CMD_READ12
|| cdb0 == SCSI_CMD_READ16;
/*
*---------------------------------------------------------------------------
- *
+ *
* SCSICdb_IsWrite --
*
* This function returns TRUE if the scsi command passed as an argument is
static INLINE Bool
SCSICdb_IsWrite(uint8 cdb0) // IN
{
- return cdb0 == SCSI_CMD_WRITE6
+ return cdb0 == SCSI_CMD_WRITE6
|| cdb0 == SCSI_CMD_WRITE10
|| cdb0 == SCSI_CMD_WRITE12
|| cdb0 == SCSI_CMD_WRITE16;
}
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSICdb_GetCDBLength --
+ *
+ * This function returns length of specified command. Multibyte
+ * CDB (0x7F) is reported as reserved command.
+ *
+ * Results:
+ * 6 for commands 00-1F
+ * 10 for commands 20-5F
+ * 16 for commands 80-9F
+ * 12 for commands A0-BF
+ * SCSI_GRP_RESERVED for commands 60-7F
+ * SCSI_GRP_VENDOR for commands C0-FF
+ * Both SCSI_GRP_RESERVED & SCSI_GRP_VENDOR are guarateed to have
+ * bigger value than 16.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#define SCSI_GRP_RESERVED 64
+#define SCSI_GRP_VENDOR 65
+
+static INLINE size_t
+SCSICdb_GetCDBLength(uint8 cdb0) // IN
+{
+ static const unsigned char lengths[] = {
+ 6, /* 00 - 1F */
+ 10, /* 20 - 3F */
+ 10, /* 40 - 5F */
+ SCSI_GRP_RESERVED, /* 60 - 7F */
+ 16, /* 80 - 9F */
+ 12, /* A0 - BF */
+ SCSI_GRP_VENDOR, /* C0 - DF */
+ SCSI_GRP_VENDOR, /* E0 - FF */
+ };
+
+ return lengths[cdb0 >> 5];
+}
+
+
/*
*---------------------------------------------------------------------------
*
*
* SCSI3InquiryLen --
*
- * Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd
+ * Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd
*
* Results:
* 16-bit allocation length.
*/
static INLINE uint16
-SCSI3InquiryLen(SCSI3InquiryCmd *inqCmd) // IN
+SCSI3InquiryLen(const SCSI3InquiryCmd *inqCmd) // IN
{
- return (inqCmd->lenMSB << 8) + inqCmd->len;
+ return (inqCmd->lengthMSB << 8) + inqCmd->length;
}
-typedef
+typedef
#include "vmware_pack_begin.h"
struct SCSICmdInfo {
uint8 code;
uint8 xferType;
- char *name;
+ const char *name;
uint8 emulation;
}
#include "vmware_pack_end.h"
#define SCSI_CMD_INFO_DATA \
{SCSI_CMD_TEST_UNIT_READY, SCSI_XFER_NONE, "TEST UNIT READY", SCSI_EMULATE}, \
{SCSI_CMD_REZERO_UNIT, SCSI_XFER_NONE, "REWIND/REZERO UNIT", SCSI_DONT_EMULATE}, \
- {0x02, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_REQUEST_SENSE, SCSI_XFER_TOHOST, "REQUEST SENSE", SCSI_EMULATE}, \
- {SCSI_CMD_FORMAT_UNIT, SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE}, \
- {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST, "READ BLOCK LIMITS", SCSI_DONT_EMULATE},\
- {0x06, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ6, SCSI_XFER_TOHOST, "READ(6)", SCSI_EMULATE}, \
- {0x09, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE6, SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE}, \
- {SCSI_CMD_SLEW_AND_PRINT, SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE}, \
- {0x0c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x0d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x0e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_REVERSE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SYNC_BUFFER, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SPACE, SCSI_XFER_NONE, "SPACE", SCSI_DONT_EMULATE}, \
+ {0x02, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REQUEST_SENSE, SCSI_XFER_TOHOST, "REQUEST SENSE", SCSI_EMULATE}, \
+ {SCSI_CMD_FORMAT_UNIT, SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE}, \
+ {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST, "READ BLOCK LIMITS", SCSI_DONT_EMULATE}, \
+ {0x06, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ6, SCSI_XFER_TOHOST, "READ(6)", SCSI_EMULATE}, \
+ {0x09, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE6, SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_SLEW_AND_PRINT, SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE}, \
+ {0x0c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x0d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x0e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_REVERSE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SYNC_BUFFER, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SPACE, SCSI_XFER_NONE, "SPACE", SCSI_DONT_EMULATE}, \
{SCSI_CMD_INQUIRY, SCSI_XFER_TOHOST, "INQUIRY", SCSI_EMULATE}, \
- {0x13, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_MODE_SELECT, SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_RESERVE_UNIT, SCSI_XFER_NONE, "RESERVE(6)", SCSI_EMULATE}, \
- {SCSI_CMD_RELEASE_UNIT, SCSI_XFER_NONE, "RELEASE(6)", SCSI_EMULATE}, \
- {SCSI_CMD_COPY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_ERASE, SCSI_XFER_NONE, "ERASE", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_MODE_SENSE, SCSI_XFER_TOHOST, "MODE SENSE(6)", SCSI_EMULATE}, \
- {SCSI_CMD_SCAN, SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE}, \
+ {0x13, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SELECT, SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RESERVE_UNIT, SCSI_XFER_NONE, "RESERVE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_RELEASE_UNIT, SCSI_XFER_NONE, "RELEASE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_COPY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_ERASE, SCSI_XFER_NONE, "ERASE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SENSE, SCSI_XFER_TOHOST, "MODE SENSE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_SCAN, SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE}, \
{SCSI_CMD_RECV_DIAGNOSTIC, SCSI_XFER_AUTO, "RECEIVE DIAGNOSTIC RESULTS", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEND_DIAGNOSTIC, SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_DIAGNOSTIC, SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE}, \
{SCSI_CMD_MEDIUM_REMOVAL, SCSI_XFER_NONE, "LOCK/UNLOCK DOOR", SCSI_DONT_EMULATE_DONT_LOG}, \
- {0x1f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x20, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x21, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x22, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x1f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x20, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x21, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x22, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
{SCSI_CMD_READ_FORMAT_CAPACITIES, SCSI_XFER_TOHOST, "READ FORMAT CAPACITIES", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SET_WINDOW, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_CAPACITY, SCSI_XFER_TOHOST, "READ CAPACITY", SCSI_EMULATE}, \
- {0x26, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x27, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ10, SCSI_XFER_TOHOST, "READ(10)", SCSI_EMULATE}, \
- {SCSI_CMD_READ_GENERATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE10, SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \
- {SCSI_CMD_SEEK10, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \
- {0x2c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE_VERIFY, SCSI_XFER_AUTO, "WRITE VERIFY", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_VERIFY, SCSI_XFER_NONE, "VERIFY", SCSI_EMULATE}, \
- {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO, "SEARCH HIGH", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO, "SEARCH EQUAL", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEARCH_DATA_LOW, SCSI_XFER_AUTO, "SEARCH LOW", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SET_LIMITS, SCSI_XFER_AUTO, "SET LIMITS", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_POSITION, SCSI_XFER_TOHOST, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SYNC_CACHE, SCSI_XFER_NONE, "SYNC CACHE", SCSI_EMULATE}, \
- {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO, "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE},\
+ {SCSI_CMD_SET_WINDOW, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CAPACITY, SCSI_XFER_TOHOST, "READ CAPACITY", SCSI_EMULATE}, \
+ {0x26, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x27, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ10, SCSI_XFER_TOHOST, "READ(10)", SCSI_EMULATE}, \
+ {SCSI_CMD_READ_GENERATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE10, SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \
+ {SCSI_CMD_SEEK10, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \
+ {0x2c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_VERIFY, SCSI_XFER_AUTO, "WRITE VERIFY", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_VERIFY, SCSI_XFER_NONE, "VERIFY", SCSI_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO, "SEARCH HIGH", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO, "SEARCH EQUAL", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_LOW, SCSI_XFER_AUTO, "SEARCH LOW", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_LIMITS, SCSI_XFER_AUTO, "SET LIMITS", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_POSITION, SCSI_XFER_TOHOST, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SYNC_CACHE, SCSI_XFER_NONE, "SYNC CACHE", SCSI_EMULATE}, \
+ {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO, "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE}, \
{SCSI_CMD_READ_DEFECT_DATA, SCSI_XFER_AUTO, "READ DEFECT DATA", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_MEDIUM_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_COMPARE, SCSI_XFER_AUTO, "COMPARE", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_COPY_VERIFY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE_BUFFER, SCSI_XFER_AUTO, "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
- {SCSI_CMD_READ_BUFFER, SCSI_XFER_AUTO, "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
- {SCSI_CMD_UPDATE_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_LONG, SCSI_XFER_AUTO, "READ LONG", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE_LONG, SCSI_XFER_AUTO, "WRITE LONG", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_CHANGE_DEF, SCSI_XFER_NONE, "CHANGE DEFINITION", SCSI_DONT_EMULATE},\
- {SCSI_CMD_WRITE_SAME, SCSI_XFER_AUTO, "WRITE SAME", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_SUBCHANNEL, SCSI_XFER_TOHOST, "READ SUBCHANNEL", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_TOC, SCSI_XFER_TOHOST, "READ TOC", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_HEADER, SCSI_XFER_TOHOST, "READ HEADER", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_PLAY_AUDIO10, SCSI_XFER_NONE, "PLAY AUDIO(10)", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_PLAY_AUDIO_MSF, SCSI_XFER_NONE, "PLAY AUDIO MSF", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MEDIUM_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_COMPARE, SCSI_XFER_AUTO, "COMPARE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_COPY_VERIFY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_BUFFER, SCSI_XFER_AUTO, "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
+ {SCSI_CMD_READ_BUFFER, SCSI_XFER_AUTO, "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
+ {SCSI_CMD_UPDATE_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_LONG, SCSI_XFER_AUTO, "READ LONG", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_LONG, SCSI_XFER_AUTO, "WRITE LONG", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_CHANGE_DEF, SCSI_XFER_NONE, "CHANGE DEFINITION", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_SAME, SCSI_XFER_AUTO, "WRITE SAME", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_SUBCHANNEL, SCSI_XFER_TOHOST, "READ SUBCHANNEL", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_TOC, SCSI_XFER_TOHOST, "READ TOC", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_HEADER, SCSI_XFER_TOHOST, "READ HEADER", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO10, SCSI_XFER_NONE, "PLAY AUDIO(10)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO_MSF, SCSI_XFER_NONE, "PLAY AUDIO MSF", SCSI_DONT_EMULATE}, \
{SCSI_CMD_PLAY_AUDIO_TRACK, SCSI_XFER_AUTO, "PLAY AUDIO TRACK", SCSI_DONT_EMULATE}, \
{SCSI_CMD_PLAY_AUDIO_RELATIVE, SCSI_XFER_AUTO, "PLAY AUDIO RELATIVE", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_PAUSE, SCSI_XFER_NONE, "PAUSE/RESUME", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_LOG_SELECT, SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_LOG_SENSE, SCSI_XFER_TOHOST, "LOG SENSE", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_STOP_PLAY, SCSI_XFER_NONE, "STOP PLAY", SCSI_DONT_EMULATE}, \
- {0x4f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x50, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_DISC_INFO, SCSI_XFER_TOHOST, "CDR INFO", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_TRACK_INFO, SCSI_XFER_TOHOST, "TRACK INFO", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_RESERVE_TRACK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x54, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_MODE_SELECT10, SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_RESERVE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_RELEASE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x58, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x59, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_MODE_SENSE10, SCSI_XFER_TOHOST, "MODE SENSE(10)", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_CLOSE_SESSION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEND_CUE_SHEET, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PAUSE, SCSI_XFER_NONE, "PAUSE/RESUME", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_LOG_SELECT, SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_LOG_SENSE, SCSI_XFER_TOHOST, "LOG SENSE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_STOP_PLAY, SCSI_XFER_NONE, "STOP PLAY", SCSI_DONT_EMULATE}, \
+ {0x4f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x50, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_DISC_INFO, SCSI_XFER_TOHOST, "CDR INFO", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_TRACK_INFO, SCSI_XFER_TOHOST, "TRACK INFO", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RESERVE_TRACK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x54, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SELECT10, SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RESERVE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RELEASE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x58, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x59, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SENSE10, SCSI_XFER_TOHOST, "MODE SENSE(10)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_CLOSE_SESSION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_CUE_SHEET, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
{SCSI_CMD_PERSISTENT_RESERVE_IN, SCSI_XFER_TOHOST, "PERSISTENT RESERVE IN", SCSI_EMULATE}, \
- {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE, "PERSISTENT RESERVE OUT", SCSI_EMULATE}, \
- {0x60, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x61, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x62, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x63, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x64, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x65, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x66, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x67, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x68, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x69, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x6a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x6b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x6c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x6d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x6e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x6f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x70, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x71, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x72, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x73, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x74, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x75, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x76, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x77, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x78, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x79, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x7a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x7b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x7c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x7d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x7e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x7f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x80, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x81, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x82, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x83, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x84, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x85, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x86, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x87, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ16, SCSI_XFER_TOHOST, "READ(16)", SCSI_EMULATE}, \
- {0x89, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE16, SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE}, \
- {0x8b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x8c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x8d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x8e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_VERIFY16, SCSI_XFER_NONE, "VERIFY(16)", SCSI_EMULATE}, \
- {0x90, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x91, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x92, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x93, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x94, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x95, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x96, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x97, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x98, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x99, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x9a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x9b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x9c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0x9d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_CAPACITY16, SCSI_XFER_TOHOST, "READ CAPACITY 16", SCSI_EMULATE}, \
- {0x9f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_REPORT_LUNS, SCSI_XFER_AUTO, "REPORT LUNS", SCSI_EMULATE},\
- {SCSI_CMD_BLANK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xa2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEND_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_REPORT_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_PLAY_AUDIO12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_LOADCD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xa7, SCSI_XFER_AUTO, "MOVE MEDIUM", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xab, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_ERASE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_WRITE_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SET_LIMITS12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE, "PERSISTENT RESERVE OUT", SCSI_EMULATE}, \
+ {0x60, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x61, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x62, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x63, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x64, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x65, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x66, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x67, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x68, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x69, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x70, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x71, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x72, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x73, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x74, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x75, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x76, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x77, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x78, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x79, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x80, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x81, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x82, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x83, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x84, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x85, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x86, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x87, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ16, SCSI_XFER_TOHOST, "READ(16)", SCSI_EMULATE}, \
+ {0x89, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE16, SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE}, \
+ {0x8b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x8c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x8d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x8e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_VERIFY16, SCSI_XFER_NONE, "VERIFY(16)", SCSI_EMULATE}, \
+ {0x90, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x91, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x92, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x93, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x94, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x95, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x96, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x97, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x98, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x99, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CAPACITY16, SCSI_XFER_TOHOST, "READ CAPACITY 16", SCSI_EMULATE}, \
+ {0x9f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REPORT_LUNS, SCSI_XFER_AUTO, "REPORT LUNS", SCSI_EMULATE}, \
+ {SCSI_CMD_BLANK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xa2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REPORT_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_LOADCD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xa7, SCSI_XFER_AUTO, "MOVE MEDIUM", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xab, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_ERASE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_LIMITS12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
{0xb4, SCSI_XFER_AUTO, "READ ELEMENT STATUS", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SET_STREAMING, SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_CD_MSF, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_AUDIO_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SET_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {SCSI_CMD_PLAY_CD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_STREAMING, SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CD_MSF, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_AUDIO_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_CD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
{SCSI_CMD_MECH_STATUS, SCSI_XFER_TOHOST, "MECHANISM STATUS", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_READ_CD, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \
- {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xc9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xca, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xcb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xcc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xcd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xce, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xcf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xd9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xda, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xdb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xdc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xdd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xde, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xdf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xe9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xea, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xeb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xec, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xed, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xee, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xef, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xf9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xfa, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xfb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xfc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xfd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xfe, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
- {0xff, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE},
+ {SCSI_CMD_READ_CD, SCSI_XFER_TOHOST, "READ CD", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xca, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xce, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xda, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xde, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xea, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xeb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xec, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xed, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xee, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xef, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfa, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfe, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xff, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE},
#endif
# include <linux/bios32.h>
#endif
+#if KERNEL_VERSION(2, 6, 6) <= LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+# ifndef DMA_BIT_MASK
+# define DMA_BIT_MASK(n) DMA_##n##BIT_MASK
+# endif
+#endif
+
/* 2.0.x has useless struct pci_dev; remap it to our own */
#ifndef KERNEL_2_1
#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_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb))
-#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb)
+#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb)
+#define compat_skb_reset_network_header(skb) skb_reset_network_header(skb)
+#define compat_skb_reset_transport_header(skb) skb_reset_transport_header(skb)
#define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off)
#define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off)
#else
#define compat_skb_ip_header(skb) (skb)->nh.iph
#define compat_skb_tcp_header(skb) (skb)->h.th
#define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data)
+#define compat_skb_reset_network_header(skb) ((skb)->nh.raw = (skb)->data)
+#define compat_skb_reset_transport_header(skb) ((skb)->h.raw = (skb)->data)
#define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off))
#define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off))
#endif
* Struct size is 16 bytes. All fields in struct are aligned to their natural
* alignment.
*/
-typedef struct VMCIResourcesQueuryHdr {
+typedef struct VMCIResourcesQueryHdr {
VMCIDatagram hdr;
uint32 numResources;
uint32 _padding;
VMCIOBJ_CONTEXT,
VMCIOBJ_PROCESS,
VMCIOBJ_DATAGRAM_PROCESS,
+ VMCIOBJ_SOCKET,
VMCIOBJ_NOT_SET,
} VMCIObjType;
* or opening the device in kernel-mode, and are always in UNICODE.
*/
#define VMCI_DEVICE_NAME TEXT("\\\\.\\VMCI")
+#define VMCI_DEVICE_NAME_NT L"\\??\\VMCI"
#define VMCI_DEVICE_NAME_PATH L"\\Device\\vmci"
#define VMCI_DEVICE_LINK_PATH L"\\DosDevices\\vmci"
VMCIIOCTL_BUFFERED(SOCKETS_IOCTL)
#define IOCTL_VMCI_SOCKETS_LISTEN \
VMCIIOCTL_BUFFERED(SOCKETS_LISTEN)
-#define IOCTL_VMCI_SOCKETS_RECV \
- VMCIIOCTL_BUFFERED(SOCKETS_RECV)
#define IOCTL_VMCI_SOCKETS_RECV_FROM \
VMCIIOCTL_BUFFERED(SOCKETS_RECV_FROM)
#define IOCTL_VMCI_SOCKETS_SELECT \
VMCIIOCTL_BUFFERED(SOCKETS_SELECT)
-#define IOCTL_VMCI_SOCKETS_SEND \
- VMCIIOCTL_BUFFERED(SOCKETS_SEND)
#define IOCTL_VMCI_SOCKETS_SEND_TO \
VMCIIOCTL_BUFFERED(SOCKETS_SEND_TO)
#define IOCTL_VMCI_SOCKETS_SET_SOCK_OPT \
VMCIIOCTL_BUFFERED(SOCKETS_SET_SOCK_OPT)
#define IOCTL_VMCI_SOCKETS_SHUTDOWN \
VMCIIOCTL_BUFFERED(SOCKETS_SHUTDOWN)
-#define IOCTL_VMCI_SOCKETS_SOCKET \
- VMCIIOCTL_BUFFERED(SOCKETS_SOCKET)
/* END VMCI SOCKETS */
+
+/*
+ * For accessing VMCIOBJ_SOCKET in IOCTLs. Both functions take a file object's
+ * fs context and get or set the socket.
+ */
+PVOID VMCIFsContext_GetSocket(PVOID fsContext);
+void VMCIFsContext_SetSocket(PVOID fsContext, PVOID socket);
+
#endif // _WIN32
} VMCIQueue;
# endif
#else
+ /*
+ * VMCIQueuePair_QueueIsMapped()
+ *
+ * This macro will return TRUE if a queue created by either the
+ * guest or host has had the memory for the queue pair mapped by the
+ * VMX and made avaiable to the host by way of the SetPageFile
+ * ioctls.
+ *
+ * After SetPageFile, the queue memory will remain available to the
+ * host until the host detaches. On Linux and Mac OS platforms the
+ * memory for the queue pair remains available to the host driver
+ * after the VMX process for the guest goes away. On Windows, the
+ * memory is copied (under the protection of a mutex) so that the
+ * host can continue to operate on the queues after the VMX is gone.
+ *
+ * The version of the VMCIQueue data structure which is provided by
+ * the VMCI kernel module is protected by the VMCI
+ * QueuePairList_Lock and the VMCI QueuePairList_FindEntry()
+ * function. Therefore, host-side clients shouldn't be able to
+ * access the structure after it's gone. And, the memory the
+ * queueHeaderPtr points to is torn down (and freed) after the entry
+ * has been removed from the QueuePairList and just before the entry
+ * itself is deallocated.
+ */
+
+# define VMCIQueuePair_QueueIsMapped(q) ((q)->queueHeaderPtr != NULL)
+
# if defined(__linux__) && defined(__KERNEL__)
/*
* Linux Kernel Host
VMCIQueueHeader *queueHeaderPtr;
struct page **page;
} VMCIQueue;
-# define VMCIQueuePair_QueueIsMapped(q) ((q)->page != NULL)
# elif defined __APPLE__
/*
* Mac OS Host
IOMemoryDescriptor *pages;
IOMemoryMap *header;
} VMCIQueue;
-# define VMCIQueuePair_QueueIsMapped(q) ((q)->pages)
# else
/*
* Windows Host
FAST_MUTEX __mutex; /* Don't touch except to init */
} VMCIQueue;
#define VMCIQueuePair_EnqueueToDevNull(q) ((q)->enqueueToDevNull)
-#define VMCIQueuePair_QueueIsMapped(q) ((q)->buffer != NULL)
# endif
#endif
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
-#include "compat_uaccess.h"
-#include "compat_fs.h"
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
#include "vmblockInt.h"
#include "block.h"
* side-stepping the syscall auditing and doing the copy from user space
* ourself. Change this back once we GPL the module.
*/
- filename = compat___getname();
+ filename = __getname();
if (!filename) {
Warning("ControlFileOpWrite: Could not obtain memory for filename.\n");
return -ENOMEM;
}
/*
- * XXX: compat___getname() returns a pointer to a PATH_MAX-sized buffer.
+ * XXX: __getname() returns a pointer to a PATH_MAX-sized buffer.
* Hard-coding this size is also gross, but it's our only option here and
* InodeOpLookup() already set a bad example by doing this.
*/
}
exit:
- compat___putname(filename);
+ __putname(filename);
return ret;
}
*/
#include "driver-config.h"
-#include "compat_fs.h"
-#include "compat_namei.h"
+#include <linux/fs.h>
+#include "compat_namei.h"
#include "vmblockInt.h"
#include "filesystem.h"
#include "block.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
static int DentryOpRevalidate(struct dentry *dentry, struct nameidata *nd);
-#else
-static int DentryOpRevalidate(struct dentry *dentry, int flags);
-#endif
struct dentry_operations LinkDentryOps = {
.d_revalidate = DentryOpRevalidate,
*----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
static int
DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating
struct nameidata *nd) // IN: lookup flags & intent
-#else
-static int
-DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating
- int flags) // IN: lookup flags (e.g., LOOKUP_CONTINUE)
-#endif
{
VMBlockInodeInfo *iinfo;
struct nameidata actualNd;
if (actualDentry &&
actualDentry->d_op &&
actualDentry->d_op->d_revalidate) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
return actualDentry->d_op->d_revalidate(actualDentry, nd);
-#else
- return actualDentry->d_op->d_revalidate(actualDentry, flags);
-#endif
}
- if (compat_path_lookup(iinfo->name, 0, &actualNd)) {
+ if (path_lookup(iinfo->name, 0, &actualNd)) {
LOG(4, "DentryOpRevalidate: [%s] no longer exists\n", iinfo->name);
return 0;
}
#include "driver-config.h"
#include <linux/module.h>
-#include "compat_fs.h"
-#include "compat_sched.h"
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/pagemap.h>
#include "vmblockInt.h"
#include "filesystem.h"
*/
#include "driver-config.h"
-#include "compat_kernel.h"
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/mount.h>
-#include "compat_fs.h"
-#include "compat_spinlock.h"
+#include <linux/fs.h>
+
#include "compat_namei.h"
-#include "compat_slab.h"
#include "os.h"
#include "vmblockInt.h"
#define VMBLOCK_ROOT_INO 1
#define GetRootInode(sb) Iget(sb, NULL, NULL, VMBLOCK_ROOT_INO)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 25)
-# define KERNEL_25_FS 0
-#else
-# define KERNEL_25_FS 1
-#endif
-
static struct inode *GetInode(struct super_block *sb, ino_t ino);
/* File system operations */
-#if KERNEL_25_FS /* { */
-# if defined(VMW_GETSB_2618)
+
+#if defined(VMW_GETSB_2618)
static int FsOpGetSb(struct file_system_type *fsType, int flags,
const char *devName, void *rawData, struct vfsmount *mnt);
-# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)
+#else
static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags,
const char *devName, void *rawData);
-# else
-static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags,
- char *devName, void *rawData);
-# endif
-#else /* } { */
-static struct super_block *FsOpReadSuper24(struct super_block *sb, void *rawData,
- int flags);
-#endif /* } */
+#endif
static int FsOpReadSuper(struct super_block *sb, void *rawData, int flags);
static struct file_system_type fsType = {
.owner = THIS_MODULE,
.name = VMBLOCK_FS_NAME,
-#if KERNEL_25_FS
.get_sb = FsOpGetSb,
.kill_sb = kill_anon_super,
-#else
- .read_super = FsOpReadSuper24,
-#endif
};
ino_t
GetNextIno(void)
{
- static spinlock_t inoLock = SPIN_LOCK_UNLOCKED;
- static ino_t nextIno = VMBLOCK_ROOT_INO + 1;
- ino_t ret;
+ static atomic_t nextIno = ATOMIC_INIT(VMBLOCK_ROOT_INO + 1);
- /* Too bad atomic_t's don't provide an atomic increment and read ... */
- spin_lock(&inoLock);
- ret = nextIno++;
- spin_unlock(&inoLock);
-
- return ret;
+ return (ino_t) atomic_inc_return(&nextIno);
}
GetInode(struct super_block *sb, // IN: file system superblock object
ino_t ino) // IN: inode number to assign to new inode
{
-#ifdef VMW_USE_IGET_LOCKED
struct inode *inode;
inode = iget_locked(sb, ino);
unlock_new_inode(inode);
}
return inode;
-#else
- return iget(sb, ino);
-#endif
}
static void
InodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem)) // IN: allocated slab item to initialize
{
-#ifdef VMW_EMBED_INODE
VMBlockInodeInfo *iinfo = slabElem;
inode_init_once(&iinfo->inode);
-#endif
}
bufOut[fsRootLen] = '\0';
} else {
VMBlockInodeInfo *dirIinfo;
+ int ret;
ASSERT(dir);
ASSERT(dentry);
}
dirIinfo = INODE_TO_IINFO(dir);
+
/*
* If dirIinfo->name[1] is '\0', then it is "/" and we don't need
* another '/' between it and the additional name.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 10)
- {
- int ret;
-
- ret = snprintf(bufOut, bufOutSize,
- dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s",
- dirIinfo->name, dentry->d_name.name);
- if (ret >= bufOutSize) {
- Warning("MakeFullName: path was too long.\n");
- return -ENAMETOOLONG;
- }
- }
-#else
- {
- /* snprintf was not exported prior to 2.4.10 */
- size_t dirLen;
- size_t pathSepLen;
- size_t dentryLen;
- size_t pathLen;
-
- dirLen = strlen(dirIinfo->name);
- pathSepLen = dirLen == 1 ? 0 : 1;
- dentryLen = strlen(dentry->d_name.name);
- pathLen = dirLen + dentryLen + pathSepLen;
- if (pathLen >= bufOutSize) {
- Warning("MakeFullName: path was too long.\n");
- return -ENAMETOOLONG;
- }
- memcpy(bufOut, dirIinfo->name, dirLen);
- if (pathSepLen == 1) {
- ASSERT(dirLen == 1);
- bufOut[dirLen] = '/';
- }
- memcpy(bufOut + dirLen + pathSepLen, dentry->d_name.name, dentryLen);
- bufOut[pathLen] = '\0';
+ ret = snprintf(bufOut, bufOutSize,
+ dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s",
+ dirIinfo->name, dentry->d_name.name);
+ if (ret >= bufOutSize) {
+ Warning("MakeFullName: path was too long.\n");
+ return -ENAMETOOLONG;
}
-#endif
}
return 0;
}
-#if KERNEL_25_FS /* { */
#if defined(VMW_GETSB_2618)
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)
static struct super_block *
FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount
int flags, // IN: mount flags
const char *dev_name, // IN: device mounting on
void *rawData) // IN: mount arguments
-#else
-static struct super_block *
-FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount
- int flags, // IN: mount flags
- char *dev_name, // IN: device mounting on
- void *rawData) // IN: mount arguments
-#endif
{
return get_sb_nodev(fs_type, flags, rawData, FsOpReadSuper);
}
#endif
-#else /* } { */
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FsOpReadSuper24 --
- *
- * Compatibility wrapper for 2.4.x kernels read_super.
- * Converts success to sb, and failure to NULL.
- *
- * Results:
- * The initialized superblock on success
- * NULL on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-static struct super_block *
-FsOpReadSuper24(struct super_block *sb, // OUT: Superblock object
- void *rawData, // IN : mount arguments
- int flags) // IN : mount flags
-{
- return FsOpReadSuper(sb, rawData, flags) ? NULL : sb;
-}
-#endif /* } */
#define __FILESYSTEM_H__
#include "compat_slab.h"
-#include "compat_fs.h"
+#include <linux/fs.h>
#include "vm_basic_types.h"
-#ifndef container_of
-#define container_of(ptr, type, memb) ((type *)((char *)(ptr) - offsetof(type, memb)))
-#endif
-
-#ifdef VMW_EMBED_INODE
-# define INODE_SET_IINFO(inode, iinfo)
-# define INODE_TO_IINFO(_inode) container_of(_inode, VMBlockInodeInfo, inode)
-#else
-# define INODE_SET_IINFO(inode, iinfo) (inode)->u.generic_ip = iinfo
-# define INODE_TO_IINFO(_inode) \
- ({ \
- /* Allocate an inode info for new inodes */ \
- if ((_inode)->u.generic_ip == NULL) { \
- VMBlockInodeInfo *_iinfo; \
- ASSERT(VMBlockInodeCache); \
- _iinfo = kmem_cache_alloc(VMBlockInodeCache, SLAB_KERNEL); \
- /* We must set the inode info for new inodes */ \
- INODE_SET_IINFO(_inode, _iinfo); \
- } \
- ((VMBlockInodeInfo *)((_inode)->u.generic_ip)); \
- })
-#endif
-
+#define INODE_TO_IINFO(_inode) container_of(_inode, VMBlockInodeInfo, inode)
#define INODE_TO_ACTUALDENTRY(inode) INODE_TO_IINFO(inode)->actualDentry
#define INODE_TO_ACTUALINODE(inode) INODE_TO_IINFO(inode)->actualDentry->d_inode
char name[PATH_MAX];
size_t nameLen;
struct dentry *actualDentry;
-#ifdef VMW_EMBED_INODE
/* Embedded inode */
struct inode inode;
-#endif
} VMBlockInodeInfo;
#include "driver-config.h"
#include <linux/module.h>
-#include "compat_fs.h"
+#include <linux/fs.h>
#include <linux/time.h>
-#include "compat_namei.h"
-#include "compat_uaccess.h"
-#include "compat_sched.h"
+#include <linux/namei.h>
#include "vmblockInt.h"
#include "filesystem.h"
/* Inode operations */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
static struct dentry *InodeOpLookup(struct inode *dir,
struct dentry *dentry, struct nameidata *nd);
-#else
-static struct dentry *InodeOpLookup(struct inode *dir, struct dentry *dentry);
-#endif
static int InodeOpReadlink(struct dentry *dentry, char __user *buffer, int buflen);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
static void *InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd);
*----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
static struct dentry *
InodeOpLookup(struct inode *dir, // IN: parent directory's inode
struct dentry *dentry, // IN: dentry to lookup
struct nameidata *nd) // IN: lookup intent and information
-#else
-static struct dentry *
-InodeOpLookup(struct inode *dir, // IN: parent directory's inode
- struct dentry *dentry) // IN: dentry to lookup
-#endif
{
char *filename;
struct inode *inode;
}
/* Get a slab from the kernel's names_cache of PATH_MAX-sized buffers. */
- filename = compat___getname();
+ filename = __getname();
if (!filename) {
Warning("InodeOpLookup: unable to obtain memory for filename.\n");
return ERR_PTR(-ENOMEM);
ret = MakeFullName(dir, dentry, filename, PATH_MAX);
if (ret < 0) {
Warning("InodeOpLookup: could not construct full name\n");
- compat___putname(filename);
+ __putname(filename);
return ERR_PTR(ret);
}
/* Block if there is a pending block on this file */
BlockWaitOnFile(filename, NULL);
- compat___putname(filename);
+ __putname(filename);
inode = Iget(dir->i_sb, dir, dentry, GetNextIno());
if (!inode) {
*/
#include "driver-config.h"
-#include "compat_init.h"
-#include "compat_kernel.h"
-#include "compat_module.h"
+#include <linux/init.h>
+#include <linux/module.h>
#include <linux/limits.h>
#include <linux/errno.h>
-#include "compat_string.h"
#include "vmblockInt.h"
#include "vmblock_version.h"
/* Module parameters */
#ifdef VMX86_DEVEL /* { */
int LOGLEVEL_THRESHOLD = 4;
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
- module_param(LOGLEVEL_THRESHOLD, int, 0600);
-# else
- MODULE_PARM(LOGLEVEL_THRESHOLD, "i");
-# endif
+module_param(LOGLEVEL_THRESHOLD, int, 0600);
MODULE_PARM_DESC(LOGLEVEL_THRESHOLD, "Logging level (0 means no log, "
"10 means very verbose, 4 is default)");
#endif /* } */
static char *root = "/tmp/VMwareDnD";
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
module_param(root, charp, 0600);
-#else
-MODULE_PARM(root, "s");
-#endif
MODULE_PARM_DESC(root, "The directory the file system redirects to.");
/* Module information */
*/
MODULE_INFO(supported, "external");
-/* Functions */
-static int VMBlockInit(void);
-static void VMBlockExit(void);
-
-/* Define init/exit routines */
-module_init(VMBlockInit);
-module_exit(VMBlockExit);
-
-
/*
*----------------------------------------------------------------------------
*
return ret;
}
+module_init(VMBlockInit);
+
/*
*----------------------------------------------------------------------------
LOG(4, "module unloaded\n");
}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70)
-/*
- *----------------------------------------------------------------------------
- *
- * strlcpy --
- *
- * 2.4 doesn't have strlcpy().
- *
- * Copies at most count - 1 bytes from src to dest, and ensures dest is NUL
- * terminated.
- *
- * Results:
- * Length of src. If src >= count, src was truncated in copy.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-size_t
-strlcpy(char *dest, // OUT: destination to copy string to
- const char *src, // IN : source to copy string from
- size_t count) // IN : size of destination buffer
-{
- size_t ret;
- size_t len;
-
- ret = strlen(src);
- len = ret >= count ? count - 1 : ret;
- memcpy(dest, src, len);
- dest[len] = '\0';
- return ret;
-}
-#endif
+module_exit(VMBlockExit);
#define __OS_H__
#include "driver-config.h"
-#include "compat_list.h"
-#include "compat_completion.h"
+#include <linux/completion.h>
#include <linux/limits.h>
#include "compat_slab.h"
-#include "compat_wait.h"
+#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/errno.h>
-#include "compat_sched.h"
#include <asm/current.h>
-#include "compat_kernel.h"
-#include "compat_spinlock.h"
typedef rwlock_t os_rwlock_t;
typedef compat_kmem_cache os_kmem_cache_t;
-typedef compat_completion os_completion_t;
+typedef struct completion os_completion_t;
typedef atomic_t os_atomic_t;
typedef struct file * os_blocker_id_t;
#define OS_FMTTID "d"
#define os_threadid (current->pid)
-/*
- * XXX vprintk() wasn't exported until 2.6.9; we should do something more
- * intelligent here eventually.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
-# define os_panic(fmt, args) \
+
+#define os_panic(fmt, args) \
({ \
vprintk(fmt, args); \
BUG(); \
})
-#else
-# define os_panic(fmt, args) \
- ({ \
- BUG(); \
- })
-#endif
#define os_rwlock_init(lock) rwlock_init(lock)
#define os_rwlock_destroy(lock)
#define os_kmem_cache_alloc(cache) kmem_cache_alloc(cache, GFP_KERNEL)
#define os_kmem_cache_free(cache, elem) kmem_cache_free(cache, elem)
-#define os_completion_init(comp) compat_init_completion(comp)
+#define os_completion_init(comp) init_completion(comp)
#define os_completion_destroy(comp)
/*
* XXX This should be made interruptible using
*/
#define os_wait_for_completion(comp) \
({ \
- compat_wait_for_completion(comp); \
+ wait_for_completion(comp); \
0; \
})
-#define os_complete_all(comp) compat_complete_all(comp)
+#define os_complete_all(comp) complete_all(comp)
#define os_atomic_dec_and_test(atomic) atomic_dec_and_test(atomic)
#define os_atomic_dec(atomic) atomic_dec(atomic)
*/
#include "driver-config.h"
-#include "compat_fs.h"
-#include "compat_statfs.h"
+#include <linux/fs.h>
+#include <linux/statfs.h>
#include "vmblockInt.h"
#include "filesystem.h"
/* Super block operations */
-#ifdef VMW_EMBED_INODE
static struct inode *SuperOpAllocInode(struct super_block *sb);
static void SuperOpDestroyInode(struct inode *inode);
-#else
-static void SuperOpClearInode(struct inode *inode);
-#endif
-#ifndef VMW_USE_IGET_LOCKED
-static void SuperOpReadInode(struct inode *inode);
-#endif
#ifdef VMW_STATFS_2618
-static int SuperOpStatfs(struct dentry *dentry, struct compat_kstatfs *stat);
+static int SuperOpStatfs(struct dentry *dentry, struct kstatfs *stat);
#else
-static int SuperOpStatfs(struct super_block *sb, struct compat_kstatfs *stat);
+static int SuperOpStatfs(struct super_block *sb, struct kstatfs *stat);
#endif
struct super_operations VMBlockSuperOps = {
-#ifdef VMW_EMBED_INODE
.alloc_inode = SuperOpAllocInode,
.destroy_inode = SuperOpDestroyInode,
-#else
- .clear_inode = SuperOpClearInode,
-#endif
-#ifndef VMW_USE_IGET_LOCKED
- .read_inode = SuperOpReadInode,
-#endif
.statfs = SuperOpStatfs,
};
-#ifdef VMW_EMBED_INODE
/*
*----------------------------------------------------------------------------
*
/* The inode we give back to VFS is embedded within our inode info struct. */
return &iinfo->inode;
}
-#endif
/*
*/
static void
-#ifdef VMW_EMBED_INODE
SuperOpDestroyInode(struct inode *inode) // IN: Inode to free
-#else
-SuperOpClearInode(struct inode *inode) // IN: Inode to free
-#endif
{
kmem_cache_free(VMBlockInodeCache, INODE_TO_IINFO(inode));
}
-#ifndef VMW_USE_IGET_LOCKED
-/*
- *----------------------------------------------------------------------------
- *
- * SuperOpReadInode --
- *
- * Performs any filesystem wide inode initialization. This is only called by
- * iget() in older kernels that do not support iget_locked(). Newer kernels
- * that use the iget_locked() interface are required to initialize the inode
- * after it has been returned to the filesystem.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-SuperOpReadInode(struct inode *inode) // IN: Inode to initialize
-{
- VMBlockReadInode(inode);
-}
-#endif
-
/*
*----------------------------------------------------------------------------
*
#ifdef VMW_STATFS_2618
static int
SuperOpStatfs(struct dentry *dentry,
- struct compat_kstatfs *stat)
+ struct kstatfs *stat)
#else
static int
SuperOpStatfs(struct super_block *sb,
- struct compat_kstatfs *stat)
+ struct kstatfs *stat)
#endif
{
if (!stat) {
#ifndef __VMBLOCKINT_H__
#define __VMBLOCKINT_H__
-#include "compat_version.h"
-#include "compat_mm.h"
+#include <linux/version.h>
+#include <linux/mm.h>
#include "vmblock.h"
#include "vm_basic_types.h"
*
* XXX This should go in driver-config.h, but vmmon's hostKernel.h is retarded.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29)
static const void *forceProcessorCheck __attribute__((unused)) = __alloc_pages;
-#endif
/*
int VMBlockInitFileSystem(char const *root);
int VMBlockCleanupFileSystem(void);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70)
-size_t strlcpy(char *dest, const char *src, size_t count);
-#endif
-
#endif /* __VMBLOCK_H__ */
*********************************************************/
/*
- * vmciGuestKernelIf.c --
- *
+ * vmciGuestKernelIf.c --
+ *
* This file implements guest only OS helper functions for VMCI.
* This is the linux specific implementation.
- */
+ */
/* Must come before any kernel header file */
#include "driver-config.h"
#error "Wrong platform."
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
#include <linux/moduleparam.h>
-#endif
#include "compat_version.h"
#include "compat_pci.h"
#error "Wrong platform."
#endif
+#if !defined(VMX86_TOOLS) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
+# error "Host Linux kernels before 2.6.9 are not supported."
+#endif
+
#define EXPORT_SYMTAB
#define __NO_VERSION__
#include "compat_module.h"
VMCIQueue *produceQ, // OUT
VMCIQueue *consumeQ) // OUT
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
int retval;
int err = VMCI_SUCCESS;
}
return err;
-
-#else
- /*
- * Host queue pair support for earlier kernels temporarily
- * disabled. See bug 365496.
- */
-
- ASSERT_NOT_IMPLEMENTED(FALSE);
-#if 0
- attach->produceIoBuf = VMCI_AllocKernelMem(sizeof *attach->produceIoBuf,
- VMCI_MEMORY_NORMAL);
- if (attach->produceIoBuf == NULL) {
- return VMCI_ERROR_NO_MEM;
- }
-
- attach->consumeIoBuf = VMCI_AllocKernelMem(sizeof *attach->consumeIoBuf,
- VMCI_MEMORY_NORMAL);
- if (attach->consumeIoBuf == NULL) {
- VMCI_FreeKernelMem(attach->produceIoBuf,
- sizeof *attach->produceIoBuf);
- return VMCI_ERROR_NO_MEM;
- }
-
- retval = map_user_kiobuf(WRITE, attach->produceIoBuf,
- (VA)attach->produceBuffer,
- attach->numProducePages * PAGE_SIZE);
- if (retval < 0) {
- err = VMCI_ERROR_NO_ACCESS;
- goto out;
- }
-
- retval = map_user_kiobuf(WRITE, attach->consumeIoBuf,
- (VA)attach->consumeBuffer,
- attach->numConsumePages * PAGE_SIZE);
- if (retval < 0) {
- unmap_kiobuf(attach->produceIoBuf);
- err = VMCI_ERROR_NO_ACCESS;
- }
-
- if (err == VMCI_SUCCESS) {
- produceQ->queueHeaderPtr = kmap(attach->produceIoBuf->maplist[0]);
- produceQ->page = &attach->produceIoBuf->maplist[1];
- consumeQ->queueHeaderPtr = kmap(attach->consumeIoBuf->maplist[0]);
- consumeQ->page = &attach->consumeIoBuf->maplist[1];
- }
-
-out:
-
- if (err < VMCI_SUCCESS) {
- if (attach->produceIoBuf != NULL) {
- VMCI_FreeKernelMem(attach->produceIoBuf,
- sizeof *attach->produceIoBuf);
- }
- if (attach->consumeIoBuf != NULL) {
- VMCI_FreeKernelMem(attach->consumeIoBuf,
- sizeof *attach->consumeIoBuf);
- }
- }
-
- return err;
-#else // 0 -- Instead just return FALSE
- return FALSE;
-#endif // 0
-#endif // Linux version >= 2.6.0
}
VMCIQueue *produceQ, // OUT
VMCIQueue *consumeQ) // OUT
{
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
int i;
ASSERT(attach->producePages);
VMCI_FreeKernelMem(attach->consumePages,
attach->numConsumePages *
sizeof attach->consumePages[0]);
-#else
- /*
- * Host queue pair support for earlier kernels temporarily
- * disabled. See bug 365496.
- */
-
- ASSERT_NOT_IMPLEMENTED(FALSE);
-#if 0
- kunmap(attach->produceIoBuf->maplist[0]);
- kunmap(attach->consumeIoBuf->maplist[0]);
-
- mark_dirty_kiobuf(attach->produceIoBuf,
- attach->numProducePages * PAGE_SIZE);
- unmap_kiobuf(attach->produceIoBuf);
-
- mark_dirty_kiobuf(attach->consumeIoBuf,
- attach->numConsumePages * PAGE_SIZE);
- unmap_kiobuf(attach->consumeIoBuf);
-
- VMCI_FreeKernelMem(attach->produceIoBuf,
- sizeof *attach->produceIoBuf);
- VMCI_FreeKernelMem(attach->consumeIoBuf,
- sizeof *attach->consumeIoBuf);
-#endif
-#endif
}
-#endif
+#endif /* Host only code */
*
*********************************************************/
-/*
+/*
* vmci.c --
*
* Linux guest driver for the VMCI device.
*/
-
+
#include "driver-config.h"
-#define EXPORT_SYMTAB
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
#include <linux/moduleparam.h>
-#endif
-
+
#include "compat_kernel.h"
#include "compat_module.h"
#include "compat_pci.h"
static void vmci_remove_device(struct pci_dev* pdev);
static int vmci_open(struct inode *inode, struct file *file);
static int vmci_close(struct inode *inode, struct file *file);
-static int vmci_ioctl(struct inode *inode, struct file *file,
+static int vmci_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static unsigned int vmci_poll(struct file *file, poll_table *wait);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id,
+static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id,
struct pt_regs * regs);
#else
static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id);
/* We dynamically request the device major number at init time. */
static int device_major_nr = 0;
-DECLARE_TASKLET(vmci_tasklet, dispatch_datagrams,
+DECLARE_TASKLET(vmci_tasklet, dispatch_datagrams,
(unsigned long)&vmci_dev);
-/*
- * Allocate a buffer for incoming datagrams globally to avoid repeated
- * allocation in the interrupt handler's atomic context.
- */
+/*
+ * Allocate a buffer for incoming datagrams globally to avoid repeated
+ * allocation in the interrupt handler's atomic context.
+ */
-static uint8 *data_buffer = NULL;
+static uint8 *data_buffer = NULL;
static uint32 data_buffer_size = VMCI_MAX_DG_SIZE;
/* Register device node ops. */
err = register_chrdev(0, "vmci", &vmci_ops);
if (err < 0) {
- printk(KERN_ERR "Unable to register vmci device\n");
+ printk(KERN_ERR "Unable to register vmci device\n");
return err;
}
device_major_nr = err;
if (data_buffer == NULL) {
goto error;
}
-
+
/* This should be last to make sure we are done initializing. */
err = pci_register_driver(&vmci_driver);
if (err < 0) {
vmci_exit(void)
{
pci_unregister_driver(&vmci_driver);
-
+
unregister_chrdev(device_major_nr, "vmci");
vfree(data_buffer);
vmci_dev.enabled = TRUE;
pci_set_drvdata(pdev, &vmci_dev);
- /*
+ /*
* We do global initialization here because we need datagrams for
* event init. If we ever support more than one VMCI device we will
* have to create seperate LateInit/EarlyExit functions that can be
VMCIUtil_Init();
VMCIQueuePair_Init();
- if (request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED,
+ if (request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED,
"vmci", &vmci_dev)) {
printk(KERN_ERR "vmci: irq %u in use\n", vmci_dev.irq);
goto components_exit;
VMCIEvent_Exit();
//VMCIDatagram_Exit();
VMCIProcess_Exit();
-
+
down(&dev->lock);
printk(KERN_INFO "Resetting vmci device\n");
outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR);
printk(KERN_INFO "Unregistered vmci device.\n");
up(&dev->lock);
-
+
compat_pci_disable_device(pdev);
}
retval = -EFAULT;
break;
}
-
+
if (VMCIDatagramProcess_Create(&dgmProc, &createInfo,
0 /* Unused */) < VMCI_SUCCESS) {
retval = -EINVAL;
}
DEBUG_ONLY(printk("VMCI: Datagram dst handle 0x%x:0x%x, src handle "
- "0x%x:0x%x, payload size %"FMT64"u.\n",
- dg->dst.context, dg->dst.resource,
+ "0x%x:0x%x, payload size %"FMT64"u.\n",
+ dg->dst.context, dg->dst.resource,
dg->src.context, dg->src.resource, dg->payloadSize));
sendInfo.result = VMCIDatagram_Send(dg);
}
ASSERT(devHndl->obj);
- recvInfo.result =
- VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj,
+ recvInfo.result =
+ VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj,
recvInfo.len, &dg);
if (recvInfo.result < VMCI_SUCCESS) {
retval = -EINVAL;
VMCIGuestDeviceHandle *devHndl =
(VMCIGuestDeviceHandle *) file->private_data;
- /*
- * Check for call to this VMCI process.
+ /*
+ * Check for call to this VMCI process.
*/
-
+
if (!devHndl) {
return mask;
}
if (devHndl->objType == VMCIOBJ_DATAGRAM_PROCESS) {
VMCIDatagramProcess *dgmProc = (VMCIDatagramProcess *) devHndl->obj;
ASSERT(dgmProc);
-
+
if (wait != NULL) {
poll_wait(file, &dgmProc->host.waitQueue, wait);
}
down(&vmci_dev.lock);
retval = vmci_dev.enabled;
up(&vmci_dev.lock);
-
+
return retval;
}
*/
spin_lock_irqsave(&vmci_dev.dev_spinlock, flags);
- /*
+ /*
* Send the datagram and retrieve the return value from the result register.
*/
__asm__ __volatile__(
"present.\n");
return;
}
-
+
if (data_buffer == NULL) {
printk(KERN_DEBUG "vmci: dispatch_datagrams(): no buffer present.\n");
return;
#ifndef _VMCI_VERSION_H_
#define _VMCI_VERSION_H_
-#define VMCI_DRIVER_VERSION 1.0.18.0
-#define VMCI_DRIVER_VERSION_COMMAS 1,0,18,0
-#define VMCI_DRIVER_VERSION_STRING "1.0.18.0"
+#define VMCI_DRIVER_VERSION 1.0.19.0
+#define VMCI_DRIVER_VERSION_COMMAS 1,0,19,0
+#define VMCI_DRIVER_VERSION_STRING "1.0.19.0"
#endif /* _VMCI_VERSION_H_ */
/* Private functions. */
static int HgfsUnpackSearchReadReply(HgfsReq *req,
- HgfsAttrInfo *attr);
+ HgfsAttrInfo *attr,
+ char **entryName);
static int HgfsGetNextDirEntry(HgfsSuperInfo *si,
HgfsHandle searchHandle,
uint32 offset,
HgfsAttrInfo *attr,
+ char **entryName,
Bool *done);
static int HgfsPackDirOpenRequest(struct inode *inode,
struct file *file,
- HgfsOp opUsed,
+ HgfsOp opUsed,
HgfsReq *req);
/* HGFS file operations for directories. */
*/
static int
HgfsUnpackSearchReadReply(HgfsReq *req, // IN: Reply packet
- HgfsAttrInfo *attr) // IN/OUT: Attributes
+ HgfsAttrInfo *attr, // IN/OUT: Attributes
+ char **entryName) // OUT: file name
{
char *fileName;
uint32 fileNameLength;
fileNameLength, strlen(fileName), fileName));
return -EPROTO;
}
- attr->fileName = kmalloc(fileNameLength + 1, GFP_KERNEL);
- if (attr->fileName == NULL) {
+ *entryName = kmalloc(fileNameLength + 1, GFP_KERNEL);
+ if (*entryName == NULL) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackSearchReadReply: out of "
"memory allocating filename, ignoring\n"));
return -ENOMEM;
}
- memcpy(attr->fileName, fileName, fileNameLength + 1);
+ memcpy(*entryName, fileName, fileNameLength + 1);
} else {
- attr->fileName = NULL;
+ *entryName = NULL;
}
return 0;
}
*
* Get the directory entry with the given offset from the server.
*
- * attr->fileName gets allocated and must be freed by the caller.
+ * fileName gets allocated and must be freed by the caller.
*
* Results:
* Returns zero on success, negative error on failure. If the
HgfsHandle searchHandle, // IN: Handle of dir
uint32 offset, // IN: Offset of next dentry to get
HgfsAttrInfo *attr, // OUT: File attributes of dentry
+ char **entryName, // OUT: File name
Bool *done) // OUT: Set true when there are
// no more dentries
{
switch(result) {
case 0:
- result = HgfsUnpackSearchReadReply(req, attr);
- if (result == 0 && attr->fileName == NULL) {
+ result = HgfsUnpackSearchReadReply(req, attr, entryName);
+ if (result == 0 && *entryName == NULL) {
/* We're at the end of the directory. */
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: end of "
"dir\n"));
HgfsSuperInfo *si;
HgfsAttrInfo attr;
uint32 d_type; // type of dirent
+ char *fileName = NULL;
char *escName = NULL; // buf for escaped version of name
size_t escNameLength = NAME_MAX + 1;
int nameLength = 0;
* Nonzero result = we failed to get valid reply from server.
* Zero result:
* - done == TRUE means we hit the end of the directory
- * - Otherwise, attr.fileName has the name of the next dirent
+ * - Otherwise, fileName has the name of the next dirent
*
*/
result = HgfsGetNextDirEntry(si,
FILE_GET_FI_P(file)->handle,
(uint32)file->f_pos,
&attr,
+ &fileName,
&done);
if (result == -ENAMETOOLONG) {
/*
* CP name format, but that is done implicitely here since we
* are guaranteed to have just one path component per dentry.
*/
- result = HgfsEscape_Do(attr.fileName,
- strlen(attr.fileName),
- escNameLength,
- escName);
- kfree(attr.fileName);
+ result = HgfsEscape_Do(fileName, strlen(fileName),
+ escNameLength, escName);
+ kfree(fileName);
+ fileName = NULL;
/*
* Check the filename length.
static void HgfsSetFileType(struct inode *inode,
HgfsAttrInfo const *attr);
static int HgfsUnpackGetattrReply(HgfsReq *req,
- HgfsAttrInfo *attr);
+ HgfsAttrInfo *attr,
+ char **fileName);
static int HgfsPackGetattrRequest(HgfsReq *req,
struct dentry *dentry,
Bool allowHandleReuse,
*/
static int
HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet
- HgfsAttrInfo *attr) // IN/OUT: Attributes
+ HgfsAttrInfo *attr, // IN/OUT: Attributes
+ char **fileName) // OUT: file name
{
int result;
char *name = NULL;
}
}
- if (length != 0) {
+ if (fileName) {
+ if (length != 0) {
- attr->fileName = kmalloc(length + 1, GFP_KERNEL);
- if (attr->fileName == NULL) {
- LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of "
- "memory allocating symlink target name, ignoring\n"));
- return -ENOMEM;
- }
+ *fileName = kmalloc(length + 1, GFP_KERNEL);
+ if (*fileName == NULL) {
+ LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of "
+ "memory allocating symlink target name, ignoring\n"));
+ return -ENOMEM;
+ }
- /* Copy and convert. From now on, the symlink target is in UTF8. */
- memcpy(attr->fileName, name, length);
- CPNameLite_ConvertFrom(attr->fileName, length, '/');
- attr->fileName[length] = '\0';
+ /* Copy and convert. From now on, the symlink target is in UTF8. */
+ memcpy(*fileName, name, length);
+ CPNameLite_ConvertFrom(*fileName, length, '/');
+ (*fileName)[length] = '\0';
+ } else {
+ *fileName = NULL;
+ }
}
return 0;
* for the indicated remote name, and if it succeeds copy the
* results of the getattr into the provided HgfsAttrInfo.
*
- * attr->fileName will be allocated on success if the file is a
- * symlink; it's the caller's duty to free it.
+ * 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.
int
HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name
- HgfsAttrInfo *attr) // OUT: Attr to copy into
+ HgfsAttrInfo *attr, // OUT: Attr to copy into
+ char **fileName) // OUT: pointer to allocated file name
{
struct HgfsSuperInfo *si;
HgfsReq *req;
*/
switch (result) {
case 0:
- result = HgfsUnpackGetattrReply(req, attr);
+ result = HgfsUnpackGetattrReply(req, attr, fileName);
break;
case -EBADF:
/*
int error;
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInstantiate: issuing getattr\n"));
- newAttr.fileName = NULL;
- error = HgfsPrivateGetattr(dentry, &newAttr);
+ error = HgfsPrivateGetattr(dentry, &newAttr, NULL);
if (error) {
return error;
}
- kfree(newAttr.fileName);
attr = &newAttr;
}
uint32 userId; /* UID */
uint32 groupId; /* GID */
uint64 hostFileId; /* Inode number */
- char *fileName; /* Either symlink target or filename */
} HgfsAttrInfo;
void HgfsChangeFileAttributes(struct inode *inode,
HgfsAttrInfo const *attr);
int HgfsPrivateGetattr(struct dentry *dentry,
- HgfsAttrInfo *attr);
+ HgfsAttrInfo *attr,
+ char **fileName);
struct inode *HgfsIget(struct super_block *sb,
ino_t ino,
HgfsAttrInfo const *attr);
/* Do a getattr on the file to see if it exists on the server. */
inode = NULL;
- attr.fileName = NULL;
- error = HgfsPrivateGetattr(dentry, &attr);
+ error = HgfsPrivateGetattr(dentry, &attr, NULL);
if (!error) {
/* File exists on the server. */
* the server.
*/
inode = HgfsIget(dir->i_sb, 0, &attr);
- kfree(attr.fileName);
if (!inode) {
error = -ENOMEM;
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsLookup: out of memory getting "
if (!dentry) {
return 0;
}
- ret = HgfsPrivateGetattr(dentry, &attr);
+ ret = HgfsPrivateGetattr(dentry, &attr, NULL);
if (ret == 0) {
uint32 effectivePermissions;
* be current with our view of the file.
*/
compat_filemap_write_and_wait(dentry->d_inode->i_mapping);
- attr.fileName = NULL;
- error = HgfsPrivateGetattr(dentry, &attr);
+ error = HgfsPrivateGetattr(dentry, &attr, NULL);
if (!error) {
/*
* If server provides file ID, we need to check whether it has changed
/* Update inode's attributes and reset the age. */
HgfsChangeFileAttributes(dentry->d_inode, &attr);
HgfsDentryAgeReset(dentry);
- kfree(attr.fileName);
}
} else {
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: using cached dentry "
#endif
{
HgfsAttrInfo attr;
+ char *fileName = NULL;
int error;
ASSERT(dentry);
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling "
"HgfsPrivateGetattr\n"));
- attr.fileName = NULL;
- error = HgfsPrivateGetattr(dentry, &attr);
+ error = HgfsPrivateGetattr(dentry, &attr, &fileName);
if (!error) {
/* Let's make sure we got called on a symlink. */
- if (attr.type != HGFS_FILE_TYPE_SYMLINK ||
- attr.fileName == NULL) {
+ if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) {
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called "
"on something that wasn't a symlink\n"));
error = -EINVAL;
} else {
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling "
"vfs_follow_link\n"));
- error = vfs_follow_link(nd, attr.fileName);
+ error = vfs_follow_link(nd, fileName);
}
- kfree(attr.fileName);
+ kfree(fileName);
}
out:
{
HgfsAttrInfo attr;
+ char *fileName = NULL;
int error;
ASSERT(dentry);
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: calling "
"HgfsPrivateGetattr\n"));
- attr.fileName = NULL;
- error = HgfsPrivateGetattr(dentry, &attr);
+ error = HgfsPrivateGetattr(dentry, &attr, &fileName);
if (!error) {
/* Let's make sure we got called on a symlink. */
- if (attr.type != HGFS_FILE_TYPE_SYMLINK ||
- attr.fileName == NULL) {
+ if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) {
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: got called "
"on something that wasn't a symlink\n"));
error = -EINVAL;
} else {
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: calling "
"vfs_readlink\n"));
- error = vfs_readlink(dentry, buffer, buflen, attr.fileName);
+ error = vfs_readlink(dentry, buffer, buflen, fileName);
}
- kfree(attr.fileName);
+ kfree(fileName);
}
return error;
}
*
*********************************************************/
-/*
+/*
* os.c --
*
- * Wrappers for Linux system functions required by "vmmemctl".
- * This allows customers to build their own vmmemctl driver for
- * custom versioned kernels without the need for source code.
+ * Wrappers for Linux system functions required by "vmmemctl".
*/
/*
#include "driver-config.h"
-#include "compat_module.h"
+#include <linux/module.h>
#include <linux/types.h>
-#include "compat_kernel.h"
-#include "compat_completion.h"
-#include "compat_mm.h"
+#include <linux/kernel.h>
+#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include "compat_sched.h"
-#include <asm/uaccess.h>
-#include "compat_page.h"
-#include "compat_wait.h"
-#include "vmmemctl_version.h"
+#include <linux/kthread.h>
#ifdef CONFIG_PROC_FS
#include <linux/stat.h>
#include <linux/proc_fs.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
-/*
- * The get_info callback of proc_dir_entry was removed in 2.6.26.
- * We must therefore use the seq_file interface from that point on.
- */
-#define VMW_USE_SEQ_FILE
#include <linux/seq_file.h>
-#endif
#endif /* CONFIG_PROC_FS */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#include <linux/smp_lock.h>
-#include "compat_kthread.h"
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)
-int errno; /* compat_exit() needs global errno variable. */
-#endif
-
-/*
- * Compatibility definitions.
- */
+#include "compat_sched.h"
-/*
- * Execute as a separate kernel thread on 2.4.x kernels.
- * Allow allocations from high memory on 2.4.x kernels.
- */
-#define OS_KTHREAD (1)
-COMPAT_KTHREAD_DECLARE_STOP_INFO();
-#endif
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include "vmmemctl_version.h"
#include "os.h"
* Constants
*/
-#ifdef OS_KTHREAD
/*
* Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't
- * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use
- * __GFP_NOWARN, if available, to suppress page allocation failure
- * warnings.
+ * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use
+ * __GFP_NOWARN, to suppress page allocation failure warnings.
*/
-#ifdef __GFP_NOWARN
#define OS_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN)
-#else
-#define OS_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM)
-#endif
/*
* GFP_ATOMIC allocations dig deep for free pages. Maybe it is
- * okay because balloon driver uses os_kmalloc_*() to only allocate
- * few bytes, and the allocation requires a new page only occasionally.
+ * okay because balloon driver uses OS_Malloc() to only allocate
+ * few bytes, and the allocation requires a new page only occasionally.
* Still if __GFP_NOMEMALLOC flag is available, then use it to inform
- * the guest's page allocator not to use emergency pools,
+ * the guest's page allocator not to use emergency pools.
*/
-#ifdef __GFP_NOWARN
-
#ifdef __GFP_NOMEMALLOC
#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN)
#else
#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC|__GFP_NOWARN)
#endif
-#else
-
-#ifdef __GFP_NOMEMALLOC
-#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC|__GFP_NOMEMALLOC)
-#else
-#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC)
-#endif
-
-#endif
/*
- * Use GFP_HIGHUSER when executing in a separate kernel thread
+ * Use GFP_HIGHUSER when executing in a separate kernel thread
* context and allocation can sleep. This is less stressful to
* the guest memory system, since it allows the thread to block
* while memory is reclaimed, and won't take pages from emergency
*/
#define OS_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER)
-#else /* OS_KTHREAD not defined */
-
-/* 2.2.x kernel is a special case. The balloon driver is unable
- * to block (sleep) because it is not executing in a separate kernel
- * thread. Therefore, the driver can only use NOSLEEP page
- * allocations.
- *
- * Use __GFP_LOW when available (2.2.x kernels) to avoid stressing
- * the guest memory system, otherwise simply use GFP_ATOMIC, which
- * is always defined (normally as __GFP_HIGH).
- */
-#ifdef __GFP_LOW
-#define OS_PAGE_ALLOC_NOSLEEP (__GFP_LOW)
-#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC)
-#else
-#define OS_PAGE_ALLOC_NOSLEEP (GFP_ATOMIC)
-#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC)
-#endif
-
-#endif
-
/*
* Types
*/
typedef struct {
/* registered state */
- os_timer_handler handler;
+ OSTimerHandler *handler;
void *data;
int period;
/* system structures */
-#ifdef OS_KTHREAD
wait_queue_head_t delay;
struct task_struct *task;
-#else
- /* termination flag */
- atomic_t stop;
-
- struct timer_list timer;
- struct tq_struct task;
-#endif
} os_timer;
typedef struct {
/* registered state */
- os_status_handler handler;
+ OSStatusHandler *handler;
const char *name_verbose;
const char *name;
} os_status;
*/
#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static struct proc_dir_entry *global_proc_entry;
-#ifdef VMW_USE_SEQ_FILE
static int os_proc_open(struct inode *, struct file *);
static struct file_operations global_proc_fops = {
.open = os_proc_open,
.llseek = seq_lseek,
.release = single_release,
};
-#else
-static int os_proc_read(char *, char **, off_t, int);
-#endif /* VMW_USE_SEQ_FILE */
-#else
-static int os_proc_read(char *, char **, off_t, int, int);
-static struct proc_dir_entry global_proc_entry = {
- 0, 8, "vmmemctl", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, os_proc_read,
-};
-#endif
#endif /* CONFIG_PROC_FS */
static os_state global_state;
+
/*
- * Simple Wrappers
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Malloc --
+ *
+ * Allocates kernel memory.
+ *
+ * Results:
+ * On success: Pointer to allocated memory
+ * On failure: NULL
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-void * CDECL
-os_kmalloc_nosleep(unsigned int size)
+void *
+OS_Malloc(size_t size) // IN
{
return(kmalloc(size, OS_KMALLOC_NOSLEEP));
}
-void CDECL
-os_kfree(void *obj, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Free --
+ *
+ * Free allocated kernel memory.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Free(void *ptr, // IN
+ size_t size) // IN
{
- kfree(obj);
+ kfree(ptr);
}
-void CDECL
-os_bzero(void *s, unsigned int n)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemZero --
+ *
+ * Fill a memory location with 0s.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemZero(void *ptr, // OUT
+ size_t size) // IN
{
- memset(s, 0, n);
+ memset(ptr, 0, size);
}
-void CDECL
-os_memcpy(void *dest, const void *src, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemCopy --
+ *
+ * Copy a memory portion into another location.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemCopy(void *dest, // OUT
+ const void *src, // IN
+ size_t size) // IN
{
memcpy(dest, src, size);
}
-int CDECL
-os_sprintf(char *str, const char *format, ...)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Snprintf --
+ *
+ * Print a string into a bounded memory location.
+ *
+ * Results:
+ * Number of character printed including trailing \0.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+OS_Snprintf(char *buf, // OUT
+ size_t size, // IN
+ const char *format, // IN
+ ...) // IN
{
int result;
va_list args;
va_start(args, format);
- result = vsprintf(str, format, args);
+ result = vsnprintf(buf, size, format, args);
va_end(args);
- return(result);
+ return result;
}
/*
* System-Dependent Operations
*/
-char * CDECL
-os_identity(void)
+const char *
+OS_Identity(void)
{
return("linux");
}
* booted with a mem=XX parameter) the totalram-size is equal to alloc.max.
*
* Returns the maximum achievable balloon size in pages
- */
-unsigned int CDECL
-os_predict_max_balloon_pages(void)
+ */
+unsigned int
+OS_PredictMaxReservedPages(void)
{
struct sysinfo info;
os_state *state = &global_state;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-
- /*
- * In 2.4.0 and later, si_meminfo() is cheap. Moreover, we want to provide
- * dynamic max balloon size later. So let us call si_meminfo() every
- * iteration.
+ /*
+ * si_meminfo() is cheap. Moreover, we want to provide dynamic
+ * max balloon size later. So let us call si_meminfo() every
+ * iteration.
*/
si_meminfo(&info);
-
- /* In 2.4.x and later kernels, info.totalram is in pages */
- state->totalMemoryPages = info.totalram;
- return(state->totalMemoryPages);
-
-#else
- /* 2.2.x kernel */
- if (!state->totalMemoryPages) {
- si_meminfo(&info); /* In 2.2.x, si_meminfo() is a costly operation */
- /* In 2.2.x kernels, info.totalram is in bytes */
- state->totalMemoryPages = info.totalram >> PAGE_SHIFT;
- }
- return(state->totalMemoryPages);
-
-#endif
+ /* info.totalram is in pages */
+ state->totalMemoryPages = info.totalram;
+ return state->totalMemoryPages;
}
/*
* Use newer alloc_page() interface on 2.4.x kernels.
* Use "struct page *" value as page handle for clients.
*/
-unsigned long CDECL
-os_addr_to_ppn(unsigned long addr)
+unsigned long
+OS_AddrToPPN(unsigned long addr)
{
struct page *page = (struct page *) addr;
- return(page_to_pfn(page));
+
+ return page_to_pfn(page);
}
-unsigned long CDECL
-os_alloc_reserved_page(int can_sleep)
+unsigned long
+OS_AllocReservedPage(int canSleep)
{
- struct page *page;
- /* allocate page */
- if (can_sleep) {
-#ifdef OS_KTHREAD
- page = alloc_page(OS_PAGE_ALLOC_CANSLEEP);
-#else
- return 0;
-#endif
- } else {
- page = alloc_page(OS_PAGE_ALLOC_NOSLEEP);
- }
- return((unsigned long) page);
+ struct page *page = alloc_page(canSleep ?
+ OS_PAGE_ALLOC_CANSLEEP : OS_PAGE_ALLOC_NOSLEEP);
+
+ return (unsigned long)page;
}
-void CDECL
-os_free_reserved_page(unsigned long addr)
+void
+OS_FreeReservedPage(unsigned long addr)
{
/* deallocate page */
struct page *page = (struct page *) addr;
__free_page(page);
}
-#ifndef OS_KTHREAD
-static void os_timer_add(os_timer *t)
-{
- /* schedule timer callback */
- struct timer_list *timer = &t->timer;
- timer->expires = jiffies + t->period;
- add_timer(timer);
-}
-
-static void os_timer_remove(os_timer *t)
-{
- /* deschedule timer callback */
- struct timer_list *timer = &t->timer;
- (void) del_timer(timer);
-}
-
-static void os_timer_bh(void *data)
-{
- os_timer *t = (os_timer *) data;
-
- if (!atomic_read(&t->stop)) {
- /* execute registered handler, rearm timer */
- (*(t->handler))(t->data);
- os_timer_add(t);
- }
-}
-
-static void os_timer_internal(ulong data)
-{
- os_timer *t = (os_timer *) data;
-
- /* perform real work in registered bottom-half handler */
- queue_task(&t->task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-#endif
-
-void CDECL
-os_timer_init(os_timer_handler handler, void *data, int period)
+void
+OS_TimerInit(OSTimerHandler *handler, // IN
+ void *clientData, // IN
+ int period) // IN
{
os_timer *t = &global_state.timer;
t->handler = handler;
- t->data = data;
+ t->data = clientData;
t->period = period;
-#ifndef OS_KTHREAD
- atomic_set(&t->stop, 0);
- t->task.routine = os_timer_bh;
- t->task.data = t;
- /* initialize timer state */
- init_timer(&t->timer);
- t->timer.function = os_timer_internal;
- t->timer.data = (ulong) t;
-#endif
}
-#ifdef OS_KTHREAD
static int os_timer_thread_loop(void *data)
{
os_timer *t = (os_timer *) data;
/* sleep for specified period */
wait_event_interruptible_timeout(t->delay,
compat_wait_check_freezing() ||
- compat_kthread_should_stop(),
+ kthread_should_stop(),
t->period);
compat_try_to_freeze();
- if (compat_kthread_should_stop()) {
+ if (kthread_should_stop()) {
break;
}
/* execute registered handler */
- (*(t->handler))(t->data);
+ t->handler(t->data);
}
/* terminate */
return(0);
}
-static int os_timer_thread_start(os_timer *t)
+void
+OS_TimerStart(void)
{
+ os_timer *t = &global_state.timer;
os_status *s = &global_state.status;
/* initialize sync objects */
init_waitqueue_head(&t->delay);
/* create kernel thread */
- t->task = compat_kthread_run(os_timer_thread_loop, t, "vmmemctl");
+ t->task = kthread_run(os_timer_thread_loop, t, "vmmemctl");
if (IS_ERR(t->task)) {
/* fail */
printk(KERN_WARNING "%s: unable to create kernel thread\n", s->name);
- return(-1);
- }
-
- if (OS_DEBUG) {
+ } else if (OS_DEBUG) {
printk(KERN_DEBUG "%s: started kernel thread pid=%d\n", s->name,
t->task->pid);
}
-
- return(0);
}
-static void os_timer_thread_stop(os_timer *t)
+void
+OS_TimerStop(void)
{
- compat_kthread_stop(t->task);
+ kthread_stop(global_state.timer.task);
}
-#endif
-void CDECL
-os_timer_start(void)
+unsigned int
+OS_TimerHz(void)
{
- os_timer *t = &global_state.timer;
-
-#ifdef OS_KTHREAD
- os_timer_thread_start(t);
-#else
- /* clear termination flag */
- atomic_set(&t->stop, 0);
-
- os_timer_add(t);
-#endif
+ return HZ;
}
-void CDECL
-os_timer_stop(void)
-{
- os_timer *t = &global_state.timer;
-#ifdef OS_KTHREAD
- os_timer_thread_stop(t);
-#else
- /* set termination flag */
- atomic_set(&t->stop, 1);
-
- os_timer_remove(t);
-#endif
-}
-
-unsigned int CDECL
-os_timer_hz(void)
-{
- return HZ;
-}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Yield --
+ *
+ * Yield the CPU, if needed.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * This thread might get descheduled, other threads might get scheduled.
+ *
+ *-----------------------------------------------------------------------------
+ */
-void CDECL
-os_yield(void)
+void
+OS_Yield(void)
{
-#ifdef OS_KTHREAD
cond_resched();
-#else
- /* Do nothing. Timer callbacks should not sleep. */
-#endif
}
#ifdef CONFIG_PROC_FS
-#ifdef VMW_USE_SEQ_FILE
static int os_proc_show(struct seq_file *f,
void *data)
{
goto out;
}
- s->handler(buf);
-
+ s->handler(buf, PAGE_SIZE);
+
if (seq_puts(f, buf) != 0) {
err = -ENOSPC;
goto out;
return single_open(file, os_proc_show, NULL);
}
-#else
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static int os_proc_read(char *buf,
- char **start,
- off_t offset,
- int length)
-#else
-static int os_proc_read(char *buf,
- char **start,
- off_t offset,
- int length,
- int unused)
#endif
-{
- os_status *s = &global_state.status;
- /* done if no handler */
- if (s->handler == NULL) {
- return(0);
- }
-
- /* invoke registered handler */
- return(s->handler(buf));
-}
-#endif /* VMW_USE_SEQ_FILE */
-#endif
-
-void CDECL
-os_init(const char *name,
+void
+OS_Init(const char *name,
const char *name_verbose,
- os_status_handler handler)
+ OSStatusHandler *handler)
{
os_state *state = &global_state;
static int initialized = 0;
/* prevent module unload with extra reference */
if (OS_DISABLE_UNLOAD) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 48)
- MOD_INC_USE_COUNT;
-#else
try_module_get(THIS_MODULE);
-#endif
}
/* zero global state */
#ifdef CONFIG_PROC_FS
/* register procfs device */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
global_proc_entry = create_proc_entry("vmmemctl", S_IFREG | S_IRUGO, NULL);
if (global_proc_entry != NULL) {
-#ifdef VMW_USE_SEQ_FILE
global_proc_entry->proc_fops = &global_proc_fops;
-#else
- global_proc_entry->get_info = os_proc_read;
-#endif /* VMW_USE_SEQ_FILE */
}
-#else
- proc_register(&proc_root, &global_proc_entry);
-#endif
#endif /* CONFIG_PROC_FS */
/* log device load */
printk(KERN_INFO "%s initialized\n", state->status.name_verbose);
}
-void CDECL
-os_cleanup(void)
+void
+OS_Cleanup(void)
{
os_status *s = &global_state.status;
- int err;
#ifdef CONFIG_PROC_FS
/* unregister procfs entry */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
remove_proc_entry("vmmemctl", NULL);
- err = 0;
-#else
- if ((err = proc_unregister(&proc_root, global_proc_entry.low_ino)) != 0) {
- printk(KERN_WARNING "%s: unable to unregister procfs entry (%d)\n", s->name, err);
- }
-#endif
#endif /* CONFIG_PROC_FS */
/* log device unload */
*
*********************************************************/
-/*
+/*
* os.h --
*
- * Definitions for OS-specific wrapper functions required
- * by "vmmemctl". This allows customers to build their own
- * vmmemctl driver for custom versioned kernels without the
- * need for source code.
+ * Definitions for OS-specific wrapper functions required by "vmmemctl".
*/
#ifndef OS_H
#define OS_H
-/*
- * Needs fixing for 64bit OSes
- */
-#ifndef __x86_64__
-#define CDECL __attribute__((cdecl, regparm(0)))
-#else
-#define CDECL
-#endif
-
/*
* Types
*/
-typedef void CDECL (*os_timer_handler)(void *);
-typedef int CDECL (*os_status_handler)(char *);
+typedef void OSTimerHandler(void *clientData);
+typedef int OSStatusHandler(char *buf, size_t size);
/*
* Operations
*/
-extern void CDECL *os_kmalloc_nosleep(unsigned int size);
-extern void CDECL os_kfree(void *obj, unsigned int size);
-extern void CDECL os_yield(void);
-extern void CDECL os_bzero(void *s, unsigned int n);
-extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size);
-extern int CDECL os_sprintf(char *str, const char *format, ...);
-
-extern unsigned long CDECL os_addr_to_ppn(unsigned long addr);
-extern unsigned long CDECL os_alloc_reserved_page(int can_sleep);
-extern void CDECL os_free_reserved_page(unsigned long page);
+extern void OS_Init(const char *name,
+ const char *nameVerbose,
+ OSStatusHandler *handler);
+extern void OS_Cleanup(void);
+extern const char *OS_Identity(void);
-extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period);
-extern void CDECL os_timer_start(void);
-extern void CDECL os_timer_stop(void);
+extern void OS_MemZero(void *ptr, size_t size);
+extern void OS_MemCopy(void *dest, const void *src, size_t size);
+extern int OS_Snprintf(char *buf, size_t size, const char *format, ...);
-extern void CDECL os_init(const char *name,
- const char *name_verbose,
- os_status_handler handler);
-extern void CDECL os_cleanup(void);
+extern void *OS_Malloc(size_t size);
+extern void OS_Free(void *ptr, size_t size);
-extern char CDECL *os_identity(void);
+extern void OS_Yield(void);
-extern unsigned int CDECL os_predict_max_balloon_pages(void);
+extern unsigned int OS_TimerHz(void);
+extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
+extern void OS_TimerStart(void);
+extern void OS_TimerStop(void);
-extern unsigned int CDECL os_timer_hz(void);
+extern unsigned int OS_PredictMaxReservedPages(void);
+extern unsigned long OS_AddrToPPN(unsigned long addr);
+extern unsigned long OS_AllocReservedPage(int canSleep);
+extern void OS_FreeReservedPage(unsigned long page);
#endif /* OS_H */
*
*********************************************************/
-/*
+/*
* vmballoon.c --
*
- * VMware server physical memory management driver for Unix-ish
- * (Linux, FreeBSD, Solaris) guests. The driver acts like a
- * "balloon" that can be inflated to reclaim physical pages by
- * reserving them in the guest and invalidating them in the
- * monitor, freeing up the underlying machine pages so they can
- * be allocated to other guests. The balloon can also be
- * deflated to allow the guest to use more physical memory.
- * Higher level policies can control the sizes of balloons in VMs
- * in order to manage physical memory resources.
+ * VMware physical memory management driver for Unix-ish
+ * (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like
+ * a "balloon" that can be inflated to reclaim physical pages by
+ * reserving them in the guest and invalidating them in the
+ * monitor, freeing up the underlying machine pages so they can
+ * be allocated to other guests. The balloon can also be
+ * deflated to allow the guest to use more physical memory.
+ * Higher level policies can control the sizes of balloons in VMs
+ * in order to manage physical memory resources.
*/
#ifdef __cplusplus
* Compile-Time Options
*/
-#define BALLOON_RATE_ADAPT (1)
+#define BALLOON_RATE_ADAPT (1)
-#define BALLOON_DEBUG (1)
-#define BALLOON_DEBUG_VERBOSE (0)
+#define BALLOON_DEBUG (1)
+#define BALLOON_DEBUG_VERBOSE (0)
-#define BALLOON_STATS
+#define BALLOON_STATS
#define BALLOON_STATS_PROCFS
/*
#define NULL 0
#endif
-#define BALLOON_NAME "vmmemctl"
-#define BALLOON_NAME_VERBOSE "VMware memory control driver"
+#define BALLOON_NAME "vmmemctl"
+#define BALLOON_NAME_VERBOSE "VMware memory control driver"
-#define BALLOON_PROTOCOL_VERSION (2)
+#define BALLOON_PROTOCOL_VERSION (2)
-#define BALLOON_CHUNK_PAGES (1000)
+#define BALLOON_CHUNK_PAGES (1000)
-#define BALLOON_NOSLEEP_ALLOC_MAX (16384)
+#define BALLOON_NOSLEEP_ALLOC_MAX (16384)
-#define BALLOON_RATE_ALLOC_MIN (512)
-#define BALLOON_RATE_ALLOC_MAX (2048)
-#define BALLOON_RATE_ALLOC_INC (16)
+#define BALLOON_RATE_ALLOC_MIN (512)
+#define BALLOON_RATE_ALLOC_MAX (2048)
+#define BALLOON_RATE_ALLOC_INC (16)
-#define BALLOON_RATE_FREE_MIN (512)
-#define BALLOON_RATE_FREE_MAX (16384)
-#define BALLOON_RATE_FREE_INC (16)
+#define BALLOON_RATE_FREE_MIN (512)
+#define BALLOON_RATE_FREE_MAX (16384)
+#define BALLOON_RATE_FREE_INC (16)
-#define BALLOON_ERROR_PAGES (16)
+#define BALLOON_ERROR_PAGES (16)
-/*
+/*
* When guest is under memory pressure, use a reduced page allocation
* rate for next several cycles.
*/
-#define SLOW_PAGE_ALLOCATION_CYCLES (4)
+#define SLOW_PAGE_ALLOCATION_CYCLES (4)
-/*
+/*
* Move it to bora/public/balloon_def.h later, if needed. Note that
* BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
* distinguishing page allocation failures from monitor-backdoor errors.
* We use value 1000 because all monitor-backdoor error codes are < 1000.
*/
-#define BALLOON_PAGE_ALLOC_FAILURE (1000)
+#define BALLOON_PAGE_ALLOC_FAILURE (1000)
// Maximum number of page allocations without yielding processor
#define BALLOON_ALLOC_YIELD_THRESHOLD (1024)
static int BalloonGuestType(void);
static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void BalloonPrimFreePage(unsigned long page);
+static void BalloonPrimFreePage(unsigned long page);
static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
static int Balloon_FreePage(Balloon *b, int monitorUnlock);
static void Balloon_StartTimer(Balloon *b);
static void Balloon_StopTimer(Balloon *b);
-static void CDECL Balloon_BH(void *data);
+static void BalloonTimerHandler(void *clientData);
static int Balloon_MonitorStart(Balloon *b);
static int Balloon_MonitorGuestType(Balloon *b);
* Macros
*/
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef BALLOON_STATS
-#define STATS_INC(stat) (stat)++
+#ifdef BALLOON_STATS
+#define STATS_INC(stat) (stat)++
#else
-#define STATS_INC(stat)
+#define STATS_INC(stat)
#endif
/*
* Macros to generate operations for simple lists of OBJ.
* OBJ must contain next and prev fields.
- *
*/
-#define GENERATE_LIST_INSERT(OBJ) \
-static void OBJ ## _Insert(OBJ **head, OBJ *obj) \
-{ \
- OBJ *h = *head; \
- \
- /* add element to head of list */ \
- obj->next = h; \
- if (h != NULL) { \
- h->prev = obj; \
- } \
- *head = obj; \
- obj->prev = NULL; \
+#define GENERATE_LIST_INSERT(OBJ) \
+static void OBJ ## _Insert(OBJ **head, OBJ *obj) \
+{ \
+ OBJ *h = *head; \
+ \
+ /* add element to head of list */ \
+ obj->next = h; \
+ if (h != NULL) { \
+ h->prev = obj; \
+ } \
+ *head = obj; \
+ obj->prev = NULL; \
}
-#define GENERATE_LIST_REMOVE(OBJ) \
-static void OBJ ## _Remove(OBJ **head, OBJ *obj) \
-{ \
- /* splice element out of list */ \
- if (obj->prev != NULL) { \
- obj->prev->next = obj->next; \
- } else { \
- *head = obj->next; \
- } \
- if (obj->next != NULL) { \
- obj->next->prev = obj->prev; \
- } \
+#define GENERATE_LIST_REMOVE(OBJ) \
+static void OBJ ## _Remove(OBJ **head, OBJ *obj) \
+{ \
+ /* splice element out of list */ \
+ if (obj->prev != NULL) { \
+ obj->prev->next = obj->next; \
+ } else { \
+ *head = obj->next; \
+ } \
+ if (obj->next != NULL) { \
+ obj->next->prev = obj->prev; \
+ } \
}
/*
* Procfs Operations
*/
+
/*
*----------------------------------------------------------------------
*
* BalloonProcRead --
*
* Ballon driver status reporting routine. Note that this is only
- * used for Linux.
+ * used for Linux.
*
* Results:
* Writes ASCII status information into "buf".
- * Returns number of bytes written.
+ * Returns number of bytes written.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
-static int CDECL
-BalloonProcRead(char *buf)
+
+static int
+BalloonProcRead(char *buf, // OUT
+ size_t size) // IN
{
int len = 0;
BalloonStats stats;
BalloonGetStats(&stats);
/* format size info */
- len += os_sprintf(buf + len,
+ len += OS_Snprintf(buf + len, size - len,
"target: %8d pages\n"
"current: %8d pages\n",
stats.nPagesTarget,
stats.nPages);
/* format rate info */
- len += os_sprintf(buf + len,
+ len += OS_Snprintf(buf + len, size - len,
"rateNoSleepAlloc: %8d pages/sec\n"
"rateSleepAlloc: %8d pages/sec\n"
"rateFree: %8d pages/sec\n",
stats.rateAlloc,
stats.rateFree);
-#ifdef BALLOON_STATS_PROCFS
- len += os_sprintf(buf + len,
+#ifdef BALLOON_STATS_PROCFS
+ len += OS_Snprintf(buf + len, size - len,
"\n"
"timer: %8u\n"
"start: %8u (%4u failed)\n"
stats.primErrorPageFree);
#endif
- return(len);
+ return len;
}
/*
* AddrToPPN --
*
* Return the physical page number corresponding to the specified
- * Linux kernel-mapped address.
+ * kernel-mapped address.
*
* Results:
* Returns PPN for "addr".
static inline unsigned long
AddrToPPN(unsigned long addr)
{
- return(os_addr_to_ppn(addr));
+ return OS_AddrToPPN(addr);
}
/*
*
* Attempts to allocate and reserve a physical page.
*
- * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- * The allocation can wait (sleep) for page writeout (swap)
- * by the guest.
- * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- * If allocation of a page requires disk writeout, then
- * just fail. DON'T sleep.
+ * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ * The allocation can wait (sleep) for page writeout (swap)
+ * by the guest.
+ * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ * If allocation of a page requires disk writeout, then
+ * just fail. DON'T sleep.
*
* Results:
* Returns the physical address of the allocated page, or 0 if error.
static unsigned long
BalloonPrimAllocPage(BalloonPageAllocType canSleep)
{
- return(os_alloc_reserved_page(canSleep));
+ return OS_AllocReservedPage(canSleep);
}
/*
static void
BalloonPrimFreePage(unsigned long page)
{
- return(os_free_reserved_page(page));
+ return OS_FreeReservedPage(page);
}
/*
* BalloonGuestType --
*
* Return balloon guest OS identifier obtained by parsing
- * system-dependent identity string.
+ * system-dependent identity string.
*
* Results:
* Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
static int
BalloonGuestType(void)
{
- char *identity;
+ const char *identity;
/* obtain OS identify string */
- identity = os_identity();
-
+ identity = OS_Identity();
+
/* unknown if not specified */
if (identity == NULL) {
return(BALLOON_GUEST_UNKNOWN);
switch (identity[0]) {
case 'l':
case 'L':
- return(BALLOON_GUEST_LINUX);
+ return BALLOON_GUEST_LINUX;
case 'b':
case 'B':
- return(BALLOON_GUEST_BSD);
+ return BALLOON_GUEST_BSD;
case 's':
case 'S':
- return(BALLOON_GUEST_SOLARIS);
+ return BALLOON_GUEST_SOLARIS;
default:
break;
}
/* unknown */
- return(BALLOON_GUEST_UNKNOWN);
+ return BALLOON_GUEST_UNKNOWN;
}
/*
/*
* Copy statistics out of global structure.
*/
- os_memcpy(stats, &b->stats, sizeof (BalloonStats));
+ OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
/*
* Fill in additional information about size and rates, which is
* BalloonChunk_Create --
*
* Creates a new BalloonChunk object capable of tracking
- * BALLOON_CHUNK_PAGES PPNs.
+ * BALLOON_CHUNK_PAGES PPNs.
*
- * We do not bother to define two versions (NOSLEEP and CANSLEEP)
- * of os_kmalloc because Chunk_Create does not require a new page
- * often.
+ * We do not bother to define two versions (NOSLEEP and CANSLEEP)
+ * of OS_Malloc because Chunk_Create does not require a new page
+ * often.
*
* Results:
- * Returns initialized BalloonChunk, or NULL if error.
+ * On success: initialized BalloonChunk
+ * On failure: NULL
*
* Side effects:
- * None.
+ * None
*
*----------------------------------------------------------------------
*/
+
static BalloonChunk *
BalloonChunk_Create(void)
{
BalloonChunk *chunk;
/* allocate memory, fail if unable */
- if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
- return(NULL);
+ chunk = OS_Malloc(sizeof *chunk);
+ if (chunk == NULL) {
+ return NULL;
}
/* initialize */
- os_bzero(chunk, sizeof(BalloonChunk));
+ OS_MemZero(chunk, sizeof *chunk);
/* everything OK */
- return(chunk);
+ return chunk;
}
+
/*
*----------------------------------------------------------------------
*
BalloonChunk_Destroy(BalloonChunk *chunk)
{
/* reclaim storage */
- os_kfree(chunk, sizeof (BalloonChunk));
+ OS_Free(chunk, sizeof *chunk);
}
/*
Balloon_Init(Balloon *b)
{
/* clear state */
- os_bzero(b, sizeof(Balloon));
+ OS_MemZero(b, sizeof *b);
/* initialize rates */
b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
(void) Balloon_FreePage(b, FALSE);
if (++cnt >= b->rateFree) {
cnt = 0;
- os_yield();
+ OS_Yield();
}
}
}
* Balloon_Reset --
*
* Resets balloon "b" to empty state. Frees all allocated pages
- * and attempts to reset contact with the monitor.
+ * and attempts to reset contact with the monitor.
*
* Results:
* None.
/*
*----------------------------------------------------------------------
*
- * Balloon_BH --
+ * BalloonTimerHandler --
*
* Balloon bottom half handler. Contacts monitor via backdoor
- * to obtain balloon size target, and starts adjusting balloon
- * size to achieve target by allocating or deallocating pages.
- * Resets balloon if requested by the monitor.
+ * to obtain balloon size target, and starts adjusting balloon
+ * size to achieve target by allocating or deallocating pages.
+ * Resets balloon if requested by the monitor.
*
* Results:
* None.
*
*----------------------------------------------------------------------
*/
-static void CDECL
-Balloon_BH(void *data)
+static void
+BalloonTimerHandler(void *clientData)
{
- Balloon *b = (Balloon *) data;
+ Balloon *b = (Balloon *) clientData;
uint32 target;
int status;
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
Balloon_StartTimer(Balloon *b)
{
- os_timer_start();
+ OS_TimerStart();
}
/*
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
Balloon_StopTimer(Balloon *b)
{
- os_timer_stop();
+ OS_TimerStop();
}
* Balloon_ErrorPagesAlloc --
*
* Attempt to add "page" to list of non-balloonable pages
- * associated with "b".
+ * associated with "b".
*
* Results:
- * Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
- * if non-balloonable page list is already full.
+ * On success: BALLOON_SUCCESS
+ * On failure: BALLOON_FAILURE (non-balloonable page list is already full)
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_ErrorPagesFree --
*
* Deallocates all pages on the list of non-balloonable pages
- * associated with "b".
+ * associated with "b".
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
/* free all non-balloonable "error" pages */
for (i = 0; i < b->errors.nextPage; i++) {
- BalloonPrimFreePage(b->errors.page[i]);
+ BalloonPrimFreePage(b->errors.page[i]);
b->errors.page[i] = 0;
STATS_INC(b->stats.primErrorPageFree);
}
* Balloon_AllocPage --
*
* Attempts to allocate a physical page, inflating balloon "b".
- * Informs monitor of PPN for allocated page via backdoor.
+ * Informs monitor of PPN for allocated page via backdoor.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_FreePage --
*
* Attempts to deallocate a physical page, deflating balloon "b".
- * Informs monitor of PPN for deallocated page via backdoor if
- * "monitorUnlock" is specified.
+ * Informs monitor of PPN for deallocated page via backdoor if
+ * "monitorUnlock" is specified.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* BalloonDecreaseRateAlloc --
*
- * Wrapper to quickly reduce the page allocation rate. This function
- * is called only when a CANSLEEP allocation fails. This implies severe
- * memory pressure inside the guest, so quickly decrease the rateAlloc.
+ * Wrapper to quickly reduce the page allocation rate. This function
+ * is called only when a CANSLEEP allocation fails. This implies severe
+ * memory pressure inside the guest, so quickly decrease the rateAlloc.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* BalloonIncreaseRateAlloc --
*
- * Wrapper to increase the page allocation rate.
+ * Wrapper to increase the page allocation rate.
*
- * This function is called when the balloon target is met or
- * b->rateAlloc (or more) pages have been successfully allocated.
- * This implies that the guest may not be under high memory
- * pressure. So let us increase the rateAlloc.
+ * This function is called when the balloon target is met or
+ * b->rateAlloc (or more) pages have been successfully allocated.
+ * This implies that the guest may not be under high memory
+ * pressure. So let us increase the rateAlloc.
*
- * If meeting balloon target requires less than b->rateAlloc
- * pages, then we do not change the page allocation rate.
+ * If meeting balloon target requires less than b->rateAlloc
+ * pages, then we do not change the page allocation rate.
*
- * If the number of pages successfully allocated (nAlloc) is far
- * higher than b->rateAlloc, then it implies that NOSLEEP
- * allocations are highly successful. Therefore, we predict that
- * the guest is under no memory pressure, and so increase
- * b->rateAlloc quickly.
+ * If the number of pages successfully allocated (nAlloc) is far
+ * higher than b->rateAlloc, then it implies that NOSLEEP
+ * allocations are highly successful. Therefore, we predict that
+ * the guest is under no memory pressure, and so increase
+ * b->rateAlloc quickly.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
{
if (BALLOON_RATE_ADAPT) {
if (nAlloc >= b->rateAlloc) {
- uint32 mult = nAlloc / b->rateAlloc;
+ uint32 mult = nAlloc / b->rateAlloc;
b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
BALLOON_RATE_ALLOC_MAX);
}
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
int status, allocations = 0;
uint32 i, nAllocNoSleep, nAllocCanSleep;
- /*
+ /*
* First try NOSLEEP page allocations to inflate balloon.
*
* If we do not throttle nosleep allocations, we can drain all
* As a side-effect, draining free pages helps to inform (force)
* the guest to start swapping if balloon target is not met yet,
* which is a desired behavior. However, balloon driver can consume
- * all available CPU cycles if too many pages are allocated in a
- * second. Therefore, we throttle nosleep allocations even when
- * the guest is not under memory pressure. OTOH, if we have already
- * predicted that the guest is under memory pressure, then we
+ * all available CPU cycles if too many pages are allocated in a
+ * second. Therefore, we throttle nosleep allocations even when
+ * the guest is not under memory pressure. OTOH, if we have already
+ * predicted that the guest is under memory pressure, then we
* slowdown page allocations considerably.
*/
if (b->slowPageAllocationCycles > 0) {
status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
if (status != BALLOON_SUCCESS) {
if (status != BALLOON_PAGE_ALLOC_FAILURE) {
- /*
+ /*
* Not a page allocation failure, so release non-balloonable
* pages, and fail.
*/
Balloon_ErrorPagesFree(b);
return(status);
}
- /*
- * NOSLEEP page allocation failed, so the guest is under memory
- * pressure. Let us slowdown page allocations for next few
+ /*
+ * NOSLEEP page allocation failed, so the guest is under memory
+ * pressure. Let us slowdown page allocations for next few
* cycles so that the guest gets out of memory pressure.
*/
b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
}
if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
- os_yield();
+ OS_Yield();
allocations = 0;
}
}
- /*
+ /*
* Check whether nosleep allocation successfully zapped nAllocNoSleep
* pages.
*/
Balloon_ErrorPagesFree(b);
return(BALLOON_SUCCESS);
} else {
- /*
+ /*
* NOSLEEP allocation failed, so the guest is under memory pressure.
* If already b->rateAlloc pages were zapped, then succeed. Otherwise,
* try CANSLEEP allocation.
}
}
- /*
+ /*
* Use CANSLEEP page allocation to inflate balloon if below target.
*
* Sleep allocations are required only when nosleep allocation fails.
* This implies that the guest is already under memory pressure, so
* let us always throttle canSleep allocations. The total number pages
- * allocated using noSleep and canSleep methods is throttled at
- * b->rateAlloc per second when the guest is under memory pressure.
+ * allocated using noSleep and canSleep methods is throttled at
+ * b->rateAlloc per second when the guest is under memory pressure.
*/
nAllocCanSleep = target - b->nPages;
nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
if(status != BALLOON_SUCCESS) {
if (status == BALLOON_PAGE_ALLOC_FAILURE) {
- /*
+ /*
* CANSLEEP page allocation failed, so guest is under severe
* memory pressure. Quickly decrease rateAlloc.
*/
}
if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
- os_yield();
+ OS_Yield();
allocations = 0;
}
}
- /*
+ /*
* Either met the balloon target or b->rateAlloc pages have been
* successfully zapped.
*/
BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
-
+
/* release non-balloonable pages, succeed */
Balloon_ErrorPagesFree(b);
return(BALLOON_SUCCESS);
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
{
int status, i;
uint32 nFree = b->nPages - target;
-
+
/* limit deallocation rate */
nFree = MIN(nFree, b->rateFree);
/* everything OK */
return(BALLOON_SUCCESS);
}
-
+
/*
*----------------------------------------------------------------------
*
* Balloon_AdjustSize --
*
* Attempts to allocate or deallocate physical pages in order
- * to reach desired "target" size for balloon "b".
+ * to reach desired "target" size for balloon "b".
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Attempts to contact monitor via backdoor to begin operation.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Attempts to contact monitor and report guest OS identity.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_MonitorGetTarget --
*
* Attempts to contact monitor via backdoor to obtain desired
- * balloon size.
+ * balloon size.
*
- * Predicts the maximum achievable balloon size and sends it
- * to vmm => vmkernel via vEbx register.
+ * Predicts the maximum achievable balloon size and sends it
+ * to vmm => vmkernel via vEbx register.
*
- * os_predict_max_balloon_pages() returns either predicted max balloon
- * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
- * vmkernel uses global config options for determining a guest's max
- * balloon size. Note that older vmballoon drivers set vEbx to
- * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
- * will fallback to config-based max balloon size estimation.
+ * OS_PredictMaxReservedPages() returns either predicted max balloon
+ * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
+ * vmkernel uses global config options for determining a guest's max
+ * balloon size. Note that older vmballoon drivers set vEbx to
+ * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
+ * will fallback to config-based max balloon size estimation.
*
* Results:
- * If successful, sets "target" to value obtained from monitor,
+ * If successful, sets "target" to value obtained from monitor,
* and returns BALLOON_SUCCESS. Otherwise returns error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
- bp.in.size = os_predict_max_balloon_pages();
+ bp.in.size = OS_PredictMaxReservedPages();
/* invoke backdoor */
Backdoor_Balloon(&bp);
*
* Balloon_MonitorLockPage --
*
- * Attempts to contact monitor and add PPN containing "addr"
- * to set of "balloon locked" pages.
+ * Attempts to contact monitor and add PPN containing "addr"
+ * to set of "balloon locked" pages.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* Balloon_MonitorUnlockPage --
*
- * Attempts to contact monitor and remove PPN containing "addr"
- * from set of "balloon locked" pages.
+ * Attempts to contact monitor and remove PPN containing "addr"
+ * from set of "balloon locked" pages.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
return(BALLOON_FAILURE);
}
+ /* os-specific initialization */
+ OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
+
/* initialize global state */
Balloon_Init(b);
- /* os-specific initialization */
- os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
- os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
-
/* start timer */
+ OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
Balloon_StartTimer(b);
/* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
static void
Balloon_Deallocate(b);
/* os-specific cleanup */
- os_cleanup();
-}
+ OS_Cleanup();
+}
int init_module(void)
{
#include <linux/if_arp.h>
#include <linux/inetdevice.h>
+#ifdef CONFIG_COMPAT
+#ifndef HAVE_UNLOCKED_IOCTL
+#include <linux/ioctl32.h>
+#endif
+#endif
+
#include "vm_basic_types.h"
#include "vmnet_def.h"
#include "vm_device_version.h"
static int enable_shm[VMXNET3_SHM_MAX_DEVICES + 1] =
{ [0 ... VMXNET3_SHM_MAX_DEVICES] = -1 };
static char *shm_disclaimer = NULL;
+static int correct_shm_disclaimer;
#define VMXNET3_SHM_DISCLAIMER "IReallyWantThisModeIAmAVMSafePartner"
/*
memcpy(tdd->data,
virt,
ctx->copy_size);
- kunmap(virt);
+ kunmap(VMXNET3_SHM_IDX2PAGE(adapter->shm, VMXNET3_SHM_SKB_GETIDX(skb)));
}
VMXNET3_LOG("copy %u bytes to dataRing[%u]\n",
ctx->copy_size, tq->tx_ring.next2fill);
*
* vmxnet3_rx_error --
*
- * called when ERR bit is set for a received pkt
+ * called when ERR bit is set for a received pkt. The desc and the associated
+ * rx buffer have not been processed yet.
*
* Result:
* none
*
* Side-effects:
* 1. up the stat counters
- * 2. free the pkt
+ * 2. free the skb if needed
* 3. reset ctx->skb
*
*----------------------------------------------------------------------------
}
rq->stats.drop_total++;
- vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb);
+ /*
+ * We do not unmap and chain the rx buffer to the skb.
+ * We basically pretend this buffer is not used and will be recycled
+ * by vmxnet3_rq_alloc_rx_buf()
+ */
+
+ /*
+ * ctx->skb may be NULL if this is the first and the only one
+ * desc for the pkt
+ */
+ if (ctx->skb) {
+ vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb);
+ }
ctx->skb = NULL;
}
VMXNET3_ASSERT(rcd->len <= rxd->len);
VMXNET3_ASSERT(rxd->addr == rbi->dma_addr && rxd->len == rbi->len);
+ if (UNLIKELY(rcd->eop && rcd->err)) {
+ vmxnet3_rx_error(rq, rcd, ctx, adapter);
+ goto rcd_done;
+ }
+
if (rcd->sop) { /* first buf of the pkt */
VMXNET3_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
rcd->rqID == rq->qid);
rbi->page = NULL;
}
} else {
- /* the only time a non-SOP buffer is type 0 is when it's EOP and
- * error flag is raised
+ /*
+ * The only time a non-SOP buffer is type 0 is when it's EOP and
+ * error flag is raised, which has already been handled.
*/
- if (UNLIKELY(rcd->err && rcd->eop)) {
- /* pretend this buffer is skipped by the device.
- * dont chain it and don't reset rbi->skb to NULL
- */
- VMXNET3_LOG("Err EOP is type 0 from ring[%u].rxd[%u]\n", ring_idx, idx);
- } else {
- /* bug in the device */
- VMXNET3_ASSERT(FALSE);
- }
+ VMXNET3_ASSERT(FALSE);
}
}
skb = ctx->skb;
if (rcd->eop) {
- if (UNLIKELY(rcd->err)) {
- vmxnet3_rx_error(rq, rcd, ctx, adapter);
- goto rcd_done;
- }
-
if (adapter->is_shm) {
vmxnet3_shm_rx_skb(adapter, skb);
*----------------------------------------------------------------------------
*/
-static int
+int
vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
{
int err;
*----------------------------------------------------------------------------
*/
-static int
+int
vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
{
if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state)) {
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 6)
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
- if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
printk(KERN_ERR "pci_set_consistent_dma_mask failed for adapter %s\n",
compat_pci_name(pdev));
err = -EIO;
}
*dma64 = TRUE;
} else {
- if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
printk(KERN_ERR "pci_set_dma_mask failed for adapter %s\n",
compat_pci_name(pdev));
err = -EIO;
*
*----------------------------------------------------------------------------
*/
-static void
+void
vmxnet3_force_close(struct vmxnet3_adapter *adapter)
{
/*
adapter->is_shm = FALSE;
if (adapter->dev_number < VMXNET3_SHM_MAX_DEVICES) {
if (enable_shm[adapter->dev_number] == 1) {
- if (shm_disclaimer == NULL ||
- strncmp(shm_disclaimer, VMXNET3_SHM_DISCLAIMER,
- strlen(VMXNET3_SHM_DISCLAIMER)) != 0) {
+ if (!correct_shm_disclaimer) {
printk(KERN_ERR "Did not activate shm, disclaimer missing\n");
} else {
adapter->is_shm = TRUE;
vmxnet3_init_module(void)
{
printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC, VMXNET3_DRIVER_VERSION_REPORT);
+
+ correct_shm_disclaimer = shm_disclaimer &&
+ (strncmp(shm_disclaimer, VMXNET3_SHM_DISCLAIMER, strlen(VMXNET3_SHM_DISCLAIMER)) == 0);
+
+#ifdef CONFIG_COMPAT
+#ifndef HAVE_UNLOCKED_IOCTL
+ if (correct_shm_disclaimer) {
+ register_ioctl32_conversion(SHM_IOCTL_TX, NULL);
+ register_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE, NULL);
+ register_ioctl32_conversion(SHM_IOCTL_ALLOC_MANY, NULL);
+ register_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE_AND_MANY, NULL);
+ register_ioctl32_conversion(SHM_IOCTL_FREE_ONE, NULL);
+ }
+#endif
+#endif
return pci_register_driver(&vmxnet3_driver);
}
static void
vmxnet3_exit_module(void)
{
+#ifdef CONFIG_COMPAT
+#ifndef HAVE_UNLOCKED_IOCTL
+ if (correct_shm_disclaimer) {
+ unregister_ioctl32_conversion(SHM_IOCTL_TX);
+ unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE);
+ unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_MANY);
+ unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE_AND_MANY);
+ unregister_ioctl32_conversion(SHM_IOCTL_FREE_ONE);
+ }
+#endif
+#endif
pci_unregister_driver(&vmxnet3_driver);
}
struct vmxnet3_adapter *adapter,
struct net_device *netdev);
+int
+vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter);
+
+int
+vmxnet3_activate_dev(struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_force_close(struct vmxnet3_adapter *adapter);
static unsigned int vmxnet3_shm_chardev_poll(struct file *filp,
poll_table *wait);
-static int vmxnet3_shm_chardev_ioctl(struct inode *inode,
- struct file *filp,
- unsigned int cmd,
- unsigned long arg);
+static long vmxnet3_shm_chardev_ioctl(struct file *filp,
+ unsigned int cmd,
+ unsigned long arg);
+
+#ifndef HAVE_UNLOCKED_IOCTL
+static int vmxnet3_shm_chardev_old_ioctl(struct inode *inode,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg);
+#endif
static struct file_operations shm_fops = {
.owner = THIS_MODULE,
.open = vmxnet3_shm_chardev_open,
.release = vmxnet3_shm_chardev_release,
.poll = vmxnet3_shm_chardev_poll,
- .ioctl = vmxnet3_shm_chardev_ioctl,
+#ifdef HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = vmxnet3_shm_chardev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vmxnet3_shm_chardev_ioctl,
+#endif
+#else
+ .ioctl = vmxnet3_shm_chardev_old_ioctl,
+#endif
};
static LIST_HEAD(vmxnet3_shm_list);
#endif
+/*
+ *----------------------------------------------------------------------------
+ *
+ * vmxnet3_shm_init_allocator --
+ *
+ * Zero all shared memory data pages and fill the allocator with them.
+ *
+ * Result:
+ * None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+vmxnet3_shm_init_allocator(struct vmxnet3_shm_pool *shm)
+{
+ int i;
+
+ shm->allocator.count = 0;
+ for (i = 1; i < shm->data.num_pages; i++) {
+ struct page *page = VMXNET3_SHM_IDX2PAGE(shm, i);
+ void *virt = kmap(page);
+ memset(virt, 0, PAGE_SIZE);
+ kunmap(page);
+
+ shm->allocator.stack[shm->allocator.count++] = i;
+
+ VMXNET3_ASSERT(i != SHM_INVALID_IDX);
+ }
+ VMXNET3_ASSERT(shm->allocator.count <= SHM_DATA_SIZE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmxnet3_shm_pool_reset --
+ *
+ * Clean up after userspace has closed the device
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmxnet3_shm_pool_reset(struct vmxnet3_shm_pool *shm)
+{
+ int err = 0;
+ printk(KERN_INFO "resetting shm pool\n");
+
+ /*
+ * Reset_work may be in the middle of resetting the device, wait for its
+ * completion.
+ */
+ while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &shm->adapter->state)) {
+ compat_msleep(1);
+ }
+
+ if (compat_netif_running(shm->adapter->netdev)) {
+ vmxnet3_quiesce_dev(shm->adapter);
+ }
+
+ vmxnet3_shm_init_allocator(shm);
+
+ if (compat_netif_running(shm->adapter->netdev)) {
+ err = vmxnet3_activate_dev(shm->adapter);
+ }
+
+ memset(shm->ctl.ptr, 0, PAGE_SIZE);
+
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &shm->adapter->state);
+
+ if (err) {
+ vmxnet3_force_close(shm->adapter);
+ }
+}
+
/*
*-----------------------------------------------------------------------------
*
// Allocate data pages
shm->data.num_pages = SHM_DATA_SIZE;
for (i = 1; i < shm->data.num_pages; i++) {
-#ifdef __GFP_ZERO
- struct page *page = alloc_page(GFP_KERNEL|__GFP_ZERO);
-#else
struct page *page = alloc_page(GFP_KERNEL);
-#endif
if (page == NULL) {
goto fail_data;
}
-#ifndef __GFP_ZERO
- {
- void *virt = kmap(page);
- memset(virt, 0, PAGE_SIZE);
- kunmap(virt);
- }
-#endif
-
VMXNET3_SHM_SET_IDX2PAGE(shm, i, page);
- shm->allocator.stack[shm->allocator.count++] = i;
VMXNET3_ASSERT(i != SHM_INVALID_IDX);
}
- VMXNET3_ASSERT(shm->allocator.count <= SHM_DATA_SIZE);
// Allocate control page
ctl_page = alloc_page(GFP_KERNEL);
goto fail_ctl;
}
ctl_ptr = (void*)kmap(ctl_page);
- memset(ctl_ptr, 0, PAGE_SIZE);
shm->ctl.pages[0] = ctl_page;
shm->ctl.ptr = ctl_ptr;
+ // Reset data and control pages
+ vmxnet3_shm_init_allocator(shm);
+ memset(shm->ctl.ptr, 0, PAGE_SIZE);
+
// Register char device
shm->misc_dev.minor = MISC_DYNAMIC_MINOR;
shm->misc_dev.name = shm->name;
// Free data pages
for (i = 1; i < SHM_DATA_SIZE; i++) {
- kunmap(VMXNET3_SHM_IDX2PAGE(shm,i));
__free_page(VMXNET3_SHM_IDX2PAGE(shm, i));
}
struct vmxnet3_shm_ringentry *re;
// consume TX queue
- vmxnet3_shm_consume_user_tx_queue(shm);
+ if (vmxnet3_shm_consume_user_tx_queue(shm) == -1) {
+ // the device has been closed, let the user space
+ // know there is activity, so that it gets a chance
+ // to read the channelBad flag.
+ mask |= POLLIN;
+ return mask;
+ }
// Wait on the rxq for an interrupt to wake us
poll_wait(filp, &shm->rxq, wait);
*-----------------------------------------------------------------------------
*/
-static int
-vmxnet3_shm_chardev_ioctl(struct inode *inode,
- struct file *filp,
+static long
+vmxnet3_shm_chardev_ioctl(struct file *filp,
unsigned int cmd,
unsigned long arg)
{
case SHM_IOCTL_ALLOC_ONE:
idx = vmxnet3_shm_alloc_page(shm);
- if (idx != SHM_INVALID_IDX) {
- return idx;
- } else {
- return -ENOMEM;
- }
+ return idx;
case SHM_IOCTL_ALLOC_MANY:
for (i = 0; i < arg; i++) {
if (idx != SHM_INVALID_IDX) {
if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) {
vmxnet3_shm_free_page(shm, idx);
- return -ENOMEM;
+ return SHM_INVALID_IDX;
}
} else {
- return -ENOMEM;
+ return SHM_INVALID_IDX;
}
}
return 0;
case SHM_IOCTL_ALLOC_ONE_AND_MANY:
idx1 = vmxnet3_shm_alloc_page(shm);
if (idx1 == SHM_INVALID_IDX) {
- return -ENOMEM;
+ return SHM_INVALID_IDX;
}
for (i = 0; i < arg - 1; i++) {
idx = vmxnet3_shm_alloc_page(shm);
if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) {
vmxnet3_shm_free_page(shm, idx);
vmxnet3_shm_free_page(shm, idx1);
- return -ENOMEM;
+ return SHM_INVALID_IDX;
}
} else {
vmxnet3_shm_free_page(shm, idx1);
- return -ENOMEM;
+ return SHM_INVALID_IDX;
}
}
return idx1;
return -ENOTTY;
}
+#ifndef HAVE_UNLOCKED_IOCTL
+static int vmxnet3_shm_chardev_old_ioctl(struct inode *inode,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ return vmxnet3_shm_chardev_ioctl(filp, cmd, arg);
+}
+#endif
/*
*-----------------------------------------------------------------------------
struct file * filp)
{
struct vmxnet3_shm_pool *shm = filp->private_data;
- kobject_put(&shm->kobj);
- // XXX: I guess we should reset the control pages here
+ if (shm->adapter) {
+ vmxnet3_shm_pool_reset(shm);
+ } else {
+ vmxnet3_shm_init_allocator(shm);
+ memset(shm->ctl.ptr, 0, PAGE_SIZE);
+ }
+
+ kobject_put(&shm->kobj);
return 0;
}
skb = dev_alloc_skb(100);
if (skb == NULL) {
+ for (i = 0; i < frags; i++) {
+ vmxnet3_shm_free_page(adapter->shm, res[i].idx);
+ }
VMXNET3_ASSERT(FALSE);
return -ENOMEM;
}
vmxnet3_shm_tx_re(struct vmxnet3_shm_pool *shm,
struct vmxnet3_shm_ringentry re)
{
- int i;
-
shm->partial_tx.res[shm->partial_tx.frags++] = re;
if (re.eop) {
shm->partial_tx.res,
shm->partial_tx.frags);
if (status < 0) {
- for (i = 0; i < shm->partial_tx.frags; i++) {
- vmxnet3_shm_free_page(shm, shm->partial_tx.res[i].idx);
- }
+ VMXNET3_LOG("vmxnet3_shm_tx_pkt failed %d\n", status);
}
shm->partial_tx.frags = 0;
return 1;
adapter->shm->adapter = NULL;
spin_unlock_irqrestore(&adapter->shm->tx_lock, flags);
+ // Mark the channel as 'in bad state'
+ adapter->shm->ctl.ptr->channelBad = 1;
+
kobject_put(&adapter->shm->kobj);
+
+ wake_up(&adapter->shm->rxq);
+
return 0;
}
#define SHM_CTL_SIZE 1
// ring size (in entries) is limited by the single control page - 4 bytes per re
-#define SHM_RX_RING_SIZE 507
-#define SHM_TX_RING_SIZE 507
+#define SHM_RX_RING_SIZE 500
+#define SHM_TX_RING_SIZE 500
// maximum fragments per packet is 16 (64k) + 2 for metadata
#define VMXNET3_SHM_MAX_FRAGS 18
uint64_t user_rx, user_tx;
uint64_t kernel_rx, kernel_tx;
} stats;
+
+ uint64_t channelBad;
};
#endif
#ifndef _VMXNET3_VERSION_H_
#define _VMXNET3_VERSION_H_
-#define VMXNET3_DRIVER_VERSION 1.0.1.0
-#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,1,0
-#define VMXNET3_DRIVER_VERSION_STRING "1.0.1.0"
+#define VMXNET3_DRIVER_VERSION 1.0.3.0
+#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,3,0
+#define VMXNET3_DRIVER_VERSION_STRING "1.0.3.0"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01000100
+#define VMXNET3_DRIVER_VERSION_NUM 0x01000300
#endif /* _VMXNET3_VERSION_H_ */
#include <linux/poll.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
-# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
-# include <asm/ioctl32.h>
-# else
-# include <linux/ioctl32.h>
-# endif
+# include <linux/ioctl32.h>
/* Use weak: not all kernels export sys_ioctl for use by modules */
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
asmlinkage __attribute__((weak)) long
sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-# else
-asmlinkage __attribute__((weak)) int
-sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-# endif
#endif
#include "compat_module.h"
#include "vsock_version.h"
#include "driverLog.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
+# error "Linux kernels before 2.6.9 are not supported."
+#endif
#define VSOCK_INVALID_FAMILY NPROTO
#define VSOCK_AF_IS_REGISTERED(val) ((val) >= 0 && (val) < NPROTO)
int VSockVmci_GetAFValue(void);
/* Internal functions. */
+static Bool VSockVmciProtoToNotifyStruct(struct sock *sk,
+ VSockProtoVersion *proto,
+ Bool oldPktProto);
static int VSockVmciGetAFValue(void);
static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg);
static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg);
static int VSockVmciRecvConnectingClient(struct sock *sk, VSockPacket *pkt);
static int VSockVmciRecvConnectingClientNegotiate(struct sock *sk,
VSockPacket *pkt);
+static int VSockVmciRecvConnectingClientInvalid(struct sock *sk,
+ VSockPacket *pkt);
static int VSockVmciRecvConnected(struct sock *sk, VSockPacket *pkt);
static int __VSockVmciBind(struct sock *sk, struct sockaddr_vm *addr);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
static int VSockVmciStreamGetsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user * optlen);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int VSockVmciDgramSendmsg(struct socket *sock, struct msghdr *msg,
- int len, struct scm_cookie *scm);
-static int VSockVmciDgramRecvmsg(struct socket *sock, struct msghdr *msg,
- int len, int flags, struct scm_cookie *scm);
-static int VSockVmciStreamSendmsg(struct socket *sock, struct msghdr *msg,
- int len, struct scm_cookie *scm);
-static int VSockVmciStreamRecvmsg(struct socket *sock, struct msghdr *msg,
- int len, int flags, struct scm_cookie *scm);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int VSockVmciDgramSendmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, int len,
- struct scm_cookie *scm);
-static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, int len,
- int flags, struct scm_cookie *scm);
-static int VSockVmciStreamSendmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, int len,
- struct scm_cookie *scm);
-static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, int len,
- int flags, struct scm_cookie *scm);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int VSockVmciDgramSendmsg(struct kiocb *kiocb,
- struct socket *sock, struct msghdr *msg, int len);
-static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, int len, int flags);
-static int VSockVmciStreamSendmsg(struct kiocb *kiocb,
- struct socket *sock, struct msghdr *msg, int len);
-static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, int len, int flags);
-#else
static int VSockVmciDgramSendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, size_t len);
static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct socket *sock, struct msghdr *msg, size_t len);
static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags);
-#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
static int VSockVmciCreate(struct socket *sock, int protocol);
* Variables.
*/
-/* Protocol family. We only use this for builds against 2.6.9 and later. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
+/* Protocol family. */
static struct proto vsockVmciProto = {
.name = "AF_VMCI",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
.owner = THIS_MODULE,
#endif
/*
- * Before 2.6.9, each address family created their own slab (by calling
- * kmem_cache_create() directly). From 2.6.9 until 2.6.11, these address
- * families instead called sk_alloc_slab() and the allocated slab was
- * assigned to the slab variable in the proto struct and was created of size
- * slab_obj_size. As of 2.6.12 and later, this slab allocation was moved
- * into proto_register() and only done if you specified a non-zero value for
+ * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab()
+ * and the allocated slab was assigned to the slab variable in the proto
+ * struct and was created of size slab_obj_size.
+ * As of 2.6.12 and later, this slab allocation was moved into
+ * proto_register() and only done if you specified a non-zero value for
* the second argument (alloc_slab); the size of the slab element was
* changed to obj_size.
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
.slab_obj_size = sizeof (VSockVmciSock),
#else
.obj_size = sizeof (VSockVmciSock),
#endif
};
-#endif
static struct net_proto_family vsockVmciFamilyOps = {
.family = VSOCK_INVALID_FAMILY,
.create = VSockVmciCreate,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
.owner = THIS_MODULE,
-#endif
};
/* Socket operations, split for DGRAM and STREAM sockets. */
static struct proto_ops vsockVmciDgramOps = {
.family = VSOCK_INVALID_FAMILY,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
.owner = THIS_MODULE,
-#endif
.release = VSockVmciRelease,
.bind = VSockVmciBind,
.connect = VSockVmciDgramConnect,
.sendmsg = VSockVmciDgramSendmsg,
.recvmsg = VSockVmciDgramRecvmsg,
.mmap = sock_no_mmap,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4)
.sendpage = sock_no_sendpage,
-#endif
};
static struct proto_ops vsockVmciStreamOps = {
.family = VSOCK_INVALID_FAMILY,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
.owner = THIS_MODULE,
-#endif
.release = VSockVmciRelease,
.bind = VSockVmciBind,
.connect = VSockVmciStreamConnect,
.sendmsg = VSockVmciStreamSendmsg,
.recvmsg = VSockVmciStreamRecvmsg,
.mmap = sock_no_mmap,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4)
.sendpage = sock_no_sendpage,
-#endif
};
static struct file_operations vsockVmciDeviceOps = {
static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID };
static VMCIId qpResumedSubId = VMCI_INVALID_ID;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
-kmem_cache_t *vsockCachep;
-#endif
-#endif
+static int protocolOverride = -1;
/*
* 64k is hopefully a reasonable default, but we should do some real
#endif
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciOldProtoOverride --
+ *
+ * Check to see if the user has asked us to override all sockets to use
+ * the vsock notify protocol.
+ *
+ * Results:
+ * TRUE if there is a protocol override in effect.
+ * - oldPktProto is TRUE the original protocol should be used.
+ * FALSE if there is no override in effect.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VSockVmciOldProtoOverride(Bool *oldPktProto) // IN
+{
+ ASSERT(oldPktProto);
+
+ if (protocolOverride != -1) {
+ if (protocolOverride == 0) {
+ *oldPktProto = TRUE;
+ } else {
+ *oldPktProto = FALSE;
+ }
+ Warning("Proto override in use.\n");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciProtoToNotifyStruct --
+ *
+ * Given a particular notify protocol version, setup the socket's notify
+ * struct correctly.
+ *
+ * Results:
+ * TRUE on success. FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VSockVmciProtoToNotifyStruct(struct sock *sk, // IN
+ VSockProtoVersion *proto, // IN
+ Bool oldPktProto) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+ ASSERT(proto);
+
+ vsk = vsock_sk(sk);
+
+ if (oldPktProto) {
+ if (*proto != VSOCK_PROTO_INVALID) {
+ Warning("Can't set both an old and new protocol\n");
+ return FALSE;
+ }
+ vsk->notifyOps = &vSockVmciNotifyPktOps;
+ goto exit;
+ }
+
+ switch(*proto) {
+ case VSOCK_PROTO_PKT_ON_NOTIFY:
+ vsk->notifyOps= &vSockVmciNotifyPktQStateOps;
+ break;
+ default:
+ Warning("Unknown notify protocol version\n");
+ return FALSE;
+ }
+
+exit:
+ NOTIFYCALL(vsk, socketInit, sk);
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNewProtoSupportedVersions
+ *
+ * Gets the supported REQUEST2/NEGOTIATE2 vsock protocol versions.
+ *
+ * Results:
+ * Either 1 specific protocol version (override mode) or
+ * VSOCK_PROTO_ALL_SUPPORTED.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static VSockProtoVersion
+VSockVmciNewProtoSupportedVersions(void) // IN
+{
+ if (protocolOverride != -1) {
+ return protocolOverride;
+ }
+
+ return VSOCK_PROTO_ALL_SUPPORTED;
+}
+
+
/*
*----------------------------------------------------------------------------
*
* when implementing backwards compatibility in the future.
*/
if (pkt->type >= VSOCK_PACKET_TYPE_MAX) {
- if (VSOCK_SEND_INVALID_BH(&dst, &src) < 0) {
- Warning("unable to send reply for invalid packet.\n");
- err = VMCI_ERROR_INVALID_ARGS;
- goto out;
- }
+ VSOCK_SEND_INVALID_BH(&dst, &src);
+ err = VMCI_ERROR_INVALID_ARGS;
+ goto out;
}
/*
* receive, but we can still receive if there is data left in our consume
* queue.
*/
- sk->compat_sk_shutdown |= SEND_SHUTDOWN;
if (VSockVmciStreamHasData(vsk) <= 0) {
- sk->compat_sk_shutdown |= RCV_SHUTDOWN;
sk->compat_sk_state = SS_UNCONNECTED;
}
sk->compat_sk_state_change(sk);
VSockVmciSock *vpending;
int err;
uint64 qpSize;
+ Bool oldRequest = FALSE;
+ Bool oldPktProto = FALSE;
ASSERT(sk);
ASSERT(pkt);
* The listen state only accepts connection requests. Reply with a reset
* unless we received a reset.
*/
- if (pkt->type != VSOCK_PACKET_TYPE_REQUEST ||
- pkt->u.size == 0) {
- VSOCK_REPLY_RESET(pkt);
- return -EINVAL;
+
+ if (!(pkt->type == VSOCK_PACKET_TYPE_REQUEST ||
+ pkt->type == VSOCK_PACKET_TYPE_REQUEST2)) {
+ VSOCK_REPLY_RESET(pkt);
+ return -EINVAL;
+ }
+
+ if (pkt->u.size == 0) {
+ VSOCK_REPLY_RESET(pkt);
+ return -EINVAL;
}
/*
* it. Otherwise propose our own size.
*/
if (pkt->u.size >= vsk->queuePairMinSize &&
- pkt->u.size <= vsk->queuePairMaxSize) {
+ pkt->u.size <= vsk->queuePairMaxSize) {
qpSize = pkt->u.size;
} else {
qpSize = vsk->queuePairSize;
}
- err = VSOCK_SEND_NEGOTIATE(pending, qpSize);
+ /*
+ * Figure out if we are using old or new requests based on the overrides
+ * pkt types sent by our peer.
+ */
+ if (VSockVmciOldProtoOverride(&oldPktProto)) {
+ oldRequest = oldPktProto;
+ } else {
+ if (pkt->type == VSOCK_PACKET_TYPE_REQUEST) {
+ oldRequest = TRUE;
+ } else if (pkt->type == VSOCK_PACKET_TYPE_REQUEST2) {
+ oldRequest = FALSE;
+ }
+ }
+
+ if (oldRequest) {
+ /* Handle a REQUEST (or override) */
+ VSockProtoVersion version = VSOCK_PROTO_INVALID;
+ if (VSockVmciProtoToNotifyStruct(pending, &version, TRUE)) {
+ err = VSOCK_SEND_NEGOTIATE(pending, qpSize);
+ } else {
+ err = -EINVAL;
+ }
+ } else {
+ /* Handle a REQUEST2 (or override) */
+ int protoInt = pkt->proto;
+ int pos;
+ uint16 activeProtoVersion = 0;
+
+ /*
+ * The list of possible protocols is the intersection of all protocols
+ * the client supports ... plus all the protocols we support.
+ */
+ protoInt &= VSockVmciNewProtoSupportedVersions();
+
+ /* We choose the highest possible protocol version and use that one. */
+ pos = fls(protoInt);
+ if (pos) {
+ activeProtoVersion = (1 << (pos - 1));
+ if (VSockVmciProtoToNotifyStruct(pending, &activeProtoVersion, FALSE)) {
+ err = VSOCK_SEND_NEGOTIATE2(pending, qpSize,
+ activeProtoVersion);
+ } else {
+ err = -EINVAL;
+ }
+ } else {
+ err = -EINVAL;
+ }
+ }
+
if (err < 0) {
VSOCK_SEND_RESET(sk, pkt);
sock_put(pending);
pending->compat_sk_state = SS_CONNECTING;
vpending->produceSize = vpending->consumeSize = qpSize;
- /* XXX Move this into the notify file. */
- vpending->notify.writeNotifyWindow = qpSize;
+ NOTIFYCALL(vpending, processRequest, pending);
/*
* We might never receive another message for this socket and it's not
sk->compat_sk_socket->state = SS_CONNECTED;
VSockVmciInsertConnected(vsockConnectedSocketsVsk(vsk), sk);
sk->compat_sk_state_change(sk);
+
break;
case VSOCK_PACKET_TYPE_NEGOTIATE:
+ case VSOCK_PACKET_TYPE_NEGOTIATE2:
if (pkt->u.size == 0 ||
VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src) != vsk->remoteAddr.svm_cid ||
pkt->srcPort != vsk->remoteAddr.svm_port ||
goto destroy;
}
+ break;
+ case VSOCK_PACKET_TYPE_INVALID:
+ err = VSockVmciRecvConnectingClientInvalid(sk, pkt);
+ if (err) {
+ skerr = -err;
+ goto destroy;
+ }
+
break;
case VSOCK_PACKET_TYPE_RST:
- skerr = ECONNRESET;
- err = 0;
- goto destroy;
+ /*
+ * Older versions of the linux code (WS 6.5 / ESX 4.0) used to continue
+ * processing here after they sent an INVALID packet. This meant that we
+ * got a RST after the INVALID. We ignore a RST after an INVALID. The
+ * common code doesn't send the RST ... so we can hang if an old version
+ * of the common code fails between getting a REQUEST and sending an
+ * OFFER back. Not much we can do about it... except hope that it
+ * doesn't happen.
+ */
+ if (vsk->ignoreConnectingRst) {
+ vsk->ignoreConnectingRst = FALSE;
+ } else {
+ skerr = ECONNRESET;
+ err = 0;
+ goto destroy;
+ }
+
+ break;
default:
/* Close and cleanup the connection. */
skerr = EPROTO;
}
ASSERT(pkt->type == VSOCK_PACKET_TYPE_ATTACH ||
- pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE);
+ pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE ||
+ pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2 ||
+ pkt->type == VSOCK_PACKET_TYPE_INVALID ||
+ pkt->type == VSOCK_PACKET_TYPE_RST);
return 0;
VMCIId attachSubId;
VMCIId detachSubId;
Bool isLocal;
+ uint32 flags;
+ Bool oldProto = TRUE;
+ Bool oldPktProto;
+ VSockProtoVersion version;
vsk = vsock_sk(sk);
handle = VMCI_INVALID_HANDLE;
ASSERT(vsk->attachSubId == VMCI_INVALID_ID);
ASSERT(vsk->detachSubId == VMCI_INVALID_ID);
+ /*
+ * If we have gotten here then we should be past the point where old linux
+ * vsock could have sent the bogus rst.
+ */
+ vsk->sentRequest = FALSE;
+ vsk->ignoreConnectingRst = FALSE;
+
/* Verify that we're OK with the proposed queue pair size */
if (pkt->u.size < vsk->queuePairMinSize ||
pkt->u.size > vsk->queuePairMaxSize) {
goto destroy;
}
+ /*
+ * Setup the notify ops to be the highest supported version that both the
+ * server and the client support.
+ */
+
+ if (VSockVmciOldProtoOverride(&oldPktProto)) {
+ oldProto = oldPktProto;
+ } else {
+ if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE) {
+ oldProto = TRUE;
+ } else if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2) {
+ oldProto = FALSE;
+ }
+ }
+
+ if (oldProto) {
+ version = VSOCK_PROTO_INVALID;
+ } else {
+ version = pkt->proto;
+ }
+
+ if (!VSockVmciProtoToNotifyStruct(sk, &version, oldProto)) {
+ err = -EINVAL;
+ goto destroy;
+ }
+
/*
* Subscribe to attach and detach events first.
*
/* Make VMCI select the handle for us. */
handle = VMCI_INVALID_HANDLE;
isLocal = vsk->remoteAddr.svm_cid == vsk->localAddr.svm_cid;
+ flags = isLocal ? VMCI_QPFLAG_LOCAL : 0;
err = VSockVmciQueuePairAlloc(&handle,
&produceQ, pkt->u.size,
&consumeQ, pkt->u.size,
vsk->remoteAddr.svm_cid,
- isLocal ? VMCI_QPFLAG_LOCAL : 0,
+ flags,
vsk->trusted);
if (err < 0) {
goto destroy;
vsk->produceSize = vsk->consumeSize = pkt->u.size;
- /* XXX Move this into the notify file. */
- vsk->notify.writeNotifyWindow = pkt->u.size;
-
vsk->attachSubId = attachSubId;
vsk->detachSubId = detachSubId;
+ NOTIFYCALL(vsk, processNegotiate, sk);
+
return 0;
destroy:
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciRecvConnectingClientInvalid --
+ *
+ * Handles an invalid packet for a client in the connecting state.
+ *
+ * Note that this assumes the socket lock is held for both sk and pending.
+ *
+ * Results:
+ * Zero on success, negative error code on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VSockVmciRecvConnectingClientInvalid(struct sock *sk, // IN: socket
+ VSockPacket *pkt) // IN: current packet
+{
+ int err = 0;
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+ ASSERT(pkt);
+
+ vsk = vsock_sk(sk);
+
+ if (vsk->sentRequest) {
+ vsk->sentRequest = FALSE;
+ vsk->ignoreConnectingRst = TRUE;
+
+ err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize);
+ if (err < 0) {
+ err = VSockVmci_ErrorToVSockError(err);
+ } else {
+ err = 0;
+ }
+ }
+
+ return err;
+}
+
+
/*
*----------------------------------------------------------------------------
*
switch (pkt->type) {
case VSOCK_PACKET_TYPE_SHUTDOWN:
if (pkt->u.mode) {
- VSockVmciSock *vsk = vsock_sk(sk);
+ vsk = vsock_sk(sk);
vsk->peerShutdown |= pkt->u.mode;
sk->compat_sk_state_change(sk);
*/
compat_sock_set_done(sk);
vsk->peerShutdown = SHUTDOWN_MASK;
- sk->compat_sk_shutdown |= SEND_SHUTDOWN;
if (VSockVmciStreamHasData(vsk) <= 0) {
sk->compat_sk_state = SS_DISCONNECTING;
- sk->compat_sk_shutdown = SHUTDOWN_MASK;
}
sk->compat_sk_state_change(sk);
break;
uint64 size, // IN
uint64 mode, // IN
VSockWaitingInfo *wait, // IN
+ VSockProtoVersion proto, // IN
VMCIHandle handle, // IN
Bool convertError) // IN
{
VSOCK_ADDR_NOFAMILY_ASSERT(src);
VSOCK_ADDR_NOFAMILY_ASSERT(dst);
- VSockPacket_Init(pkt, src, dst, type, size, mode, wait, handle);
+ VSockPacket_Init(pkt, src, dst, type, size, mode, wait, proto, handle);
LOG_PACKET(pkt);
VSOCK_STATS_CTLPKT_LOG(pkt->type);
err = VMCIDatagram_Send(&pkt->dg);
} else {
VSockPacket_GetAddresses(pkt, &src, &dst);
return __VSockVmciSendControlPkt(&reply, &src, &dst, type,
- size, mode, wait, handle, TRUE);
+ size, mode, wait,
+ VSOCK_PROTO_INVALID, handle, TRUE);
}
}
static VSockPacket pkt;
return __VSockVmciSendControlPkt(&pkt, src, dst, type,
- size, mode, wait, handle, FALSE);
+ size, mode, wait, VSOCK_PROTO_INVALID,
+ handle, FALSE);
}
*/
int
-VSockVmciSendControlPkt(struct sock *sk, // IN
- VSockPacketType type, // IN
- uint64 size, // IN
- uint64 mode, // IN
- VSockWaitingInfo *wait, // IN
- VMCIHandle handle) // IN
+VSockVmciSendControlPkt(struct sock *sk, // IN
+ VSockPacketType type, // IN
+ uint64 size, // IN
+ uint64 mode, // IN
+ VSockWaitingInfo *wait, // IN
+ VSockProtoVersion proto, // IN
+ VMCIHandle handle) // IN
{
VSockPacket *pkt;
VSockVmciSock *vsk;
}
err = __VSockVmciSendControlPkt(pkt, &vsk->localAddr, &vsk->remoteAddr,
- type, size, mode, wait, handle, TRUE);
+ type, size, mode, wait, proto, handle,
+ TRUE);
kfree(pkt);
return err;
goto out;
}
- VSockAddr_Init(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port);
+ /*
+ * VSockVmci_GetAFValue() acquires a mutex and may sleep, so fill the
+ * field after unlocking socket tables.
+ */
+ VSockAddr_InitNoFamily(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port);
/*
* Remove stream sockets from the unbound list and add them to the hash
if (sk->compat_sk_socket->type == SOCK_STREAM) {
__VSockVmciRemoveBound(sk);
__VSockVmciInsertBound(vsockBoundSockets(&vsk->localAddr), sk);
+ spin_unlock_bh(&vsockTableLock);
}
+ vsk->localAddr.svm_family = VSockVmci_GetAFValue();
+ VSOCK_ADDR_ASSERT(&vsk->localAddr);
- err = 0;
+ return 0;
out:
if (sk->compat_sk_socket->type == SOCK_STREAM) {
vsk = NULL;
/*
- * Before 2.5.5, sk_alloc() always used its own cache and protocol-specific
- * data was contained in the protinfo union. We cannot use those other
- * structures so we allocate our own structure and attach it to the
- * user_data pointer that we don't otherwise need. We must be sure to free
- * it later in our destruct routine.
- *
- * From 2.5.5 until 2.6.8, sk_alloc() offerred to use a cache that the
- * caller provided. After this, the cache was moved into the proto
- * structure, but you still had to specify the size and cache yourself until
- * 2.6.12. Most recently (in 2.6.24), sk_alloc() was changed to expect the
+ * From 2.6.9 to until 2.6.12 sk_alloc() used a cache in
+ * the protocol structure, but you still had to specify the size and cache
+ * yourself.
+ * Most recently (in 2.6.24), sk_alloc() was changed to expect the
* network namespace, and the option to zero the sock was dropped.
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
- sk = sk_alloc(vsockVmciFamilyOps.family, priority, 1);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
- sk = sk_alloc(vsockVmciFamilyOps.family, priority,
- sizeof (VSockVmciSock), vsockCachep);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
sk = sk_alloc(vsockVmciFamilyOps.family, priority,
vsockVmciProto.slab_obj_size, vsockVmciProto.slab);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
return NULL;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
- vsock_sk(sk) = kmalloc(sizeof *vsk, priority);
- if (!vsock_sk(sk)) {
- sk_free(sk);
- return NULL;
- }
- sk_vsock(vsock_sk(sk)) = sk;
-#endif
-
/*
* If we go this far, we know the socket family is registered, so there's no
* need to register it now.
INIT_LIST_HEAD(&vsk->pendingLinks);
INIT_LIST_HEAD(&vsk->acceptQueue);
vsk->rejected = FALSE;
+ vsk->sentRequest = FALSE;
+ vsk->ignoreConnectingRst = FALSE;
vsk->attachSubId = vsk->detachSubId = VMCI_INVALID_ID;
vsk->peerShutdown = 0;
vsk->trusted = capable(CAP_NET_ADMIN);
}
- vsk->notifyOps = &vSockVmciNotifyPktOps;
- NOTIFYCALL(vsk, socketInit, sk);
+ vsk->notifyOps = NULL;
if (sock) {
VSockVmciInsertBound(vsockUnboundSockets, sk);
NOTIFYCALL(vsk, socketDestruct, sk);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
- ASSERT(vsock_sk(sk) == vsk);
- kfree(vsock_sk(sk));
-#endif
-
down(®istrationMutex);
vsockVmciSocketCount--;
VSockVmciTestUnregister();
VSOCK_STATS_CTLPKT_DUMP_ALL();
VSOCK_STATS_HIST_DUMP_ALL();
-
}
int err = 0;
/*
- * Before 2.6.9, each address family created their own slab (by calling
- * kmem_cache_create() directly). From 2.6.9 until 2.6.11, these address
- * families instead called sk_alloc_slab() and the allocated slab was
- * assigned to the slab variable in the proto struct and was created of size
- * slab_obj_size. As of 2.6.12 and later, this slab allocation was moved
- * into proto_register() and only done if you specified a non-zero value for
- * the second argument (alloc_slab); the size of the slab element was
+ * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab()
+ * and the allocated slab was assigned to the slab variable in the proto
+ * struct and was created of size slab_obj_size. As of 2.6.12 and later,
+ * this slab allocation was moved
+ * into proto_register() and only done if you specified a non-zero value
+ * for the second argument (alloc_slab); the size of the slab element was
* changed to obj_size.
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
- /* Simply here for clarity and so else case at end implies > rest. */
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
- vsockCachep = kmem_cache_create("vsock", sizeof (VSockVmciSock),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (!vsockCachep) {
- err = -ENOMEM;
- }
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
err = sk_alloc_slab(&vsockVmciProto, "vsock");
if (err != 0) {
sk_alloc_slab_error(&vsockVmciProto);
static void
VSockVmciUnregisterProto(void)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
- /* Simply here for clarity and so else case at end implies > rest. */
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
- kmem_cache_destroy(vsockCachep);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
sk_free_slab(&vsockVmciProto);
#else
proto_unregister(&vsockVmciProto);
VSockVmciSock *vsk;
struct sockaddr_vm *remoteAddr;
long timeout;
+ Bool oldPktProto = FALSE;
COMPAT_DEFINE_WAIT(wait);
err = 0;
sk->compat_sk_state = SS_CONNECTING;
- err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize);
- if (err < 0) {
- sk->compat_sk_state = SS_UNCONNECTED;
- goto out;
+ if (VSockVmciOldProtoOverride(&oldPktProto) && oldPktProto) {
+ err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize);
+ if (err < 0) {
+ sk->compat_sk_state = SS_UNCONNECTED;
+ goto out;
+ }
+ } else {
+ int supportedProtoVersions = VSockVmciNewProtoSupportedVersions();
+ err = VSOCK_SEND_CONN_REQUEST2(sk, vsk->queuePairSize,
+ supportedProtoVersions);
+ if (err < 0) {
+ sk->compat_sk_state = SS_UNCONNECTED;
+ goto out;
+ }
+
+ vsk->sentRequest = TRUE;
}
/*
mask |= POLLERR;
}
- if (sk->compat_sk_shutdown == SHUTDOWN_MASK) {
+ /*
+ * INET sockets treat local write shutdown and peer write shutdown
+ * as a case of POLLHUP set.
+ */
+ if ((sk->compat_sk_shutdown == SHUTDOWN_MASK) ||
+ ((sk->compat_sk_shutdown & SEND_SHUTDOWN) &&
+ (vsk->peerShutdown & SEND_SHUTDOWN))) {
mask |= POLLHUP;
}
/* POLLRDHUP wasn't added until 2.6.17. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
- if (sk->compat_sk_shutdown & RCV_SHUTDOWN) {
+ if (sk->compat_sk_shutdown & RCV_SHUTDOWN ||
+ vsk->peerShutdown & SEND_SHUTDOWN) {
mask |= POLLRDHUP;
}
#endif
if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
Bool spaceAvailNow = FALSE;
int32 ret = 0;
+
NOTIFYCALLRET(vsk, ret, pollOut, sk, 1, &spaceAvailNow);
if (ret < 0) {
mask |= POLLERR;
} else {
if (spaceAvailNow) {
- mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+ /* Remove POLLWRBAND since INET sockets are not setting it.*/
+ mask |= POLLOUT | POLLWRNORM;
}
}
}
}
+ /*
+ * Simulate INET socket poll behaviors, which sets POLLOUT|POLLWRNORM when
+ * peer is closed and nothing to read, but local send is not shutdown.
+ */
+ if (sk->compat_sk_state == SS_UNCONNECTED) {
+ if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ }
+
release_sock(sk);
}
*----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciDgramSendmsg(struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- int len, // IN: length of message
- struct scm_cookie *scm) // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- int len, // IN: length of message
- struct scm_cookie *scm); // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- int len) // IN: length of message
-#else
static int
VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED
struct socket *sock, // IN: socket to send on
struct msghdr *msg, // IN: message to send
size_t len) // IN: length of message
-#endif
{
int err;
struct sock *sk;
*----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciStreamSendmsg(struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- int len, // IN: length of message
- struct scm_cookie *scm) // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- int len, // IN: length of message
- struct scm_cookie *scm); // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- int len) // IN: length of message
-#else
static int
VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED
struct socket *sock, // IN: socket to send on
struct msghdr *msg, // IN: message to send
size_t len) // IN: length of message
-#endif
{
struct sock *sk;
VSockVmciSock *vsk;
goto out;
}
- if (sk->compat_sk_shutdown & SEND_SHUTDOWN) {
+ /* Send data only if both sides are not shutdown in the direction. */
+ if (sk->compat_sk_shutdown & SEND_SHUTDOWN ||
+ vsk->peerShutdown & RCV_SHUTDOWN) {
err = -EPIPE;
goto out;
}
}
NOTIFYCALLRET(vsk, err, sendPreBlock, sk, &sendData);
+
if (err < 0) {
goto outWait;
}
*----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciDgramRecvmsg(struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- int len, // IN: length of receive buffer
- int flags, // IN: receive flags
- struct scm_cookie *scm) // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciDgramRecvmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- int len, // IN: length of receive buffer
- int flags, // IN: receive flags
- struct scm_cookie *scm) // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciDgramRecvmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- int len, // IN: length of receive buffer
- int flags) // IN: receive flags
-#else
static int
VSockVmciDgramRecvmsg(struct kiocb *kiocb, // UNUSED
struct socket *sock, // IN: socket to receive from
struct msghdr *msg, // IN/OUT: message to receive into
size_t len, // IN: length of receive buffer
int flags) // IN: receive flags
-#endif
{
int err;
int noblock;
*----------------------------------------------------------------------------
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciStreamRecvmsg(struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- int len, // IN: length of receive buffer
- int flags, // IN: receive flags
- struct scm_cookie *scm) // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- int len, // IN: length of receive buffer
- int flags, // IN: receive flags
- struct scm_cookie *scm) // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- int len, // IN: length of receive buffer
- int flags) // IN: receive flags
-#else
static int
VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED
struct socket *sock, // IN: socket to receive from
struct msghdr *msg, // IN/OUT: message to receive into
size_t len, // IN: length of receive buffer
int flags) // IN: receive flags
-#endif
{
struct sock *sk;
VSockVmciSock *vsk;
goto out;
}
+ /*
+ * We don't check peerShutdown flag here since peer may actually shut down,
+ * but there can be data in the VMCI queue that local socket can receive.
+ */
if (sk->compat_sk_shutdown & RCV_SHUTDOWN) {
err = 0;
goto out;
/*
* If the other side has shutdown for sending and there is nothing more to
- * read, then set our socket's RCV_SHUTDOWN flag and modify the socket
- * state.
+ * read, then modify the socket state.
*/
if (vsk->peerShutdown & SEND_SHUTDOWN) {
if (VSockVmciStreamHasData(vsk) <= 0) {
- sk->compat_sk_shutdown |= RCV_SHUTDOWN;
sk->compat_sk_state = SS_UNCONNECTED;
compat_sock_set_done(sk);
sk->compat_sk_state_change(sk);
struct file * filp) // IN
{
int ret;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 26) || \
- (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3))
- lock_kernel();
-#endif
ret = -ENOTTY;
if (filp && filp->f_op && filp->f_op->ioctl == VSockVmciDevIoctl) {
ret = VSockVmciDevIoctl(filp->f_dentry->d_inode, filp, iocmd, ioarg);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 26) || \
- (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3))
- unlock_kernel();
-#endif
return ret;
}
#endif /* !HAVE_COMPAT_IOCTL */
MODULE_DESCRIPTION("VMware Virtual Socket Family");
MODULE_VERSION(VSOCK_DRIVER_VERSION_STRING);
MODULE_LICENSE("GPL v2");
+
/*
* Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
* with them and mark their kernel modules as externally supported via a
* by default (i.e., neither mkinitrd nor modprobe will accept it).
*/
MODULE_INFO(supported, "external");
+
+#ifdef VMX86_DEVEL
+/* We only support protocol negotiation overrides on devel builds. */
+module_param(protocolOverride, int, 0);
+MODULE_PARM_DESC(protocolOverride, "Specify a vsock protocol (auto negotiated by default");
+#endif
Bool rejected;
compat_delayed_work dwork;
uint32 peerShutdown;
+ Bool sentRequest;
+ Bool ignoreConnectingRst;
} VSockVmciSock;
int VSockVmciSendControlPktBH(struct sockaddr_vm *src,
VSockWaitingInfo *wait, VMCIHandle handle);
int VSockVmciSendControlPkt(struct sock *sk, VSockPacketType type,
uint64 size, uint64 mode,
- VSockWaitingInfo *wait, VMCIHandle handle);
+ VSockWaitingInfo *wait,
+ VSockProtoVersion version,
+ VMCIHandle handle);
int64 VSockVmciStreamHasData(VSockVmciSock *vsk);
int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk);
((_pkt)->type == VSOCK_PACKET_TYPE_RST) ? \
0 : \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_RST, \
- 0, 0, NULL, VMCI_INVALID_HANDLE)
+ 0, 0, NULL, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_NEGOTIATE(_sk, _size) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE, \
- _size, 0, NULL, VMCI_INVALID_HANDLE)
+ _size, 0, NULL, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
+#define VSOCK_SEND_NEGOTIATE2(_sk, _size, signalProto) \
+ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE2, \
+ _size, 0, NULL, signalProto, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_QP_OFFER(_sk, _handle) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_OFFER, \
- 0, 0, NULL, _handle)
+ 0, 0, NULL, VSOCK_PROTO_INVALID, _handle)
#define VSOCK_SEND_CONN_REQUEST(_sk, _size) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST, \
- _size, 0, NULL, VMCI_INVALID_HANDLE)
+ _size, 0, NULL, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
+#define VSOCK_SEND_CONN_REQUEST2(_sk, _size, signalProto) \
+ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST2, \
+ _size, 0, NULL, signalProto, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_ATTACH(_sk, _handle) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_ATTACH, \
- 0, 0, NULL, _handle)
+ 0, 0, NULL, VSOCK_PROTO_INVALID, _handle)
#define VSOCK_SEND_WROTE(_sk) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WROTE, \
- 0, 0, NULL, VMCI_INVALID_HANDLE)
+ 0, 0, NULL, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_READ(_sk) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_READ, \
- 0, 0, NULL, VMCI_INVALID_HANDLE)
+ 0, 0, NULL, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_SHUTDOWN(_sk, _mode) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_SHUTDOWN, \
- 0, _mode, NULL, VMCI_INVALID_HANDLE)
+ 0, _mode, NULL, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_WAITING_WRITE(_sk, _waitInfo) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_WRITE, \
- 0, 0, _waitInfo, VMCI_INVALID_HANDLE)
+ 0, 0, _waitInfo, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_SEND_WAITING_READ(_sk, _waitInfo) \
VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_READ, \
- 0, 0, _waitInfo, VMCI_INVALID_HANDLE)
+ 0, 0, _waitInfo, VSOCK_PROTO_INVALID, \
+ VMCI_INVALID_HANDLE)
#define VSOCK_REPLY_RESET(_pkt) \
VSockVmciReplyControlPktFast(_pkt, VSOCK_PACKET_TYPE_RST, \
0, 0, NULL, VMCI_INVALID_HANDLE)
#include "af_vsock.h"
#define PKT_FIELD(vsk, fieldName) \
- (vsk)->notify.fieldName
+ (vsk)->notify.pkt.fieldName
#define VSOCK_MAX_DGRAM_RESENDS 10
}
}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessRequest
+ *
+ * Called near the end of process request.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessNegotiate
+ *
+ * Called near the end of process negotiate.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
/* Socket control packet based operations. */
VSockVmciNotifyOps vSockVmciNotifyPktOps = {
VSockVmciNotifyPktSocketInit,
VSockVmciNotifyPktSendInit,
VSockVmciNotifyPktSendPreBlock,
VSockVmciNotifyPktSendPreEnqueue,
- VSockVmciNotifyPktSendPostEnqueue
+ VSockVmciNotifyPktSendPostEnqueue,
+ VSockVmciNotifyPktProcessRequest,
+ VSockVmciNotifyPktProcessNegotiate,
};
# define VSOCK_OPTIMIZATION_FLOW_CONTROL 1
#endif
+#define VSOCK_MAX_DGRAM_RESENDS 10
+
#define NOTIFYCALLRET(vsk, rv, mod_fn, args...) \
do { \
- if (vsk->notifyOps->mod_fn != NULL) { \
+ if (vsk->notifyOps && \
+ vsk->notifyOps->mod_fn != NULL) { \
rv = (vsk->notifyOps->mod_fn)(args); \
} else { \
rv = 0; \
#define NOTIFYCALL(vsk, mod_fn, args...) \
do { \
- if (vsk->notifyOps->mod_fn != NULL) { \
+ if (vsk->notifyOps && \
+ vsk->notifyOps->mod_fn != NULL) { \
(vsk->notifyOps->mod_fn)(args); \
} \
} while (0)
-
-typedef struct VSockVmciNotify {
+typedef struct VSockVmciNotifyPkt {
uint64 writeNotifyWindow;
uint64 writeNotifyMinWindow;
Bool peerWaitingRead;
VSockWaitingInfo peerWaitingWriteInfo;
uint64 produceQGeneration;
uint64 consumeQGeneration;
+} VSockVmciNotifyPkt;
+
+typedef struct VSockVmciNotifyPktQState {
+ uint64 writeNotifyWindow;
+ uint64 writeNotifyMinWindow;
+ Bool peerWaitingWrite;
+ Bool peerWaitingWriteDetected;
+} VSockVmciNotifyPktQState;
+
+typedef union VSockVmciNotify {
+ VSockVmciNotifyPkt pkt;
+ VSockVmciNotifyPktQState pktQState;
} VSockVmciNotify;
typedef struct VSockVmciRecvNotifyData {
-#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
uint64 consumeHead;
uint64 produceTail;
-#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
Bool notifyOnBlock;
-#endif
-#endif
} VSockVmciRecvNotifyData;
typedef struct VSockVmciSendNotifyData {
-#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
uint64 consumeHead;
uint64 produceTail;
-#endif
} VSockVmciSendNotifyData;
/* Socket notification callbacks. */
int32 (*sendPostEnqueue)(struct sock *sk,
ssize_t written,
VSockVmciSendNotifyData *data);
+ void (*processRequest)(struct sock *sk);
+ void (*processNegotiate)(struct sock *sk);
} VSockVmciNotifyOps;
extern VSockVmciNotifyOps vSockVmciNotifyPktOps;
+extern VSockVmciNotifyOps vSockVmciNotifyPktQStateOps;
#endif /* __NOTIFY_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * notifyQState.c --
+ *
+ * Linux control notifications based on Queuepair state for the VMCI
+ * Stream Sockets protocol.
+ */
+
+
+#include "driver-config.h"
+
+#include <linux/socket.h>
+
+#include "compat_sock.h"
+
+#include "notify.h"
+#include "af_vsock.h"
+
+#define PKT_FIELD(vsk, fieldName) \
+ (vsk)->notify.pktQState.fieldName
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyWaitingWrite --
+ *
+ * Determines if the conditions have been met to notify a waiting writer.
+ *
+ * Results:
+ * TRUE if a notification should be sent, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk) // IN
+{
+ Bool retval;
+ uint64 notifyLimit;
+
+ if (!PKT_FIELD(vsk, peerWaitingWrite)) {
+ return FALSE;
+ }
+
+ /*
+ * When the sender blocks, we take that as a sign that the sender
+ * is faster than the receiver. To reduce the transmit rate of the
+ * sender, we delay the sending of the read notification by
+ * decreasing the writeNotifyWindow. The notification is delayed
+ * until the number of bytes used in the queue drops below the
+ * writeNotifyWindow.
+ */
+
+ if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) {
+ PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE;
+ PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE;
+ if (PKT_FIELD(vsk, writeNotifyWindow) <
+ PKT_FIELD(vsk, writeNotifyMinWindow)) {
+ PKT_FIELD(vsk, writeNotifyWindow) =
+ PKT_FIELD(vsk, writeNotifyMinWindow);
+ }
+ }
+ notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow);
+
+ /*
+ * The notifyLimit is used to delay notifications in the case where
+ * flow control is enabled. Below the test is expressed in terms of
+ * free space in the queue:
+ * if freeSpace > ConsumeSize - writeNotifyWindow then notify
+ * An alternate way of expressing this is to rewrite the expression
+ * to use the data ready in the receive queue:
+ * if writeNotifyWindow > bufferReady then notify
+ * as freeSpace == ConsumeSize - bufferReady.
+ */
+
+ retval = VMCIQueue_FreeSpace(vsk->consumeQ, vsk->produceQ, vsk->consumeSize) >
+ notifyLimit;
+
+ if (retval) {
+ /*
+ * Once we notify the peer, we reset the detected flag so the
+ * next wait will again cause a decrease in the window size.
+ */
+
+ PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
+ }
+ return retval;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciHandleRead --
+ *
+ * Handles an incoming read message.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciHandleRead(struct sock *sk, // IN
+ VSockPacket *pkt, // IN: unused
+ Bool bottomHalf, // IN: unused
+ struct sockaddr_vm *dst, // IN: unused
+ struct sockaddr_vm *src) // IN: unused
+{
+
+ sk->compat_sk_write_space(sk);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciHandleWrote --
+ *
+ * Handles an incoming wrote message.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciHandleWrote(struct sock *sk, // IN
+ VSockPacket *pkt, // IN: unused
+ Bool bottomHalf, // IN: unused
+ struct sockaddr_vm *dst, // IN: unused
+ struct sockaddr_vm *src) // IN: unused
+{
+ sk->compat_sk_data_ready(sk, 0);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciBlockUpdateWriteWindow --
+ *
+ * Updates the write window when we are blocking for data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciBlockUpdateWriteWindow(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+
+ vsk = vsock_sk(sk);
+
+ if (PKT_FIELD(vsk, writeNotifyWindow) < vsk->consumeSize) {
+ PKT_FIELD(vsk, writeNotifyWindow) =
+ MIN(PKT_FIELD(vsk, writeNotifyWindow) + PAGE_SIZE,
+ vsk->consumeSize);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciSendReadNotification --
+ *
+ * Sends a read notification to this socket's peer.
+ *
+ * Results:
+ * >= 0 if the datagram is sent successfully, negative error value
+ * otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VSockVmciSendReadNotification(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+ Bool sentRead;
+ unsigned int retries;
+ int err;
+
+ ASSERT(sk);
+
+ vsk = vsock_sk(sk);
+ sentRead = FALSE;
+ retries = 0;
+ err = 0;
+
+ if (VSockVmciNotifyWaitingWrite(vsk)) {
+ /*
+ * Notify the peer that we have read, retrying the send on failure up to our
+ * maximum value. XXX For now we just log the failure, but later we should
+ * schedule a work item to handle the resend until it succeeds. That would
+ * require keeping track of work items in the vsk and cleaning them up upon
+ * socket close.
+ */
+ while (!(vsk->peerShutdown & RCV_SHUTDOWN) &&
+ !sentRead &&
+ retries < VSOCK_MAX_DGRAM_RESENDS) {
+ err = VSOCK_SEND_READ(sk);
+ if (err >= 0) {
+ sentRead = TRUE;
+ }
+
+ retries++;
+ }
+
+ if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentRead) {
+ Warning("unable to send read notification to peer for socket %p.\n", sk);
+ } else {
+ PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
+ }
+ }
+ return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktSocketInit --
+ *
+ * Function that is called after a socket is created and before any
+ * notify ops are used.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktSocketInit(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, writeNotifyWindow) = 0;
+ PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
+ PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
+ PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktSocketDestruct --
+ *
+ * Function that is called when the socket is being released.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktSocketDestruct(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, writeNotifyWindow) = 0;
+ PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
+ PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
+ PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
+ return;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktPollIn --
+ *
+ * Called by the poll function to figure out if there is data to read
+ * and to setup future notifications if needed. Only called on sockets
+ * that aren't shutdown for recv.
+ *
+ * Results:
+ * 0 on success. Negative error on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktPollIn(struct sock *sk, // IN
+ int target, // IN
+ Bool *dataReadyNow) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+ ASSERT(dataReadyNow);
+
+ vsk = vsock_sk(sk);
+
+ if (VSockVmciStreamHasData(vsk)) {
+ *dataReadyNow = TRUE;
+ } else {
+ /*
+ * We can't read right now because there is nothing in the queue.
+ * Ask for notifications when there is something to read.
+ */
+ if (sk->compat_sk_state == SS_CONNECTED) {
+ VSockVmciBlockUpdateWriteWindow(sk);
+ }
+ *dataReadyNow = FALSE;
+ }
+
+ return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktPollOut
+ *
+ * Called by the poll function to figure out if there is space to write
+ * and to setup future notifications if needed. Only called on a
+ * connected socket that isn't shutdown for send.
+ *
+ * Results:
+ * 0 on success. Negative error on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktPollOut(struct sock *sk, // IN
+ int target, // IN
+ Bool *spaceAvailNow) // IN
+{
+ int64 produceQFreeSpace;
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+ ASSERT(spaceAvailNow);
+
+ vsk = vsock_sk(sk);
+
+ produceQFreeSpace =
+ VSockVmciStreamHasSpace(vsk);
+ if (produceQFreeSpace > 0) {
+ *spaceAvailNow = TRUE;
+ return 0;
+ } else if (produceQFreeSpace == 0) {
+ /*
+ * This is a connected socket but we can't currently send data. Nothing
+ * else to do.
+ */
+ *spaceAvailNow = FALSE;
+ }
+
+ return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktRecvInit --
+ *
+ * Called at the start of a stream recv call with the socket lock held.
+ *
+ * Results:
+ * 0 on success. Negative error on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktRecvInit(struct sock *sk, // IN
+ int target, // IN
+ VSockVmciRecvNotifyData *data) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+ ASSERT(data);
+
+ vsk = vsock_sk(sk);
+
+ data->consumeHead = 0;
+ data->produceTail = 0;
+ data->notifyOnBlock = FALSE;
+
+ if (PKT_FIELD(vsk, writeNotifyMinWindow) < target + 1) {
+ ASSERT(target < vsk->consumeSize);
+ PKT_FIELD(vsk, writeNotifyMinWindow) = target + 1;
+ if (PKT_FIELD(vsk, writeNotifyWindow) <
+ PKT_FIELD(vsk, writeNotifyMinWindow)) {
+ /*
+ * If the current window is smaller than the new minimal
+ * window size, we need to reevaluate whether we need to
+ * notify the sender. If the number of ready bytes are
+ * smaller than the new window, we need to send a
+ * notification to the sender before we block.
+ */
+
+ PKT_FIELD(vsk, writeNotifyWindow) =
+ PKT_FIELD(vsk, writeNotifyMinWindow);
+ data->notifyOnBlock = TRUE;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktRecvPreBlock --
+ *
+ * Called right before a socket is about to block with the socket lock
+ * held. The socket lock may have been released between the entry
+ * function and the preblock call.
+ *
+ * Note: This function may be called multiple times before the post
+ * block function is called.
+ *
+ * Results:
+ * 0 on success. Negative error on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktRecvPreBlock(struct sock *sk, // IN
+ int target, // IN
+ VSockVmciRecvNotifyData *data) // IN
+{
+ VSockVmciSock *vsk;
+ int err;
+
+ ASSERT(sk);
+ ASSERT(data);
+
+ vsk = vsock_sk(sk);
+ err = 0;
+
+ VSockVmciBlockUpdateWriteWindow(sk);
+
+ if (data->notifyOnBlock) {
+ err = VSockVmciSendReadNotification(sk);
+ if (err < 0) {
+ return err;
+ }
+ data->notifyOnBlock = FALSE;
+ }
+
+ return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktRecvPostDequeue --
+ *
+ * Called right after we dequeue / peek data from a socket.
+ *
+ * Results:
+ * 0 on success. Negative error on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktRecvPostDequeue(struct sock *sk, // IN
+ int target, // IN
+ ssize_t copied, // IN
+ Bool dataRead, // IN
+ VSockVmciRecvNotifyData *data) // IN
+{
+ VSockVmciSock *vsk;
+ int err;
+ Bool wasFull = FALSE;
+ uint64 freeSpace;
+
+ ASSERT(sk);
+ ASSERT(data);
+
+ vsk = vsock_sk(sk);
+ err = 0;
+
+ if (dataRead) {
+ Atomic_MFence();
+
+ freeSpace = VMCIQueue_FreeSpace(vsk->consumeQ,
+ vsk->produceQ,
+ vsk->consumeSize);
+ wasFull = freeSpace == copied;
+
+ if (wasFull) {
+ PKT_FIELD(vsk, peerWaitingWrite) = TRUE;
+ }
+
+ err = VSockVmciSendReadNotification(sk);
+ if (err < 0) {
+ return err;
+ }
+
+ /* See the comment in VSockVmciNotifyPktSendPostEnqueue */
+ sk->compat_sk_data_ready(sk, 0);
+ }
+
+ return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktSendInit --
+ *
+ * Called at the start of a stream send call with the socket lock held.
+ *
+ * Results:
+ * 0 on success. A negative error code on failure.
+ *
+ * Side effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktSendInit(struct sock *sk, // IN
+ VSockVmciSendNotifyData *data) // IN
+{
+ ASSERT(sk);
+ ASSERT(data);
+
+ data->consumeHead = 0;
+ data->produceTail = 0;
+
+ return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifySendPostEnqueue --
+ *
+ * Called right after we enqueue data to a socket.
+ *
+ * Results:
+ * 0 on success. Negative error on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktSendPostEnqueue(struct sock *sk, // IN
+ ssize_t written, // IN
+ VSockVmciSendNotifyData *data) // IN
+{
+ int err = 0;
+ VSockVmciSock *vsk;
+ Bool sentWrote = FALSE;
+ Bool wasEmpty;
+
+ int retries = 0;
+
+ ASSERT(sk);
+ ASSERT(data);
+
+ vsk = vsock_sk(sk);
+
+ Atomic_MFence();
+
+ wasEmpty = (VMCIQueue_BufReady(vsk->produceQ,
+ vsk->consumeQ,
+ vsk->produceSize) == written);
+ if (wasEmpty) {
+ while (!(vsk->peerShutdown & RCV_SHUTDOWN) &&
+ !sentWrote &&
+ retries < VSOCK_MAX_DGRAM_RESENDS) {
+ err = VSOCK_SEND_WROTE(sk);
+ if (err >= 0) {
+ sentWrote = TRUE;
+ }
+
+ retries++;
+ }
+ }
+
+ if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentWrote) {
+ Warning("unable to send wrote notification to peer for socket %p.\n", sk);
+ return err;
+ }
+
+ return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktHandlePkt
+ *
+ * Called when a notify packet is recieved for a socket in the connected
+ * state. Note this might be called from a bottom half.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktHandlePkt(struct sock *sk, // IN
+ VSockPacket *pkt, // IN
+ Bool bottomHalf, // IN
+ struct sockaddr_vm *dst, // IN
+ struct sockaddr_vm *src, // IN
+ Bool *pktProcessed) // In
+{
+ Bool processed = FALSE;
+
+ ASSERT(sk);
+ ASSERT(pkt);
+
+ switch (pkt->type) {
+ case VSOCK_PACKET_TYPE_WROTE:
+ VSockVmciHandleWrote(sk, pkt, bottomHalf, dst, src);
+ processed = TRUE;
+ break;
+ case VSOCK_PACKET_TYPE_READ:
+ VSockVmciHandleRead(sk, pkt, bottomHalf, dst, src);
+ processed = TRUE;
+ break;
+ }
+
+ if (pktProcessed) {
+ *pktProcessed = processed;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessRequest
+ *
+ * Called near the end of process request.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessNegotiate
+ *
+ * Called near the end of process negotiate.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN
+{
+ VSockVmciSock *vsk;
+
+ ASSERT(sk);
+
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
+/* Socket always on control packet based operations. */
+VSockVmciNotifyOps vSockVmciNotifyPktQStateOps = {
+ VSockVmciNotifyPktSocketInit,
+ VSockVmciNotifyPktSocketDestruct,
+ VSockVmciNotifyPktPollIn,
+ VSockVmciNotifyPktPollOut,
+ VSockVmciNotifyPktHandlePkt,
+ VSockVmciNotifyPktRecvInit,
+ VSockVmciNotifyPktRecvPreBlock,
+ NULL, /* recvPreDequeue */
+ VSockVmciNotifyPktRecvPostDequeue,
+ VSockVmciNotifyPktSendInit,
+ NULL, /* sendPreBlock */
+ NULL, /* sendPreEnqueue */
+ VSockVmciNotifyPktSendPostEnqueue,
+ VSockVmciNotifyPktProcessRequest,
+ VSockVmciNotifyPktProcessNegotiate,
+};
[VSOCK_PACKET_TYPE_SHUTDOWN] = "SHUTDOWN",
[VSOCK_PACKET_TYPE_WAITING_WRITE] = "WAITING_WRITE",
[VSOCK_PACKET_TYPE_WAITING_READ] = "WAITING_READ",
+ [VSOCK_PACKET_TYPE_REQUEST2] = "REQUEST2",
+ [VSOCK_PACKET_TYPE_NEGOTIATE2] = "NEGOTIATE2",
};
written = snprintf(cur, left, "PKT: %u:%u -> %u:%u",
break;
+ case VSOCK_PACKET_TYPE_REQUEST2:
+ case VSOCK_PACKET_TYPE_NEGOTIATE2:
+ written = snprintf(cur, left, ", %s, size = %"FMT64"u, "
+ "proto = %u",
+ typeStrings[pkt->type], pkt->u.size,
+ pkt->proto);
+ break;
+
default:
written = snprintf(cur, left, ", unrecognized type");
}
/* The resource ID on which control packets are sent. */
#define VSOCK_PACKET_RID 1
-/* Assert that the given packet is valid. */
-#define VSOCK_PACKET_ASSERT(_p) \
- ASSERT((_p)); \
- ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX); \
- ASSERT(0 == (_p)->_reserved1); \
- ASSERT(0 == (_p)->_reserved2)
-
+/*
+ * Assert that the given packet is valid.
+ * We check that the two original reserved fields equal zero because the
+ * version of the common code that shipped with ESX 4.0 and WS 6.5 did so and
+ * will return a RST packet if they aren't set that way. For newer packet
+ * types added after that release we don't do this.
+ */
+#define VSOCK_PACKET_ASSERT(_p) \
+ do { \
+ ASSERT((_p)); \
+ ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX); \
+ if ((_p)->type < VSOCK_PACKET_TYPE_REQUEST2) { \
+ ASSERT(0 == (_p)->proto); \
+ ASSERT(0 == (_p)->_reserved2); \
+ } \
+ } while(0)
typedef enum VSockPacketType {
VSOCK_PACKET_TYPE_INVALID = 0, // Invalid type.
- VSOCK_PACKET_TYPE_REQUEST, // Connection request.
+ VSOCK_PACKET_TYPE_REQUEST, // Connection request (WR/WW/READ/WRITE)
VSOCK_PACKET_TYPE_NEGOTIATE, // Connection negotiate.
VSOCK_PACKET_TYPE_OFFER, // Connection offer queue pair.
VSOCK_PACKET_TYPE_ATTACH, // Connection attach.
VSOCK_PACKET_TYPE_SHUTDOWN, // Shutdown the connection.
VSOCK_PACKET_TYPE_WAITING_WRITE, // Notify peer we are waiting to write.
VSOCK_PACKET_TYPE_WAITING_READ, // Notify peer we are waiting to read.
+ VSOCK_PACKET_TYPE_REQUEST2, // Connection request (new proto flags)
+ VSOCK_PACKET_TYPE_NEGOTIATE2, // Connection request (new proto flags)
VSOCK_PACKET_TYPE_MAX // Last message.
} VSockPacketType;
+typedef uint16 VSockProtoVersion;
+#define VSOCK_PROTO_INVALID 0 // Invalid protocol version.
+#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0) // Queuepair inspection proto.
+
+#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY)
+
typedef struct VSockWaitingInfo {
uint64 generation; // Generation of the queue.
uint64 offset; // Offset within the queue.
VMCIDatagram dg; // Datagram header.
uint8 version; // Version.
uint8 type; // Type of message.
- uint16 _reserved1; // Reserved.
+ VSockProtoVersion proto; // Supported proto versions in CONNECT2 and
+ // NEGOTIATE2. 0 otherwise.
uint32 srcPort; // Source port.
uint32 dstPort; // Destination port.
uint32 _reserved2; // Reserved.
uint64 size, // IN
uint64 mode, // IN
VSockWaitingInfo *wait, // IN
+ VSockProtoVersion proto, // IN
VMCIHandle handle) // IN
{
ASSERT(pkt);
pkt->type = type;
pkt->srcPort = src->svm_port;
pkt->dstPort = dst->svm_port;
- VSockOS_ClearMemory(&pkt->_reserved1, sizeof pkt->_reserved1);
+ VSockOS_ClearMemory(&pkt->proto, sizeof pkt->proto);
VSockOS_ClearMemory(&pkt->_reserved2, sizeof pkt->_reserved2);
switch (pkt->type) {
ASSERT(wait);
VSockOS_Memcpy(&pkt->u.wait, wait, sizeof pkt->u.wait);
break;
+
+ case VSOCK_PACKET_TYPE_REQUEST2:
+ case VSOCK_PACKET_TYPE_NEGOTIATE2:
+ pkt->u.size = size;
+ pkt->proto = proto;
+ break;
}
VSOCK_PACKET_ASSERT(pkt);
goto exit;
}
- if (0 != pkt->_reserved1 || 0 != pkt->_reserved2) {
- goto exit;
+ /* See the comment above VSOCK_PACKET_ASSERT. */
+ if (pkt->type < VSOCK_PACKET_TYPE_REQUEST2) {
+ if (0 != pkt->proto || 0 != pkt->_reserved2) {
+ goto exit;
+ }
}
switch (pkt->type) {
}
err = 0;
-
+
exit:
return sockerr2err(err);
}
#define VMNET_CAP_IP6_CSUM 0x80000 /* Can do IPv6 csum offload. */
#define VMNET_CAP_TSO6 0x100000 /* Can do TSO segmentation offload for IPv6 pkts. */
#define VMNET_CAP_TSO256k 0x200000 /* Can do TSO segmentation offload for pkts up to 256kB. */
+#define VMNET_CAP_UPT 0x400000 /* Support UPT */
#endif // _VMNET_DEF_H_
typedef
#include "vmware_pack_begin.h"
-struct vmxnet3_TxDataDesc {
+struct Vmxnet3_TxDataDesc {
uint8 data[VMXNET3_HDR_COPY_SIZE];
}
#include "vmware_pack_end.h"
typedef
#include "vmware_pack_begin.h"
-struct vmxnet3_TxQueueConf {
+struct Vmxnet3_TxQueueConf {
uint64 txRingBasePA;
uint64 dataRingBasePA;
uint64 compRingBasePA;
*
*********************************************************/
-/*
+/*
* os.c --
*
- * Wrappers for Solaris system functions required by "vmmemctl".
+ * Wrappers for Solaris system functions required by "vmmemctl".
*/
/*
#include <sys/ksynch.h>
#include "os.h"
+#include "vm_assert.h"
#include "balloon_def.h"
#include "vmballoon_kstats.h"
#include "vmmemctl.h"
kcondvar_t cv;
/* registered state */
- os_timer_handler handler;
+ OSTimerHandler *handler;
void *data;
int period;
} os_timer;
static os_state global_state;
static dev_info_t *vmmemctl_dip; /* only one instance */
+
/*
- * Simple Wrappers
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Malloc --
+ *
+ * Allocates kernel memory.
+ *
+ * Results:
+ * On success: Pointer to allocated memory
+ * On failure: NULL
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-void *os_kmalloc_nosleep(unsigned int size)
+void *
+OS_Malloc(size_t size) // IN
{
return (kmem_alloc(size, KM_NOSLEEP));
}
-void os_kfree(void *obj, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Free --
+ *
+ * Free allocated kernel memory.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Free(void *ptr, // IN
+ size_t size) // IN
{
- kmem_free(obj, size);
+ kmem_free(ptr, size);
}
-void os_bzero(void *b, unsigned int len)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemZero --
+ *
+ * Fill a memory location with 0s.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemZero(void *ptr, // OUT
+ size_t size) // IN
{
- bzero(b, len);
+ bzero(ptr, size);
}
-void os_memcpy(void *dest, const void *src, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemCopy --
+ *
+ * Copy a memory portion into another location.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemCopy(void *dest, // OUT
+ const void *src, // IN
+ size_t size) // IN
{
bcopy(src, dest, size);
}
-int os_sprintf(char *str, const char *format, ...)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Snprintf --
+ *
+ * Print a string into a bounded memory location.
+ *
+ * Results:
+ * Number of character printed including trailing \0.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+OS_Snprintf(char *buf, // OUT
+ size_t size, // IN
+ const char *format, // IN
+ ...) // IN
{
- ASSERT(0);
+ NOT_REACHED();
/*
* XXX disabled because the varargs header file doesn't seem to
* work in the current (gcc 2.95.3) cross-compiler environment.
* System-Dependent Operations
*/
-char *os_identity(void)
+const char *
+OS_Identity(void)
{
return "solaris";
}
*
* Currently we just return the total memory pages.
*/
-unsigned int os_predict_max_balloon_pages(void)
+unsigned int
+OS_PredictMaxReservedPages(void)
{
return(maxmem);
}
-unsigned long os_addr_to_ppn(unsigned long addr)
+unsigned long
+OS_AddrToPPN(unsigned long addr)
{
return (ulong_t)page_pptonum(((os_page *)addr)->pp);
}
* interface for allocating physical pages that may allow us to
* eliminate some of this.
*/
-unsigned long os_alloc_reserved_page(int can_sleep)
+unsigned long
+OS_AllocReservedPage(int canSleep)
{
os_state *state = &global_state;
page_t *pp;
/*
* Reserve space for the page.
*/
- flags = can_sleep ? KM_SLEEP : KM_NOSLEEP;
+ flags = canSleep ? KM_SLEEP : KM_NOSLEEP;
if (!page_resv(1, flags))
return 0; /* no space! */
/*
- * Allocating space for os_page early simplifies error handling.
+ * Allocating space for os_page early simplifies error handling.
*/
if ((page = kmem_alloc(sizeof (os_page), flags)) == NULL) {
page_unresv(1);
* Allocate the page itself. Note that this can fail.
*/
kseg.s_as = &kas;
- flags = can_sleep ? PG_EXCL | PG_WAIT : PG_EXCL;
+ flags = canSleep ? PG_EXCL | PG_WAIT : PG_EXCL;
pp = page_create_va(vp, off, PAGESIZE, flags, &kseg,
(caddr_t)(ulong_t)off);
if (pp != NULL) {
return (unsigned long)page;
}
-void os_free_reserved_page(unsigned long addr)
+void
+OS_FreeReservedPage(unsigned long addr)
{
os_state *state = &global_state;
os_page *page = (os_page *)addr;
/*
* Initialize timer data.
*/
-void os_timer_init(os_timer_handler handler, void *data, int period)
+void
+OS_TimerInit(OSTimerHandler *handler, // IN
+ void *clientData, // IN
+ int period) // IN
{
os_timer *t = &global_state.timer;
t->id = 0;
t->handler = handler;
- t->data = data;
+ t->data = clientData;
t->period = period;
t->stop = 0;
cv_init(&t->cv, NULL, CV_DRIVER, NULL);
}
-void os_timer_start(void)
+void
+OS_TimerStart(void)
{
os_timer *t = &global_state.timer;
t->stop = 0;
}
-void os_timer_stop(void)
+void
+OS_TimerStop(void)
{
os_timer *t = &global_state.timer;
cv_destroy(&timer->cv);
}
-unsigned int os_timer_hz(void)
+unsigned int
+OS_TimerHz(void)
{
return drv_usectohz(ONE_SECOND_IN_MICROSECONDS);
}
-void os_yield(void)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Yield --
+ *
+ * Yield the CPU, if needed.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Yield(void)
{
/* Do nothing. */
}
-void os_init(const char *name,
+void OS_Init(const char *name,
const char *name_verbose,
- os_status_handler handler)
+ OSStatusHandler *handler)
{
os_state *state = &global_state;
static int initialized = 0;
cmn_err(CE_CONT, "!%s initialized\n", name_verbose);
}
-void os_cleanup(void)
+void OS_Cleanup(void)
{
os_state *state = &global_state;
*
*********************************************************/
-/*
+/*
* os.h --
*
- * Definitions for OS-specific wrapper functions required
- * by "vmmemctl". This allows customers to build their own
- * vmmemctl driver for custom versioned kernels without the
- * need for source code.
+ * Definitions for OS-specific wrapper functions required by "vmmemctl".
*/
#ifndef OS_H
#define OS_H
-/*
- * Needs fixing for 64bit OSes
- */
-#ifndef __x86_64__
-#define CDECL __attribute__((cdecl, regparm(0)))
-#else
-#define CDECL
-#endif
-
/*
* Types
*/
-typedef void CDECL (*os_timer_handler)(void *);
-typedef int CDECL (*os_status_handler)(char *);
+typedef void OSTimerHandler(void *clientData);
+typedef int OSStatusHandler(char *buf, size_t size);
/*
* Operations
*/
-extern void CDECL *os_kmalloc_nosleep(unsigned int size);
-extern void CDECL os_kfree(void *obj, unsigned int size);
-extern void CDECL os_yield(void);
-extern void CDECL os_bzero(void *s, unsigned int n);
-extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size);
-extern int CDECL os_sprintf(char *str, const char *format, ...);
-
-extern unsigned long CDECL os_addr_to_ppn(unsigned long addr);
-extern unsigned long CDECL os_alloc_reserved_page(int can_sleep);
-extern void CDECL os_free_reserved_page(unsigned long page);
+extern void OS_Init(const char *name,
+ const char *nameVerbose,
+ OSStatusHandler *handler);
+extern void OS_Cleanup(void);
+extern const char *OS_Identity(void);
-extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period);
-extern void CDECL os_timer_start(void);
-extern void CDECL os_timer_stop(void);
+extern void OS_MemZero(void *ptr, size_t size);
+extern void OS_MemCopy(void *dest, const void *src, size_t size);
+extern int OS_Snprintf(char *buf, size_t size, const char *format, ...);
-extern void CDECL os_init(const char *name,
- const char *name_verbose,
- os_status_handler handler);
-extern void CDECL os_cleanup(void);
+extern void *OS_Malloc(size_t size);
+extern void OS_Free(void *ptr, size_t size);
-extern char CDECL *os_identity(void);
+extern void OS_Yield(void);
-extern unsigned int CDECL os_predict_max_balloon_pages(void);
+extern unsigned int OS_TimerHz(void);
+extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
+extern void OS_TimerStart(void);
+extern void OS_TimerStop(void);
-extern unsigned int CDECL os_timer_hz(void);
+extern unsigned int OS_PredictMaxReservedPages(void);
+extern unsigned long OS_AddrToPPN(unsigned long addr);
+extern unsigned long OS_AllocReservedPage(int canSleep);
+extern void OS_FreeReservedPage(unsigned long page);
#endif /* OS_H */
*
*********************************************************/
-/*
+/*
* vmballoon.c --
*
- * VMware server physical memory management driver for Unix-ish
- * (Linux, FreeBSD, Solaris) guests. The driver acts like a
- * "balloon" that can be inflated to reclaim physical pages by
- * reserving them in the guest and invalidating them in the
- * monitor, freeing up the underlying machine pages so they can
- * be allocated to other guests. The balloon can also be
- * deflated to allow the guest to use more physical memory.
- * Higher level policies can control the sizes of balloons in VMs
- * in order to manage physical memory resources.
+ * VMware physical memory management driver for Unix-ish
+ * (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like
+ * a "balloon" that can be inflated to reclaim physical pages by
+ * reserving them in the guest and invalidating them in the
+ * monitor, freeing up the underlying machine pages so they can
+ * be allocated to other guests. The balloon can also be
+ * deflated to allow the guest to use more physical memory.
+ * Higher level policies can control the sizes of balloons in VMs
+ * in order to manage physical memory resources.
*/
#ifdef __cplusplus
* Compile-Time Options
*/
-#define BALLOON_RATE_ADAPT (1)
+#define BALLOON_RATE_ADAPT (1)
-#define BALLOON_DEBUG (1)
-#define BALLOON_DEBUG_VERBOSE (0)
+#define BALLOON_DEBUG (1)
+#define BALLOON_DEBUG_VERBOSE (0)
-#define BALLOON_STATS
+#define BALLOON_STATS
#define BALLOON_STATS_PROCFS
/*
#define NULL 0
#endif
-#define BALLOON_NAME "vmmemctl"
-#define BALLOON_NAME_VERBOSE "VMware memory control driver"
+#define BALLOON_NAME "vmmemctl"
+#define BALLOON_NAME_VERBOSE "VMware memory control driver"
-#define BALLOON_PROTOCOL_VERSION (2)
+#define BALLOON_PROTOCOL_VERSION (2)
-#define BALLOON_CHUNK_PAGES (1000)
+#define BALLOON_CHUNK_PAGES (1000)
-#define BALLOON_NOSLEEP_ALLOC_MAX (16384)
+#define BALLOON_NOSLEEP_ALLOC_MAX (16384)
-#define BALLOON_RATE_ALLOC_MIN (512)
-#define BALLOON_RATE_ALLOC_MAX (2048)
-#define BALLOON_RATE_ALLOC_INC (16)
+#define BALLOON_RATE_ALLOC_MIN (512)
+#define BALLOON_RATE_ALLOC_MAX (2048)
+#define BALLOON_RATE_ALLOC_INC (16)
-#define BALLOON_RATE_FREE_MIN (512)
-#define BALLOON_RATE_FREE_MAX (16384)
-#define BALLOON_RATE_FREE_INC (16)
+#define BALLOON_RATE_FREE_MIN (512)
+#define BALLOON_RATE_FREE_MAX (16384)
+#define BALLOON_RATE_FREE_INC (16)
-#define BALLOON_ERROR_PAGES (16)
+#define BALLOON_ERROR_PAGES (16)
-/*
+/*
* When guest is under memory pressure, use a reduced page allocation
* rate for next several cycles.
*/
-#define SLOW_PAGE_ALLOCATION_CYCLES (4)
+#define SLOW_PAGE_ALLOCATION_CYCLES (4)
-/*
+/*
* Move it to bora/public/balloon_def.h later, if needed. Note that
* BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
* distinguishing page allocation failures from monitor-backdoor errors.
* We use value 1000 because all monitor-backdoor error codes are < 1000.
*/
-#define BALLOON_PAGE_ALLOC_FAILURE (1000)
+#define BALLOON_PAGE_ALLOC_FAILURE (1000)
// Maximum number of page allocations without yielding processor
#define BALLOON_ALLOC_YIELD_THRESHOLD (1024)
static int BalloonGuestType(void);
static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void BalloonPrimFreePage(unsigned long page);
+static void BalloonPrimFreePage(unsigned long page);
static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
static int Balloon_FreePage(Balloon *b, int monitorUnlock);
static void Balloon_StartTimer(Balloon *b);
static void Balloon_StopTimer(Balloon *b);
-static void CDECL Balloon_BH(void *data);
+static void BalloonTimerHandler(void *clientData);
static int Balloon_MonitorStart(Balloon *b);
static int Balloon_MonitorGuestType(Balloon *b);
* Macros
*/
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef BALLOON_STATS
-#define STATS_INC(stat) (stat)++
+#ifdef BALLOON_STATS
+#define STATS_INC(stat) (stat)++
#else
-#define STATS_INC(stat)
+#define STATS_INC(stat)
#endif
/*
* Macros to generate operations for simple lists of OBJ.
* OBJ must contain next and prev fields.
- *
*/
-#define GENERATE_LIST_INSERT(OBJ) \
-static void OBJ ## _Insert(OBJ **head, OBJ *obj) \
-{ \
- OBJ *h = *head; \
- \
- /* add element to head of list */ \
- obj->next = h; \
- if (h != NULL) { \
- h->prev = obj; \
- } \
- *head = obj; \
- obj->prev = NULL; \
+#define GENERATE_LIST_INSERT(OBJ) \
+static void OBJ ## _Insert(OBJ **head, OBJ *obj) \
+{ \
+ OBJ *h = *head; \
+ \
+ /* add element to head of list */ \
+ obj->next = h; \
+ if (h != NULL) { \
+ h->prev = obj; \
+ } \
+ *head = obj; \
+ obj->prev = NULL; \
}
-#define GENERATE_LIST_REMOVE(OBJ) \
-static void OBJ ## _Remove(OBJ **head, OBJ *obj) \
-{ \
- /* splice element out of list */ \
- if (obj->prev != NULL) { \
- obj->prev->next = obj->next; \
- } else { \
- *head = obj->next; \
- } \
- if (obj->next != NULL) { \
- obj->next->prev = obj->prev; \
- } \
+#define GENERATE_LIST_REMOVE(OBJ) \
+static void OBJ ## _Remove(OBJ **head, OBJ *obj) \
+{ \
+ /* splice element out of list */ \
+ if (obj->prev != NULL) { \
+ obj->prev->next = obj->next; \
+ } else { \
+ *head = obj->next; \
+ } \
+ if (obj->next != NULL) { \
+ obj->next->prev = obj->prev; \
+ } \
}
/*
* Procfs Operations
*/
+
/*
*----------------------------------------------------------------------
*
* BalloonProcRead --
*
* Ballon driver status reporting routine. Note that this is only
- * used for Linux.
+ * used for Linux.
*
* Results:
* Writes ASCII status information into "buf".
- * Returns number of bytes written.
+ * Returns number of bytes written.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
-static int CDECL
-BalloonProcRead(char *buf)
+
+static int
+BalloonProcRead(char *buf, // OUT
+ size_t size) // IN
{
int len = 0;
BalloonStats stats;
BalloonGetStats(&stats);
/* format size info */
- len += os_sprintf(buf + len,
+ len += OS_Snprintf(buf + len, size - len,
"target: %8d pages\n"
"current: %8d pages\n",
stats.nPagesTarget,
stats.nPages);
/* format rate info */
- len += os_sprintf(buf + len,
+ len += OS_Snprintf(buf + len, size - len,
"rateNoSleepAlloc: %8d pages/sec\n"
"rateSleepAlloc: %8d pages/sec\n"
"rateFree: %8d pages/sec\n",
stats.rateAlloc,
stats.rateFree);
-#ifdef BALLOON_STATS_PROCFS
- len += os_sprintf(buf + len,
+#ifdef BALLOON_STATS_PROCFS
+ len += OS_Snprintf(buf + len, size - len,
"\n"
"timer: %8u\n"
"start: %8u (%4u failed)\n"
stats.primErrorPageFree);
#endif
- return(len);
+ return len;
}
/*
* AddrToPPN --
*
* Return the physical page number corresponding to the specified
- * Linux kernel-mapped address.
+ * kernel-mapped address.
*
* Results:
* Returns PPN for "addr".
static inline unsigned long
AddrToPPN(unsigned long addr)
{
- return(os_addr_to_ppn(addr));
+ return OS_AddrToPPN(addr);
}
/*
*
* Attempts to allocate and reserve a physical page.
*
- * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- * The allocation can wait (sleep) for page writeout (swap)
- * by the guest.
- * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- * If allocation of a page requires disk writeout, then
- * just fail. DON'T sleep.
+ * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ * The allocation can wait (sleep) for page writeout (swap)
+ * by the guest.
+ * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ * If allocation of a page requires disk writeout, then
+ * just fail. DON'T sleep.
*
* Results:
* Returns the physical address of the allocated page, or 0 if error.
static unsigned long
BalloonPrimAllocPage(BalloonPageAllocType canSleep)
{
- return(os_alloc_reserved_page(canSleep));
+ return OS_AllocReservedPage(canSleep);
}
/*
static void
BalloonPrimFreePage(unsigned long page)
{
- return(os_free_reserved_page(page));
+ return OS_FreeReservedPage(page);
}
/*
* BalloonGuestType --
*
* Return balloon guest OS identifier obtained by parsing
- * system-dependent identity string.
+ * system-dependent identity string.
*
* Results:
* Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
static int
BalloonGuestType(void)
{
- char *identity;
+ const char *identity;
/* obtain OS identify string */
- identity = os_identity();
-
+ identity = OS_Identity();
+
/* unknown if not specified */
if (identity == NULL) {
return(BALLOON_GUEST_UNKNOWN);
switch (identity[0]) {
case 'l':
case 'L':
- return(BALLOON_GUEST_LINUX);
+ return BALLOON_GUEST_LINUX;
case 'b':
case 'B':
- return(BALLOON_GUEST_BSD);
+ return BALLOON_GUEST_BSD;
case 's':
case 'S':
- return(BALLOON_GUEST_SOLARIS);
+ return BALLOON_GUEST_SOLARIS;
default:
break;
}
/* unknown */
- return(BALLOON_GUEST_UNKNOWN);
+ return BALLOON_GUEST_UNKNOWN;
}
/*
/*
* Copy statistics out of global structure.
*/
- os_memcpy(stats, &b->stats, sizeof (BalloonStats));
+ OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
/*
* Fill in additional information about size and rates, which is
* BalloonChunk_Create --
*
* Creates a new BalloonChunk object capable of tracking
- * BALLOON_CHUNK_PAGES PPNs.
+ * BALLOON_CHUNK_PAGES PPNs.
*
- * We do not bother to define two versions (NOSLEEP and CANSLEEP)
- * of os_kmalloc because Chunk_Create does not require a new page
- * often.
+ * We do not bother to define two versions (NOSLEEP and CANSLEEP)
+ * of OS_Malloc because Chunk_Create does not require a new page
+ * often.
*
* Results:
- * Returns initialized BalloonChunk, or NULL if error.
+ * On success: initialized BalloonChunk
+ * On failure: NULL
*
* Side effects:
- * None.
+ * None
*
*----------------------------------------------------------------------
*/
+
static BalloonChunk *
BalloonChunk_Create(void)
{
BalloonChunk *chunk;
/* allocate memory, fail if unable */
- if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
- return(NULL);
+ chunk = OS_Malloc(sizeof *chunk);
+ if (chunk == NULL) {
+ return NULL;
}
/* initialize */
- os_bzero(chunk, sizeof(BalloonChunk));
+ OS_MemZero(chunk, sizeof *chunk);
/* everything OK */
- return(chunk);
+ return chunk;
}
+
/*
*----------------------------------------------------------------------
*
BalloonChunk_Destroy(BalloonChunk *chunk)
{
/* reclaim storage */
- os_kfree(chunk, sizeof (BalloonChunk));
+ OS_Free(chunk, sizeof *chunk);
}
/*
Balloon_Init(Balloon *b)
{
/* clear state */
- os_bzero(b, sizeof(Balloon));
+ OS_MemZero(b, sizeof *b);
/* initialize rates */
b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
(void) Balloon_FreePage(b, FALSE);
if (++cnt >= b->rateFree) {
cnt = 0;
- os_yield();
+ OS_Yield();
}
}
}
* Balloon_Reset --
*
* Resets balloon "b" to empty state. Frees all allocated pages
- * and attempts to reset contact with the monitor.
+ * and attempts to reset contact with the monitor.
*
* Results:
* None.
/*
*----------------------------------------------------------------------
*
- * Balloon_BH --
+ * BalloonTimerHandler --
*
* Balloon bottom half handler. Contacts monitor via backdoor
- * to obtain balloon size target, and starts adjusting balloon
- * size to achieve target by allocating or deallocating pages.
- * Resets balloon if requested by the monitor.
+ * to obtain balloon size target, and starts adjusting balloon
+ * size to achieve target by allocating or deallocating pages.
+ * Resets balloon if requested by the monitor.
*
* Results:
* None.
*
*----------------------------------------------------------------------
*/
-static void CDECL
-Balloon_BH(void *data)
+static void
+BalloonTimerHandler(void *clientData)
{
- Balloon *b = (Balloon *) data;
+ Balloon *b = (Balloon *) clientData;
uint32 target;
int status;
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
Balloon_StartTimer(Balloon *b)
{
- os_timer_start();
+ OS_TimerStart();
}
/*
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
Balloon_StopTimer(Balloon *b)
{
- os_timer_stop();
+ OS_TimerStop();
}
* Balloon_ErrorPagesAlloc --
*
* Attempt to add "page" to list of non-balloonable pages
- * associated with "b".
+ * associated with "b".
*
* Results:
- * Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
- * if non-balloonable page list is already full.
+ * On success: BALLOON_SUCCESS
+ * On failure: BALLOON_FAILURE (non-balloonable page list is already full)
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_ErrorPagesFree --
*
* Deallocates all pages on the list of non-balloonable pages
- * associated with "b".
+ * associated with "b".
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
/* free all non-balloonable "error" pages */
for (i = 0; i < b->errors.nextPage; i++) {
- BalloonPrimFreePage(b->errors.page[i]);
+ BalloonPrimFreePage(b->errors.page[i]);
b->errors.page[i] = 0;
STATS_INC(b->stats.primErrorPageFree);
}
* Balloon_AllocPage --
*
* Attempts to allocate a physical page, inflating balloon "b".
- * Informs monitor of PPN for allocated page via backdoor.
+ * Informs monitor of PPN for allocated page via backdoor.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_FreePage --
*
* Attempts to deallocate a physical page, deflating balloon "b".
- * Informs monitor of PPN for deallocated page via backdoor if
- * "monitorUnlock" is specified.
+ * Informs monitor of PPN for deallocated page via backdoor if
+ * "monitorUnlock" is specified.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* BalloonDecreaseRateAlloc --
*
- * Wrapper to quickly reduce the page allocation rate. This function
- * is called only when a CANSLEEP allocation fails. This implies severe
- * memory pressure inside the guest, so quickly decrease the rateAlloc.
+ * Wrapper to quickly reduce the page allocation rate. This function
+ * is called only when a CANSLEEP allocation fails. This implies severe
+ * memory pressure inside the guest, so quickly decrease the rateAlloc.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* BalloonIncreaseRateAlloc --
*
- * Wrapper to increase the page allocation rate.
+ * Wrapper to increase the page allocation rate.
*
- * This function is called when the balloon target is met or
- * b->rateAlloc (or more) pages have been successfully allocated.
- * This implies that the guest may not be under high memory
- * pressure. So let us increase the rateAlloc.
+ * This function is called when the balloon target is met or
+ * b->rateAlloc (or more) pages have been successfully allocated.
+ * This implies that the guest may not be under high memory
+ * pressure. So let us increase the rateAlloc.
*
- * If meeting balloon target requires less than b->rateAlloc
- * pages, then we do not change the page allocation rate.
+ * If meeting balloon target requires less than b->rateAlloc
+ * pages, then we do not change the page allocation rate.
*
- * If the number of pages successfully allocated (nAlloc) is far
- * higher than b->rateAlloc, then it implies that NOSLEEP
- * allocations are highly successful. Therefore, we predict that
- * the guest is under no memory pressure, and so increase
- * b->rateAlloc quickly.
+ * If the number of pages successfully allocated (nAlloc) is far
+ * higher than b->rateAlloc, then it implies that NOSLEEP
+ * allocations are highly successful. Therefore, we predict that
+ * the guest is under no memory pressure, and so increase
+ * b->rateAlloc quickly.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
{
if (BALLOON_RATE_ADAPT) {
if (nAlloc >= b->rateAlloc) {
- uint32 mult = nAlloc / b->rateAlloc;
+ uint32 mult = nAlloc / b->rateAlloc;
b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
BALLOON_RATE_ALLOC_MAX);
}
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
int status, allocations = 0;
uint32 i, nAllocNoSleep, nAllocCanSleep;
- /*
+ /*
* First try NOSLEEP page allocations to inflate balloon.
*
* If we do not throttle nosleep allocations, we can drain all
* As a side-effect, draining free pages helps to inform (force)
* the guest to start swapping if balloon target is not met yet,
* which is a desired behavior. However, balloon driver can consume
- * all available CPU cycles if too many pages are allocated in a
- * second. Therefore, we throttle nosleep allocations even when
- * the guest is not under memory pressure. OTOH, if we have already
- * predicted that the guest is under memory pressure, then we
+ * all available CPU cycles if too many pages are allocated in a
+ * second. Therefore, we throttle nosleep allocations even when
+ * the guest is not under memory pressure. OTOH, if we have already
+ * predicted that the guest is under memory pressure, then we
* slowdown page allocations considerably.
*/
if (b->slowPageAllocationCycles > 0) {
status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
if (status != BALLOON_SUCCESS) {
if (status != BALLOON_PAGE_ALLOC_FAILURE) {
- /*
+ /*
* Not a page allocation failure, so release non-balloonable
* pages, and fail.
*/
Balloon_ErrorPagesFree(b);
return(status);
}
- /*
- * NOSLEEP page allocation failed, so the guest is under memory
- * pressure. Let us slowdown page allocations for next few
+ /*
+ * NOSLEEP page allocation failed, so the guest is under memory
+ * pressure. Let us slowdown page allocations for next few
* cycles so that the guest gets out of memory pressure.
*/
b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
}
if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
- os_yield();
+ OS_Yield();
allocations = 0;
}
}
- /*
+ /*
* Check whether nosleep allocation successfully zapped nAllocNoSleep
* pages.
*/
Balloon_ErrorPagesFree(b);
return(BALLOON_SUCCESS);
} else {
- /*
+ /*
* NOSLEEP allocation failed, so the guest is under memory pressure.
* If already b->rateAlloc pages were zapped, then succeed. Otherwise,
* try CANSLEEP allocation.
}
}
- /*
+ /*
* Use CANSLEEP page allocation to inflate balloon if below target.
*
* Sleep allocations are required only when nosleep allocation fails.
* This implies that the guest is already under memory pressure, so
* let us always throttle canSleep allocations. The total number pages
- * allocated using noSleep and canSleep methods is throttled at
- * b->rateAlloc per second when the guest is under memory pressure.
+ * allocated using noSleep and canSleep methods is throttled at
+ * b->rateAlloc per second when the guest is under memory pressure.
*/
nAllocCanSleep = target - b->nPages;
nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
if(status != BALLOON_SUCCESS) {
if (status == BALLOON_PAGE_ALLOC_FAILURE) {
- /*
+ /*
* CANSLEEP page allocation failed, so guest is under severe
* memory pressure. Quickly decrease rateAlloc.
*/
}
if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
- os_yield();
+ OS_Yield();
allocations = 0;
}
}
- /*
+ /*
* Either met the balloon target or b->rateAlloc pages have been
* successfully zapped.
*/
BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
-
+
/* release non-balloonable pages, succeed */
Balloon_ErrorPagesFree(b);
return(BALLOON_SUCCESS);
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
{
int status, i;
uint32 nFree = b->nPages - target;
-
+
/* limit deallocation rate */
nFree = MIN(nFree, b->rateFree);
/* everything OK */
return(BALLOON_SUCCESS);
}
-
+
/*
*----------------------------------------------------------------------
*
* Balloon_AdjustSize --
*
* Attempts to allocate or deallocate physical pages in order
- * to reach desired "target" size for balloon "b".
+ * to reach desired "target" size for balloon "b".
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Attempts to contact monitor via backdoor to begin operation.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Attempts to contact monitor and report guest OS identity.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
* Balloon_MonitorGetTarget --
*
* Attempts to contact monitor via backdoor to obtain desired
- * balloon size.
+ * balloon size.
*
- * Predicts the maximum achievable balloon size and sends it
- * to vmm => vmkernel via vEbx register.
+ * Predicts the maximum achievable balloon size and sends it
+ * to vmm => vmkernel via vEbx register.
*
- * os_predict_max_balloon_pages() returns either predicted max balloon
- * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
- * vmkernel uses global config options for determining a guest's max
- * balloon size. Note that older vmballoon drivers set vEbx to
- * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
- * will fallback to config-based max balloon size estimation.
+ * OS_PredictMaxReservedPages() returns either predicted max balloon
+ * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
+ * vmkernel uses global config options for determining a guest's max
+ * balloon size. Note that older vmballoon drivers set vEbx to
+ * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
+ * will fallback to config-based max balloon size estimation.
*
* Results:
- * If successful, sets "target" to value obtained from monitor,
+ * If successful, sets "target" to value obtained from monitor,
* and returns BALLOON_SUCCESS. Otherwise returns error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
- bp.in.size = os_predict_max_balloon_pages();
+ bp.in.size = OS_PredictMaxReservedPages();
/* invoke backdoor */
Backdoor_Balloon(&bp);
*
* Balloon_MonitorLockPage --
*
- * Attempts to contact monitor and add PPN containing "addr"
- * to set of "balloon locked" pages.
+ * Attempts to contact monitor and add PPN containing "addr"
+ * to set of "balloon locked" pages.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
*
* Balloon_MonitorUnlockPage --
*
- * Attempts to contact monitor and remove PPN containing "addr"
- * from set of "balloon locked" pages.
+ * Attempts to contact monitor and remove PPN containing "addr"
+ * from set of "balloon locked" pages.
*
* Results:
- * Returns BALLOON_SUCCESS if successful, otherwise error code.
+ * Returns BALLOON_SUCCESS if successful, otherwise error code.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
return(BALLOON_FAILURE);
}
+ /* os-specific initialization */
+ OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
+
/* initialize global state */
Balloon_Init(b);
- /* os-specific initialization */
- os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
- os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
-
/* start timer */
+ OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
Balloon_StartTimer(b);
/* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
static void
Balloon_Deallocate(b);
/* os-specific cleanup */
- os_cleanup();
-}
+ OS_Cleanup();
+}
int init_module(void)
{
#include <math.h>
#include <limits.h>
+#ifndef WIN32
+# include <arpa/inet.h>
+#endif
+
#include "vmware.h"
#include "buildNumber.h"
#include "conf.h"
typedef struct _GuestInfoCache{
char value[INFO_MAX][MAX_VALUE_LEN]; /* Stores values of all key-value pairs. */
- GuestNicList nicInfo;
+ NicInfoV3 *nicInfo;
GuestDiskInfo diskInfo;
} GuestInfoCache;
static Bool GuestInfoUpdateVmdb(ToolsAppCtx *ctx, GuestInfoType infoType, void *info);
static Bool SetGuestInfo(ToolsAppCtx *ctx, GuestInfoType key,
const char *value, char delimiter);
-static Bool NicInfoChanged(GuestNicList *nicInfo);
+static Bool NicInfoChanged(NicInfoV3 *nicInfo);
static Bool DiskInfoChanged(PGuestDiskInfo diskInfo);
static void GuestInfoClearCache(void);
-static int PrintNicInfo(GuestNicList *nicInfo, int (*PrintFunc)(const char *, ...));
+static GuestNicList *NicInfoV3ToV2(const NicInfoV3 *infoV3);
/**
char osNameFull[MAX_VALUE_LEN];
char osName[MAX_VALUE_LEN];
gboolean disableQueryDiskInfo;
- GuestNicList nicInfo;
+ NicInfoV3 *nicInfo = NULL;
GuestDiskInfo diskInfo;
#if defined(_WIN32) || defined(linux)
GuestMemInfo vmStats = {0};
g_debug("Entered guest info gather.\n");
- memset(&nicInfo, 0, sizeof nicInfo);
-
/* Send tools version. */
if (!GuestInfoUpdateVmdb(ctx, INFO_BUILD_NUMBER, BUILD_NUMBER)) {
/*
/* Get NIC information. */
if (!GuestInfo_GetNicInfo(&nicInfo)) {
g_warning("Failed to get nic info.\n");
- } else if (NicInfoChanged(&nicInfo)) {
- if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, &nicInfo)) {
+ } else if (NicInfoChanged(nicInfo)) {
+ if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, nicInfo)) {
/*
* Update the cache. Release the memory previously used by the cache,
* and copy the new information into the cache.
*/
- VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo);
+ GuestInfo_FreeNicInfo(gInfoCache.nicInfo);
gInfoCache.nicInfo = nicInfo;
} else {
g_warning("Failed to update VMDB.\n");
}
} else {
g_debug("Nic info not changed.\n");
- VMX_XDR_FREE(xdr_GuestNicList, &nicInfo);
+ GuestInfo_FreeNicInfo(nicInfo);
}
/* Send the uptime to VMX so that it can detect soft resets. */
*----------------------------------------------------------------------
*/
-Bool
-GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info, // IN
+void
+GuestInfoConvertNicInfoToNicInfoV1(NicInfoV3 *info, // IN
GuestNicInfoV1 *infoV1) // OUT
{
uint32 maxNics;
u_int i;
- if ((NULL == info) ||
- (NULL == infoV1)) {
- return FALSE;
- }
+ ASSERT(info);
+ ASSERT(infoV1);
maxNics = MIN(info->nics.nics_len, MAX_NICS);
infoV1->numNicEntries = maxNics;
XDRUTIL_FOREACH(i, info, nics) {
u_int j;
uint32 maxIPs;
- GuestNic *nic = XDRUTIL_GETITEM(info, nics, i);
+ GuestNicV3 *nic = XDRUTIL_GETITEM(info, nics, i);
Str_Strcpy(infoV1->nicList[i].macAddress,
nic->macAddress,
infoV1->nicList[i].numIPs = 0;
XDRUTIL_FOREACH(j, nic, ips) {
- VmIpAddress *ip = XDRUTIL_GETITEM(nic, ips, j);
+ IpAddressEntry *ip = XDRUTIL_GETITEM(nic, ips, j);
+ TypedIpAddress *typedIp = &ip->ipAddressAddr;
+
+ if (typedIp->ipAddressAddrType != IAT_IPV4) {
+ continue;
+ }
- if (strlen(ip->ipAddress) < sizeof infoV1->nicList[i].ipAddress[j]) {
- Str_Strcpy(infoV1->nicList[i].ipAddress[j],
- ip->ipAddress,
- sizeof infoV1->nicList[i].ipAddress[j]);
+ if (NetUtil_InetNToP(AF_INET, typedIp->ipAddressAddr.InetAddress_val,
+ infoV1->nicList[i].ipAddress[j],
+ sizeof infoV1->nicList[i].ipAddress[j])) {
infoV1->nicList[i].numIPs++;
if (infoV1->nicList[i].numIPs == maxIPs) {
break;
}
- } else {
- g_debug("Ignoring IPV6 address for compatibility.\n");
}
}
break;
}
}
-
- return TRUE;
}
case INFO_IPADDRESS:
{
- static Bool isCmdV1 = FALSE;
+ static NicInfoVersion supportedVersion = NIC_INFO_V3;
+ NicInfoV3 *nicInfoV3 = (NicInfoV3 *)info;
char *reply = NULL;
size_t replyLen;
Bool status;
- if (FALSE == isCmdV1) {
- /* 13 = max size of string representation of an int + 3 spaces. */
- char request[sizeof GUEST_INFO_COMMAND + 13];
- GuestNicProto message;
- XDR xdrs;
-
- if (DynXdr_Create(&xdrs) == NULL) {
- return FALSE;
- }
+nicinfo_fsm:
+ switch (supportedVersion) {
+ case NIC_INFO_V3:
+ case NIC_INFO_V2:
+ {
+ /*
+ * 13 = max size of string representation of an int + 3 spaces.
+ * XXX Ditch the magic numbers.
+ */
+ char request[sizeof GUEST_INFO_COMMAND + 13];
+ GuestNicProto message = {0};
+ GuestNicList *nicList = NULL;
+ NicInfoVersion fallbackVersion;
+ XDR xdrs;
+
+ if (DynXdr_Create(&xdrs) == NULL) {
+ return FALSE;
+ }
- /* Add the RPC preamble: message name, and type. */
- Str_Sprintf(request, sizeof request, "%s %d ",
- GUEST_INFO_COMMAND, INFO_IPADDRESS_V2);
+ /* Add the RPC preamble: message name, and type. */
+ Str_Sprintf(request, sizeof request, "%s %d ",
+ GUEST_INFO_COMMAND, INFO_IPADDRESS_V2);
+
+ /*
+ * Fill in message according to the version we'll attempt. Also
+ * note which version we'll fall back to should the VMX reject
+ * our update.
+ */
+ if (supportedVersion == NIC_INFO_V3) {
+ message.ver = NIC_INFO_V3;
+ message.GuestNicProto_u.nicInfoV3 = nicInfoV3;
+
+ fallbackVersion = NIC_INFO_V2;
+ } else {
+ nicList = NicInfoV3ToV2(nicInfoV3);
+ message.ver = NIC_INFO_V2;
+ message.GuestNicProto_u.nicsV2 = nicList;
+
+ fallbackVersion = NIC_INFO_V1;
+ }
- message.ver = NIC_INFO_V2;
- message.GuestNicProto_u.nicsV2 = info;
+ /* Write preamble and serialized nic info to XDR stream. */
+ if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) ||
+ !xdr_GuestNicProto(&xdrs, &message)) {
+ g_warning("Error serializing nic info v2 data.");
+ DynXdr_Destroy(&xdrs, TRUE);
+ return FALSE;
+ }
- /* Write preamble and serialized nic info to XDR stream. */
- if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) ||
- !xdr_GuestNicProto(&xdrs, &message)) {
- g_warning("Error serializing nic info v2 data.");
+ status = RpcChannel_Send(ctx->rpc,
+ DynXdr_Get(&xdrs),
+ xdr_getpos(&xdrs),
+ &reply,
+ &replyLen);
DynXdr_Destroy(&xdrs, TRUE);
- return FALSE;
- }
- status = RpcChannel_Send(ctx->rpc,
- DynXdr_Get(&xdrs),
- xdr_getpos(&xdrs),
- &reply,
- &replyLen);
- DynXdr_Destroy(&xdrs, TRUE);
- if (!status) {
- g_warning("Failed to send V2 nic info message.\n");
- }
+ if (nicList) {
+ free(nicList);
+ nicList = NULL;
+ }
- if (g_key_file_get_boolean(ctx->config, "guestinfo", "printNicInfo", NULL)) {
- PrintNicInfo((GuestNicList *) info,
- (int (*)(const char *fmt, ...)) RpcVMX_Log);
+ if (!status) {
+ g_warning("NicInfo update failed: version %u, reply \"%s\".\n",
+ supportedVersion, reply);
+ supportedVersion = fallbackVersion;
+ vm_free(reply);
+ reply = NULL;
+ goto nicinfo_fsm;
+ }
}
- } else {
- status = FALSE;
- }
- if (!status) {
- /*
- * Could be that we are talking to the old protocol that GuestNicInfo is
- * still fixed size. Another try to send the fixed sized Nic info.
- */
- char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND +
+ break;
+
+ case NIC_INFO_V1:
+ {
+ /*
+ * Could be that we are talking to the old protocol that
+ * GuestNicInfo is still fixed size. Another try to send the
+ * fixed sized Nic info.
+ */
+ char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND +
2 + /* 2 bytes are for digits of infotype. */
3 * sizeof (char)]; /* 3 spaces */
- GuestNicInfoV1 nicInfo;
+ GuestNicInfoV1 nicInfo;
+
+ Str_Sprintf(request,
+ sizeof request,
+ "%s %d ",
+ GUEST_INFO_COMMAND,
+ INFO_IPADDRESS);
+
+ GuestInfoConvertNicInfoToNicInfoV1(nicInfoV3, &nicInfo);
- vm_free(reply);
- reply = NULL;
-
- Str_Sprintf(request,
- sizeof request,
- "%s %d ",
- GUEST_INFO_COMMAND,
- INFO_IPADDRESS);
- if (GuestInfoConvertNicInfoToNicInfoV1(info, &nicInfo)) {
memcpy(request + strlen(request),
&nicInfo,
sizeof(GuestNicInfoV1));
&replyLen);
g_debug("Just sent fixed sized nic info message.\n");
+
if (!status) {
g_debug("Failed to update fixed sized nic information\n");
vm_free(reply);
return FALSE;
}
- isCmdV1 = TRUE;
- } else {
- return FALSE;
}
+ break;
+ default:
+ NOT_REACHED();
}
g_debug("Updated new NIC information\n");
*-----------------------------------------------------------------------------
*/
-GuestNic *
-GuestInfoFindMacAddress(GuestNicList *nicInfo, // IN/OUT
+GuestNicV3 *
+GuestInfoFindMacAddress(NicInfoV3 *nicInfo, // IN/OUT
const char *macAddress) // IN
{
u_int i;
for (i = 0; i < nicInfo->nics.nics_len; i++) {
- GuestNic *nic = &nicInfo->nics.nics_val[i];
+ GuestNicV3 *nic = &nicInfo->nics.nics_val[i];
if (strncmp(nic->macAddress, macAddress, NICINFO_MAC_LEN) == 0) {
return nic;
}
*/
Bool
-NicInfoChanged(GuestNicList *nicInfo) // IN
+NicInfoChanged(NicInfoV3 *nicInfo) // IN
{
u_int i;
- GuestNicList *cachedNicInfo = &gInfoCache.nicInfo;
+ NicInfoV3 *cachedNicInfo = gInfoCache.nicInfo;
+
+ if (!cachedNicInfo) {
+ return TRUE;
+ }
+
+ /*
+ * XXX Add routing, DNS, WINS comparisons.
+ */
if (cachedNicInfo->nics.nics_len != nicInfo->nics.nics_len) {
g_debug("Number of nics has changed\n");
for (i = 0; i < cachedNicInfo->nics.nics_len; i++) {
u_int j;
- GuestNic *cachedNic = &cachedNicInfo->nics.nics_val[i];
- GuestNic *matchedNic;
+ GuestNicV3 *cachedNic = &cachedNicInfo->nics.nics_val[i];
+ GuestNicV3 *matchedNic;
/* Find the corresponding nic in the new nic info. */
matchedNic = GuestInfoFindMacAddress(nicInfo, cachedNic->macAddress);
/* Which IP addresses have been modified for this NIC? */
for (j = 0; j < cachedNic->ips.ips_len; j++) {
- VmIpAddress *cachedIp = &cachedNic->ips.ips_val[j];
+ TypedIpAddress *cachedIp = &cachedNic->ips.ips_val[j].ipAddressAddr;
Bool foundIP = FALSE;
+ ssize_t cmpsz =
+ cachedIp->ipAddressAddrType == IAT_IPV4 ? 4 :
+ cachedIp->ipAddressAddrType == IAT_IPV6 ? 16 :
+ -1;
u_int k;
+ /* XXX */
+ ASSERT(cmpsz != -1);
+
for (k = 0; k < matchedNic->ips.ips_len; k++) {
- VmIpAddress *matchedIp = &matchedNic->ips.ips_val[k];
- if (0 == strncmp(cachedIp->ipAddress,
- matchedIp->ipAddress,
- NICINFO_MAX_IP_LEN)) {
+ TypedIpAddress *matchedIp =
+ &matchedNic->ips.ips_val[k].ipAddressAddr;
+ if (cachedIp->ipAddressAddrType == matchedIp->ipAddressAddrType &&
+ memcmp(cachedIp->ipAddressAddr.InetAddress_val,
+ matchedIp->ipAddressAddr.InetAddress_val,
+ cmpsz) == 0) {
foundIP = TRUE;
break;
}
if (FALSE == foundIP) {
/* This ip address couldn't be found and has been modified. */
+#if 0
g_debug("MAC address %s, ipaddress %s deleted\n",
cachedNic->macAddress,
cachedIp->ipAddress);
+#endif
return TRUE;
}
}
-/*
- *----------------------------------------------------------------------------
- *
- * PrintNicInfo --
- *
- * Print NIC info struct using the specified print function.
- *
- * Results:
- * Sum of return values of print function (for printf, this will be the
- * number of characters printed).
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-PrintNicInfo(GuestNicList *nicInfo, // IN
- int (*PrintFunc)(const char *, ...)) // IN
-{
- int ret = 0;
- u_int i = 0;
-
- ret += PrintFunc("NicInfo: count: %ud\n", nicInfo->nics.nics_len);
- for (i = 0; i < nicInfo->nics.nics_len; i++) {
- u_int j;
- GuestNic *nic = &nicInfo->nics.nics_val[i];
-
- ret += PrintFunc("NicInfo: nic [%d/%d] mac: %s",
- i+1,
- nicInfo->nics.nics_len,
- nic->macAddress);
-
- for (j = 0; j < nic->ips.ips_len; j++) {
- VmIpAddress *ipAddress = &nic->ips.ips_val[j];
-
- ret += PrintFunc("NicInfo: nic [%d/%d] IP [%d/%d]: %s",
- i+1,
- nicInfo->nics.nics_len,
- j+1,
- nic->ips.ips_len,
- ipAddress->ipAddress);
- }
- }
-
- return ret;
-}
-
-
/*
*----------------------------------------------------------------------
*
gInfoCache.value[i][0] = 0;
}
- VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo);
- memset(&gInfoCache.nicInfo, 0, sizeof gInfoCache.nicInfo);
+ GuestInfo_FreeNicInfo(gInfoCache.nicInfo);
+ gInfoCache.nicInfo = NULL;
+}
+
+
+/*
+ ***********************************************************************
+ * NicInfoV3ToV2 -- */ /**
+ *
+ * @brief Converts the NicInfoV3 NIC list to a GuestNicList.
+ *
+ * @note This function performs @e shallow copies of things such as
+ * IP address array, making it depend on the source NicInfoV3.
+ * In other words, do @e not free NicInfoV3 before freeing the
+ * returned pointer.
+ *
+ * @param[in] infoV3 Source NicInfoV3 container.
+ *
+ * @return Pointer to a GuestNicList. Caller should free it using
+ * plain ol' @c free.
+ *
+ ***********************************************************************
+ */
+
+static GuestNicList *
+NicInfoV3ToV2(const NicInfoV3 *infoV3)
+{
+ GuestNicList *nicList;
+ unsigned int i, j;
+
+ nicList = Util_SafeCalloc(sizeof *nicList, 1);
+
+ XDRUTIL_ARRAYAPPEND(nicList, nics, infoV3->nics.nics_len);
+ XDRUTIL_FOREACH(i, infoV3, nics) {
+ GuestNicV3 *nic = XDRUTIL_GETITEM(infoV3, nics, i);
+ GuestNic *oldNic = XDRUTIL_GETITEM(nicList, nics, i);
+
+ Str_Strcpy(oldNic->macAddress, nic->macAddress, sizeof oldNic->macAddress);
+
+ XDRUTIL_ARRAYAPPEND(oldNic, ips, nic->ips.ips_len);
+
+ XDRUTIL_FOREACH(j, nic, ips) {
+ IpAddressEntry *ipEntry = XDRUTIL_GETITEM(nic, ips, j);
+ TypedIpAddress *ip = &ipEntry->ipAddressAddr;
+ VmIpAddress *oldIp = XDRUTIL_GETITEM(oldNic, ips, j);
+
+ /* XXX */
+ oldIp->addressFamily = (ip->ipAddressAddrType == IAT_IPV4) ?
+ NICINFO_ADDR_IPV4 : NICINFO_ADDR_IPV6;
+
+ NetUtil_InetNToP(ip->ipAddressAddrType == IAT_IPV4 ?
+ AF_INET : AF_INET6,
+ ip->ipAddressAddr.InetAddress_val, oldIp->ipAddress,
+ sizeof oldIp->ipAddress);
+
+ Str_Sprintf(oldIp->subnetMask, sizeof oldIp->subnetMask, "%u",
+ ipEntry->ipAddressPrefixLength);
+ }
+ }
+
+ return nicList;
}
vmResumed = FALSE;
/* Add the first timer event. */
- src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10);
- VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL);
- g_source_unref(src);
+ if (ctx->rpc) {
+ src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10);
+ VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL);
+ g_source_unref(src);
+ }
return ®Data;
}
*
* Long story short, we shouldn't care if this function fails.
*/
- if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+ if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
g_warning("Setting HGFS server capability failed!\n");
}
appName,
set);
- if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+ if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
g_warning("Setting resolution_server capability failed!\n");
}
libvix_la_SOURCES += foundryToolsDaemon.c
libvix_la_SOURCES += vixPlugin.c
libvix_la_SOURCES += $(top_srcdir)/lib/vixTools/vixTools.c
+libvix_la_SOURCES += $(top_srcdir)/lib/hgfsHelper/hgfsHelperPosix.c
if HAVE_X11
install-data-hook:
#include "hgfsDevLinux.h"
#endif
-#ifndef __FreeBSD__
-#include "netutil.h"
-#endif
-
/* Only Win32 and Linux use impersonation functions. */
#if !defined(__FreeBSD__) && !defined(sun)
#include "impersonate.h"
{
g_debug("*** %s\n", __FUNCTION__);
ASSERT(gBackupState != NULL);
- ASSERT(gBackupState->machineState == VMBACKUP_MSTATE_IDLE);
if (gBackupState->currentOp != NULL) {
VmBackup_Cancel(gBackupState->currentOp);
/**
- * Reloads the config file and re-configure the logging subsystem if the
- * log file was updated. If the config file is being loaded for the first
- * time, try to upgrade it to the new version if an old version is
- * detected.
+ * Timer callback that just calls ToolsCore_ReloadConfig().
*
* @param[in] clientData Service state.
*
*/
static gboolean
-ToolsCoreReloadConfig(gpointer clientData)
+ToolsCoreConfFileCb(gpointer clientData)
{
- ToolsServiceState *state = clientData;
- char *confFile = state->configFile;
- gboolean loaded = TRUE;
-
- if (confFile == NULL) {
- confFile = VMTools_GetToolsConfFile();
- }
-
- if (state->ctx.config == NULL) {
- state->ctx.config = VMTools_LoadConfig(confFile,
- G_KEY_FILE_NONE,
- state->mainService);
- state->configMtime = time(NULL);
- if (state->ctx.config == NULL) {
- /* Couldn't load the config file. Just create an empty dictionary. */
- state->ctx.config = g_key_file_new();
- }
- } else if (VMTools_ReloadConfig(confFile,
- G_KEY_FILE_NONE,
- &state->ctx.config,
- &state->configMtime)) {
- g_debug("Config file reloaded.\n");
- } else {
- loaded = FALSE;
- }
-
- if (loaded) {
- VMTools_ConfigLogging(state->ctx.config);
- if (state->log) {
- VMTools_EnableLogging(state->log);
- }
- }
-
- if (state->configFile == NULL) {
- g_free(confFile);
- }
+ ToolsCore_ReloadConfig(clientData, FALSE);
return TRUE;
}
}
+/**
+ * Reloads the config file and re-configure the logging subsystem if the
+ * log file was updated. If the config file is being loaded for the first
+ * time, try to upgrade it to the new version if an old version is
+ * detected.
+ *
+ * @param[in] state Service state.
+ * @param[in] force Whether to force reconfiguration of the logging
+ * subsystem.
+ */
+
+void
+ToolsCore_ReloadConfig(ToolsServiceState *state,
+ gboolean force)
+{
+ char *confFile;
+ gboolean loaded = TRUE;
+
+ VMTools_SetDefaultLogDomain(state->name);
+
+ confFile = g_strdup(state->configFile);
+ if (confFile == NULL) {
+ confFile = VMTools_GetToolsConfFile();
+ }
+
+ if (state->ctx.config == NULL) {
+ state->ctx.config = VMTools_LoadConfig(confFile,
+ G_KEY_FILE_NONE,
+ state->mainService);
+ state->configMtime = time(NULL);
+ if (state->ctx.config == NULL) {
+ /* Couldn't load the config file. Just create an empty dictionary. */
+ state->ctx.config = g_key_file_new();
+ }
+ } else if (VMTools_ReloadConfig(confFile,
+ G_KEY_FILE_NONE,
+ &state->ctx.config,
+ &state->configMtime)) {
+ g_debug("Config file reloaded.\n");
+ } else {
+ loaded = FALSE;
+ }
+
+ if (force || loaded) {
+ VMTools_ConfigLogging(state->ctx.config);
+ if (state->log) {
+ VMTools_EnableLogging(state->log);
+ }
+ }
+
+ g_free(confFile);
+}
+
+
/**
* Performs any initial setup steps for the service's main loop.
*
g_thread_init(NULL);
}
- VMTools_SetDefaultLogDomain(state->name);
- ToolsCoreReloadConfig(state);
+ ToolsCore_ReloadConfig(state, FALSE);
/* Initializes the app context. */
gctx = g_main_context_default();
goto error;
}
- if (!state->ctx.rpc->start(state->ctx.rpc)) {
+ /*
+ * Start the RPC channel if it's been created. The channel may be NULL if this is
+ * not running in the context of a VM.
+ */
+ if (state->ctx.rpc && !state->ctx.rpc->start(state->ctx.rpc)) {
goto error;
}
int
ToolsCore_Run(ToolsServiceState *state)
{
- g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreReloadConfig, state);
+ /*
+ * If there's no RPC channel (not in a VM) then there's no point in trying to
+ * run the loop, just exit with a '0' return status (see bug 297528 for why '0').
+ */
+ if (!state->ctx.rpc) {
+ return 0;
+ }
+
+ g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreConfFileCb, state);
+
#if defined(__APPLE__)
ToolsCore_CFRunLoop(state);
#else
static ToolsServiceState gState = { NULL, };
+
+/**
+ * Reloads the service configuration - including forcing rotation of log
+ * files by reinitializing the logging subsystem.
+ *
+ * @param[in] info Unused.
+ * @param[in] data Service state.
+ *
+ * @return TRUE
+ */
+
+static gboolean
+ToolsCoreSigHUPCb(const siginfo_t *info,
+ gpointer data)
+{
+ VMTools_ResetLogging(TRUE);
+ ToolsCore_ReloadConfig(data, TRUE);
+ return TRUE;
+}
+
+
/**
* Handles a signal that would terminate the process. Asks the main loop
* to exit nicely.
src = VMTools_NewSignalSource(SIGHUP);
VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
- ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
+ ToolsCoreSigHUPCb, &gState, NULL);
g_source_unref(src);
src = VMTools_NewSignalSource(SIGINT);
&pcaps);
if (pcaps != NULL) {
- ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE);
+ if (state->ctx.rpc) {
+ ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE);
+ }
g_array_free(pcaps, TRUE);
}
gboolean
ToolsCore_LoadPlugins(ToolsServiceState *state);
+void
+ToolsCore_ReloadConfig(ToolsServiceState *state,
+ gboolean force);
+
void
ToolsCore_RegisterPlugins(ToolsServiceState *state);
} else {
/*
* Currently we try to bring up an RpcIn channel, which will only run
- * inside a Virtual Machine. We want to exit with a "success" status
- * if this check fails, though. (See bug 297528 for why.)
+ * inside a Virtual Machine. Some plugins may still want to launch and at
+ * least begin even in not in a VM (typically because the installation is dual
+ * purposed between a VM and Bootcamp) - plugins may wish to undo some state
+ * if not in a VM.
*
* XXX: this should be relaxed when we try to bring up a VMCI or TCP channel.
*/
if (!state->ctx.isVMware) {
g_warning("The %s service needs to run inside a virtual machine.\n",
state->name);
- exit(0);
+ state->ctx.rpc = NULL;
+ } else {
+ state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx);
}
-
- state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx);
app = ToolsCore_GetTcloName(state);
ASSERT(app != NULL);
}
- RpcChannel_Setup(state->ctx.rpc,
- app,
- mainCtx,
- &state->ctx,
- ToolsCoreCheckReset,
- state);
-
- /* Register the "built in" RPCs. */
- for (i = 0; i < ARRAYSIZE(rpcs); i++) {
- RpcChannelCallback *rpc = &rpcs[i];
- rpc->clientData = state;
- RpcChannel_RegisterCallback(state->ctx.rpc, rpc);
+ if (state->ctx.rpc) {
+ RpcChannel_Setup(state->ctx.rpc,
+ app,
+ mainCtx,
+ &state->ctx,
+ ToolsCoreCheckReset,
+ state);
+
+ /* Register the "built in" RPCs. */
+ for (i = 0; i < ARRAYSIZE(rpcs); i++) {
+ RpcChannelCallback *rpc = &rpcs[i];
+ rpc->clientData = state;
+ RpcChannel_RegisterCallback(state->ctx.rpc, rpc);
+ }
}
return TRUE;
SUBDIRS += vmrpcdbg
SUBDIRS += testDebug
SUBDIRS += testPlugin
+SUBDIRS += testVmblock
install-exec-local:
rm -f $(DESTDIR)$(TEST_PLUGIN_INSTALLDIR)/*.a
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_PROGRAMS = vmware-testvmblock-legacy
+noinst_PROGRAMS += vmware-testvmblock-manual-legacy
+
+if HAVE_FUSE
+ noinst_PROGRAMS += vmware-testvmblock-fuse
+ noinst_PROGRAMS += vmware-testvmblock-manual-fuse
+endif
+
+AM_CFLAGS =
+AM_CFLAGS += -DVMX86_DEVEL
+AM_CFLAGS += -DVMX86_DEBUG
+
+AM_LDFLAGS =
+AM_LDFLAGS += -lpthread
+
+vmware_testvmblock_legacy_SOURCES = vmblocktest.c
+
+vmware_testvmblock_manual_legacy_SOURCES = manual-blocker.c
+
+vmware_testvmblock_fuse_CFLAGS = $(AM_CFLAGS) -Dvmblock_fuse
+vmware_testvmblock_fuse_SOURCES = vmblocktest.c
+
+vmware_testvmblock_manual_fuse_CFLAGS = $(AM_CFLAGS) -Dvmblock_fuse
+vmware_testvmblock_manual_fuse_SOURCES = manual-blocker.c
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * manual-blocker.c --
+ *
+ * A small test program for manually manipulating vmblock.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "vmblock_user.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * main --
+ *
+ * Takes the target file to block as a command line arg. Sits in a loop
+ * waiting for commands.
+ *
+ * Results:
+ * Returns 0 on success and nonzero on failure.
+ *
+ * Side effects:
+ * None/all.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+main(int argc,
+ char *argv[])
+{
+ int status;
+ char op;
+
+ if (argc < 2 ||
+ strcmp(argv[1], "-h") == 0 ||
+ strcmp(argv[1], "--help") == 0) {
+ printf("Usage: %s <path>\n", argv[0]);
+ puts("a to Add a block, d to Delete a block, or l to List blocks (to"
+ " vmblock's log).\n");
+ return 1;
+ }
+
+ int fd = open(VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE);
+ if (fd <= 0) {
+ perror("open");
+ return 2;
+ }
+ printf("Opened " VMBLOCK_DEVICE " as fd %d.\n", fd);
+
+ while (1) {
+ op = getchar();
+ if (op == 'a') {
+ status = VMBLOCK_CONTROL(fd, VMBLOCK_ADD_FILEBLOCK, argv[1]);
+ if (status != 0) {
+ perror(NULL);
+ } else {
+ printf("%s blocked.\n", argv[1]);
+ }
+ } else if (op == 'd') {
+ status = VMBLOCK_CONTROL(fd, VMBLOCK_DEL_FILEBLOCK, argv[1]);
+ if (status != 0) {
+ perror(NULL);
+ } else {
+ printf("%s unblocked.\n", argv[1]);
+ }
+ } else if (op == 'l') {
+ status = VMBLOCK_CONTROL(fd, VMBLOCK_LIST_FILEBLOCKS, argv[1]);
+ if (status != 0) {
+ perror(NULL);
+ } else {
+ printf("Check vmblock's log for list of blocks.\n");
+ }
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * vmblocktest.c --
+ *
+ * Test program for the vmblock file system. Ensures correctness and
+ * stability.
+ *
+ */
+
+#if !defined(linux) && !defined(sun) && !defined(__FreeBSD__) && !defined(vmblock_fuse)
+# error "vmblocktest.c needs to be ported to your OS."
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <semaphore.h>
+#ifdef sun
+# include <stropts.h>
+#endif
+
+#include "vmblock_user.h"
+#include "vm_basic_types.h"
+
+#define BLOCKROOT VMBLOCK_MOUNT_POINT "/"
+#define CONTROLFILE VMBLOCK_DEVICE
+#define CONTROLFILE_MODE VMBLOCK_DEVICE_MODE
+#define REALROOT "/tmp/VMwareDnD/"
+#define FILENAME "/foo"
+#define ACCESSORFULLNAME(dir) BLOCKROOT dir FILENAME
+#define BLOCKERFULLNAME(dir) REALROOT dir
+
+#define lprintf(...) \
+ do { \
+ pthread_mutex_lock(&print_lock); \
+ printf(__VA_ARGS__); \
+ fflush(stdout); \
+ pthread_mutex_unlock(&print_lock); \
+ } while(0)
+
+#define lfprintf(stream, ...) \
+ do { \
+ pthread_mutex_lock(&print_lock); \
+ fprintf(stream, __VA_ARGS__); \
+ fflush(stream); \
+ pthread_mutex_unlock(&print_lock); \
+ } while(0)
+
+#define Log(fmt, args...) lprintf(fmt, ## args)
+#define ERROR(fmt, args...) lfprintf(stderr, fmt, ## args)
+#define THREAD_LOG(fmt, args...) lprintf(" (%lx) " fmt, (unsigned long)pthread_self(), ## args)
+#define THREAD_ERROR(fmt, args...) lfprintf(stderr, " (%"FMTPID") " fmt, getpid(), ## args)
+
+#if defined (linux) || defined(__FreeBSD__)
+# define os_thread_yield() sched_yield()
+#elif defined(sun)
+# define os_thread_yield() yield()
+#endif
+
+/*
+ * This program may optionally throttle accessor thread generation
+ * via POSIX semaphores.
+ */
+#if defined(USE_SEMAPHORES)
+sem_t sem;
+# define SEM_THREADS (unsigned int)10
+# define SEM_INIT() sem_init(&sem, 0, SEM_THREADS)
+# define SEM_DESTROY() sem_destroy(&sem)
+# define SEM_WAIT() sem_wait(&sem)
+# define SEM_POST() sem_post(&sem)
+# define PTHREAD_SEMAPHORE_CLEANUP() pthread_cleanup_push(sem_post, \
+ (void *)&sem)
+#else
+# define SEM_INIT()
+# define SEM_DESTROY()
+# define SEM_WAIT()
+# define SEM_POST()
+# define PTHREAD_SEMAPHORE_CLEANUP()
+#endif
+
+/* Types */
+typedef struct FileState {
+ /* Accessors will access the file through the vmblock namespace */
+ char *accessorName;
+ /* The blocker will add blocks using the real file's name */
+ char *blockerName;
+ Bool blocked;
+ unsigned int waiters;
+} FileState;
+
+typedef struct ThreadInfo {
+ int blockFd;
+ pthread_mutex_t *lock;
+ FileState *files;
+ size_t filesArraySize;
+ unsigned int sleepTime;
+} ThreadInfo;
+
+/* Variables */
+static Bool programQuit = FALSE;
+static FileState files[] = {
+ { ACCESSORFULLNAME("0"), BLOCKERFULLNAME("0"), FALSE, 0 },
+ { ACCESSORFULLNAME("1"), BLOCKERFULLNAME("1"), FALSE, 0 },
+ { ACCESSORFULLNAME("2"), BLOCKERFULLNAME("2"), FALSE, 0 },
+ { ACCESSORFULLNAME("3"), BLOCKERFULLNAME("3"), FALSE, 0 },
+ { ACCESSORFULLNAME("4"), BLOCKERFULLNAME("4"), FALSE, 0 },
+ { ACCESSORFULLNAME("5"), BLOCKERFULLNAME("5"), FALSE, 0 },
+ { ACCESSORFULLNAME("6"), BLOCKERFULLNAME("6"), FALSE, 0 },
+ { ACCESSORFULLNAME("7"), BLOCKERFULLNAME("7"), FALSE, 0 },
+ { ACCESSORFULLNAME("8"), BLOCKERFULLNAME("8"), FALSE, 0 },
+ { ACCESSORFULLNAME("9"), BLOCKERFULLNAME("9"), FALSE, 0 },
+};
+
+/* Thread entry points */
+static void *blocker(void *arg);
+static void *accessor(void *arg);
+
+/* Utility functions */
+static Bool addBlock(int fd, char const *filename);
+static Bool delBlock(int fd, char const *filename);
+static Bool listBlocks(int fd);
+#ifdef VMBLOCK_PURGE_FILEBLOCKS
+static Bool purgeBlocks(int fd);
+#endif
+static unsigned int getRand(unsigned int max);
+static void sighandler(int sig);
+
+pthread_mutex_t print_lock;
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * main --
+ *
+ * Does all necessary setup then starts the blocker thread and continually
+ * starts accessor threads.
+ *
+ * Results:
+ * EXIT_SUCCESS and EXIT_FAILURE.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+main(int argc,
+ char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+ int i;
+ int blockFd;
+ char *progname;
+ pthread_t blockerThread;
+ pthread_mutex_t filesLock;
+ pthread_attr_t attr;
+ ThreadInfo info;
+ int count;
+
+ progname = basename(argv[0]);
+ pthread_mutex_init(&filesLock, NULL);
+
+ SEM_INIT();
+ pthread_mutex_init(&print_lock, NULL);
+
+ /* Open device user to add/delete blocks */
+ blockFd = open(CONTROLFILE, CONTROLFILE_MODE);
+ if (blockFd < 0) {
+ ERROR("%s: could not open " CONTROLFILE "\n", progname);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Provide ability to just list blocks */
+ if (argc > 1) {
+ if (strcmp(argv[1], "-list") == 0) {
+ listBlocks(blockFd);
+#ifdef VMBLOCK_PURGE_FILEBLOCKS
+ } else if (strcmp(argv[1], "-purge") == 0) {
+ purgeBlocks(blockFd);
+#endif
+ }
+ close(blockFd);
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Create directories/files used during test */
+ for (i = 0; i < sizeof files/sizeof files[0]; i++) {
+ int err;
+ struct stat statbuf;
+ char buf[PATH_MAX];
+
+ err = stat(files[i].blockerName, &statbuf);
+ if (!err) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ goto create_file;
+ }
+
+ ERROR("%s: file [%s] already exists and is not a directory\n",
+ progname, files[i].blockerName);
+ goto exit_failure;
+ }
+
+ err = mkdir(files[i].blockerName, S_IRWXU | S_IRWXG);
+ if (err) {
+ ERROR("%s: could not create [%s]\n", progname, files[i].blockerName);
+ goto exit_failure;
+ }
+
+create_file:
+ strncpy(buf, files[i].blockerName, sizeof buf);
+ strncat(buf, FILENAME, sizeof buf - strlen(files[i].blockerName));
+ err = stat(buf, &statbuf);
+ if (!err) {
+ if (S_ISREG(statbuf.st_mode)) {
+ continue;
+ }
+
+ ERROR("%s: file [%s] already exists and is not a regular file\n",
+ progname, buf);
+ goto exit_failure;
+ }
+
+ err = creat(buf, S_IRUSR | S_IRGRP);
+ if (err < 0) {
+ ERROR("%s: could not create [%s]\n", progname, buf);
+ goto exit_failure;
+ }
+
+ continue;
+
+exit_failure:
+ close(blockFd);
+ exit(EXIT_FAILURE);
+ }
+
+ if (signal(SIGINT, sighandler) == SIG_ERR ||
+ signal(SIGTERM, sighandler) == SIG_ERR) {
+ ERROR("%s: could not install signal handlers\n", progname);
+ close(blockFd);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Seems cleaner than a bunch of globals ... */
+ info.blockFd = blockFd;
+ info.lock = &filesLock;
+ info.files = files;
+ info.filesArraySize = sizeof files/sizeof files[0];
+ info.sleepTime = 1;
+
+ /*
+ * Start a thread that flips a random file's state, then sleeps for a while
+ * and does it again.
+ */
+ if (pthread_create(&blockerThread, NULL, blocker, &info)) {
+ ERROR("%s: could not create blocker thread\n", progname);
+ close(blockFd);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Start a bunch of threads that try to open a random file, check its status
+ * once they have it open (to make sure it is not blocked), then close it
+ * and exit.
+ */
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ count = 0;
+ while (!programQuit) {
+ pthread_t thread;
+ int rv;
+ SEM_WAIT();
+ /* Create threads until we cannot anymore */
+ if ((rv = pthread_create(&thread, &attr, accessor, &info)) != 0) {
+ SEM_POST();
+ if (rv == EAGAIN || rv == ENOMEM) {
+ os_thread_yield();
+ continue;
+ }
+ ERROR("%s: could not create an accessor thread (%d total)\n",
+ progname, count);
+ ERROR("%s: pthread_create: %s\n", progname, strerror(rv));
+ ret = EXIT_FAILURE;
+ break;
+ }
+ count++;
+ }
+
+ Log("%s: Not creating any more accessor threads.\n", progname);
+
+ programQuit = TRUE;
+ pthread_join(blockerThread, NULL);
+
+ pthread_mutex_destroy(&filesLock);
+ close(blockFd);
+
+ Log("%s: Exiting with %s.\n",
+ progname, ret == EXIT_SUCCESS ? "success" : "failure");
+
+ exit(ret);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * blocker --
+ *
+ * Entry point for the single blocker thread. Continuously picks a file at
+ * random and changes its state by adding or deleting a block on that file.
+ *
+ * Results:
+ * EXIT_SUCCESS and EXIT_FAILURE.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void *
+blocker(void *arg) // IN
+{
+ ThreadInfo *info = (ThreadInfo *)arg;
+ unsigned int index;
+
+ if (!info) {
+ THREAD_ERROR("blocker: no thread info provided\n");
+ pthread_exit((void *)EXIT_FAILURE);
+ }
+
+ while (!programQuit) {
+ index = getRand(info->filesArraySize - 1);
+
+ pthread_mutex_lock(info->lock);
+
+ if (info->files[index].blocked) {
+ info->files[index].blocked = FALSE;
+ if ( !delBlock(info->blockFd, info->files[index].blockerName) ) {
+ THREAD_ERROR("blocker: could not delete block on [%s]\n",
+ info->files[index].blockerName);
+ goto error;
+ }
+ } else if (info->files[index].waiters == 0) {
+ /*
+ * Only add a new block if all previous waiters are done. This
+ * ensures we don't get incorrect error messages from accessor threads
+ * even though the open(2) and check are not atomic in the accessor.
+ */
+ info->files[index].blocked = TRUE;
+ if ( !addBlock(info->blockFd, info->files[index].blockerName) ) {
+ THREAD_ERROR("blocker: could not add block on [%s]\n",
+ info->files[index].blockerName);
+ goto error;
+ }
+ }
+
+ pthread_mutex_unlock(info->lock);
+
+ sleep(info->sleepTime);
+ }
+
+ pthread_mutex_lock(info->lock);
+ for (index = 0; index < info->filesArraySize; index++) {
+ if (info->files[index].blocked) {
+ info->files[index].blocked = FALSE;
+#ifndef TEST_CLOSE_FD
+ THREAD_LOG("blocker: deleting block for [%s]\n",
+ info->files[index].blockerName);
+ if ( !delBlock(info->blockFd, info->files[index].blockerName) ) {
+ THREAD_ERROR("blocker: could not delete existing block on exit for [%s]\n",
+ info->files[index].blockerName);
+ }
+#else
+ THREAD_LOG("blocker: unmarking block for [%s], left for unblock on release\n",
+ info->files[index].blockerName);
+#endif
+ }
+ }
+ pthread_mutex_unlock(info->lock);
+
+ pthread_exit(EXIT_SUCCESS);
+
+error:
+ programQuit = TRUE;
+ pthread_mutex_unlock(info->lock);
+ pthread_exit((void *)EXIT_FAILURE);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * accessor --
+ *
+ * Entry point for accessor threads. Picks a file at random and attempts to
+ * open it. Once it is opened, ensures the state of the file is not blocked
+ * and outputs an error message accordingly.
+ *
+ * Results:
+ * EXIT_SUCCESS and EXIT_FAILURE.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void *
+accessor(void *arg) // IN
+{
+ ThreadInfo *info = (ThreadInfo *)arg;
+ unsigned int index;
+ int fd;
+ uintptr_t ret = EXIT_SUCCESS;
+
+ PTHREAD_SEMAPHORE_CLEANUP();
+
+ if (!info) {
+ THREAD_ERROR("blocker: no thread info provided\n");
+ pthread_exit((void *)EXIT_FAILURE);
+ }
+
+ index = getRand(info->filesArraySize - 1);
+
+ /*
+ * We can't hold the lock while calling open(2), since we will deadlock
+ * waiting for the blocker thread to remove the block on the file. So, we
+ * bump the waiter count to ensure that a new block is not placed on this
+ * file until we have checked its state. This prevents incorrect error
+ * messages that would happen if the blocker placed a new block on the file
+ * between our open(2) call returning and acquiring the lock.
+ *
+ * The fact that we can't hold the lock through open(2) also means that it's
+ * not atomic with respect to checking the file's blocked flag. Given this,
+ * it's possible that we'll miss some errors if the block is removed after
+ * open(2) returns but before we check the blocked flag -- hopefully running
+ * this test for a very long time will be sufficient to catch these cases.
+ * (Having the blocker sleep increases the likelihood of seeing such
+ * errors.)
+ */
+ pthread_mutex_lock(info->lock);
+ info->files[index].waiters++;
+ pthread_mutex_unlock(info->lock);
+
+ fd = open(info->files[index].accessorName, O_RDONLY);
+ if (fd < 0) {
+ if (errno == EMFILE) {
+ /* We already have hit the maximum number of file descriptors */
+ pthread_mutex_lock(info->lock);
+ info->files[index].waiters--;
+ pthread_mutex_unlock(info->lock);
+ pthread_exit((void *)EXIT_FAILURE);
+ }
+ THREAD_ERROR("accessor: could not open file [%s]\n",
+ info->files[index].accessorName);
+ THREAD_ERROR("accessor: open: %s\n", strerror(errno));
+ pthread_exit((void *)EXIT_FAILURE);
+ }
+
+ pthread_mutex_lock(info->lock);
+ info->files[index].waiters--;
+
+ if (info->files[index].blocked) {
+ THREAD_ERROR("accessor: [ERROR] accessed file [%s] while blocked (%d)\n",
+ info->files[index].accessorName, info->files[index].blocked);
+ ret = EXIT_FAILURE;
+ }
+ pthread_mutex_unlock(info->lock);
+ close(fd);
+
+ pthread_exit((void *)ret);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * addBlock --
+ *
+ * Adds a block on the specified filename.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * Future open(2)s on the file will block until delBlock() is called for
+ * that file.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+addBlock(int fd, // IN: fd of control device
+ char const *filename) // IN: filename to add block for
+{
+ Log("Blocking [%s]\n", filename);
+ return VMBLOCK_CONTROL(fd, VMBLOCK_ADD_FILEBLOCK, filename) == 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * delBlock --
+ *
+ * Deletes a block on the specified filename.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * Previous open(2)s that had blocked will now complete.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+delBlock(int fd, // IN: fd of control device
+ char const *filename) // IN: filename to delete block for
+{
+ Log("Unblocking [%s]\n", filename);
+ return VMBLOCK_CONTROL(fd, VMBLOCK_DEL_FILEBLOCK, filename) == 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * listBlocks --
+ *
+ * Tells the kernel module to list all existing blocks.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+listBlocks(int fd) // IN: fd of control device
+{
+ Log("Listing blocks (check kernel log output)\n");
+ return VMBLOCK_CONTROL(fd, VMBLOCK_LIST_FILEBLOCKS, NULL) == 0;
+}
+
+
+#ifdef VMBLOCK_PURGE_FILEBLOCKS
+/*
+ *----------------------------------------------------------------------------
+ *
+ * purgeBlocks --
+ *
+ * Tells the kernel module to purge all existing blocks, regardless of
+ * who opened them.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+purgeBlocks(int fd) // IN: fd of control device
+{
+ Log("Purging all blocks\n");
+ return VMBLOCK_CONTROL(fd, VMBLOCK_PURGE_FILEBLOCKS, NULL) == 0;
+}
+#endif
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * getRand --
+ *
+ * Retrieves the next random number within the range [0, max].
+ *
+ * Results:
+ * A random number.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static unsigned int
+getRand(unsigned int max) // IN: max value returnable
+{
+ return random() % max;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * sighandler --
+ *
+ * Sets the programQuit flag when a signal is received.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Program will quit.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+sighandler(int sig)
+{
+ programQuit = TRUE;
+}
"Usage: %s stat <subcommand>\n\n"
"Subcommands\n"
" hosttime: print the host time\n"
- " memory: print the virtual machine memory in MBs\n"
" speed: print the CPU speed in MHz\n"
"ESX guests only subcommands\n"
" sessionid: print the current session id\n"
StatCommand(char **argv, // IN: Command line arguments
int argc) // IN: Length of command line arguments
{
- if (toolbox_strcmp(argv[optind], "memory") == 0) {
- return Stat_MemorySize();
- } else if (toolbox_strcmp(argv[optind], "hosttime") == 0) {
+ if (toolbox_strcmp(argv[optind], "hosttime") == 0) {
return Stat_HostTime();
} else if (toolbox_strcmp(argv[optind], "sessionid") == 0) {
return Stat_GetSessionID();
ToolboxUnknownEntityError(argv[0], "command", argv[optind]);
retval = EX_USAGE;
} else if (cmd->requireRoot && !System_IsUserAdmin()) {
- fprintf(stderr, "%s: You must be root to perform %s operations",
+ fprintf(stderr,
+#ifdef _WIN32
+ "%s: Administrator permissions are needed to perform %s "
+ "operations. Use an administrator command prompt to "
+ "complete these tasks.",
+#else
+ "%s: You must be root to perform %s operations",
+#endif
argv[0], cmd->command);
retval = EX_NOPERM;
} else if (cmd->requireArguments && ++optind >= argc) {
* Stat commands
*/
-int Stat_MemorySize(void);
int Stat_HostTime(void);
int Stat_ProcessorSpeed(void);
int Stat_GetSessionID(void);
#define MAX_DEVICES 50 /* maximum number of devices we'll show */
#define SHRINK_DISABLED_ERR "Shrink disk is disabled for this virtual machine.\n\n" \
"Shrinking is disabled for linked clones, parents of " \
- "linked clones, \npre-allocated disks, snapshots, and " \
+ "linked clones, \npre-allocated disks, snapshots, or due to " \
"other factors. \nSee the User's manual for more " \
"information.\n"
#define SHRINK_FEATURE_ERR "The shrink feature is not available,\n\n" \
"because too many communication channels are open.\n\n If you are running " \
"an old version of a VMware product, you should consider upgrading.\n\n" \
"If too many communication channels are open, you should power off your " \
- "virtual machine and then power it back on\n."
+ "virtual machine and then power it back on.\n"
#define SHRINK_CONFLICT_ERR "Error, The Toolbox believes disk shrinking is " \
"enabled while the host believes it is disabled.\n\n " \
"Please close and reopen the Toolbox to synchronize " \
GtkWidget *viewport;
GtkWidget *ebox;
- int i;
- WiperPartition_List *plist;
- WiperPartition *partkb;
+ WiperPartition_List plist;
gchar *items;
int newrow;
gtk_clist_set_selection_mode(GTK_CLIST(shrinkList), GTK_SELECTION_MULTIPLE);
Wiper_Init(NULL);
- plist = WiperPartition_Open();
- if (plist != NULL) {
- for (i=0; i < plist->size; i++) {
- if (strlen(plist->partitions[i].comment) == 0) {
- partkb = (WiperPartition *)malloc(sizeof (WiperPartition));
- memcpy(partkb, &(plist->partitions[i]), sizeof (WiperPartition));
- items = partkb->mountPoint;
+ if (WiperPartition_Open(&plist)) {
+ DblLnkLst_Links *curr, *next;
+
+ DblLnkLst_ForEachSafe(curr, next, &plist.link) {
+ WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link);
+
+ if (part->type != PARTITION_UNSUPPORTED) {
+ /*
+ * Detach the element we are interested in so it is not
+ * destroyed when we call WiperPartition_Close.
+ */
+ DblLnkLst_Unlink1(&part->link);
+ items = part->mountPoint;
newrow = gtk_clist_append(GTK_CLIST(shrinkList), &items);
- gtk_clist_set_row_data(GTK_CLIST(shrinkList), newrow,
- partkb);
+ gtk_clist_set_row_data_full(GTK_CLIST(shrinkList), newrow,
+ part, (GDestroyNotify)WiperSinglePartition_Close);
}
}
- WiperPartition_Close(plist);
+ WiperPartition_Close(&plist);
}
} else {
label = gtk_label_new(SHRINK_DISABLED_ERR);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-
}
}
}
do {
rnum = GPOINTER_TO_UINT(slist->data);
- part = (WiperPartition *)(gtk_clist_get_row_data(GTK_CLIST(shrinkList),
- rnum));
+ part = gtk_clist_get_row_data(GTK_CLIST(shrinkList), rnum);
if (Shrink_DoWipe(part, mainWnd)) {
disks_to_shrink++;
slist = slist->next;
if (ToolsMain_YesNoBox("Shrink Disk",
"Do you want to shrink the disk(s)?\n")) {
if (GuestApp_DiskShrink()) {
- ToolsMain_MsgBox("Information", "The shrink process is complete.");
+ ToolsMain_MsgBox("Information", "The shrink process has finished.");
}
gtk_clist_unselect_all(GTK_CLIST(shrinkList));
}
GError *err = NULL;
if (!File_Exists(path)) {
- fprintf(stderr, "%s doesn't exists\n", path);
+ fprintf(stderr, "%s doesn't exist\n", path);
return EX_OSFILE;
}
static void ShrinkWiperDestroy(int signal);
#endif
-static WiperPartition_List * ShrinkGetMountPoints(void);
-static WiperPartition * ShrinkGetPartition(char *mountPoint, int quiet_flag);
+static Bool ShrinkGetMountPoints(WiperPartition_List *);
+static WiperPartition * ShrinkGetPartition(char *mountPoint);
static Wiper_State *wiper = NULL;
*/
int
-Shrink_List(void) // IN: Verbosity flag.
+Shrink_List(void)
{
- int i;
- WiperPartition_List *plist = ShrinkGetMountPoints();
- if (plist == NULL) {
+ WiperPartition_List plist;
+ DblLnkLst_Links *curr;
+
+ if (!ShrinkGetMountPoints(&plist)) {
return EX_TEMPFAIL;
}
- for (i = 0; i < plist->size; i++) {
- if (strlen(plist->partitions[i].comment) == 0) {
- printf("%s\n", plist->partitions[i].mountPoint);
+
+ DblLnkLst_ForEach(curr, &plist.link) {
+ WiperPartition *p = DblLnkLst_Container(curr, WiperPartition, link);
+ if (p->type != PARTITION_UNSUPPORTED) {
+ printf("%s\n", p->mountPoint);
}
}
- WiperPartition_Close(plist);
+
+ WiperPartition_Close(&plist);
+
return EXIT_SUCCESS;
}
*/
static WiperPartition*
-ShrinkGetPartition(char *mountPoint, // IN: mount point
- int quiet_flag) // IN: Verbosity flag
+ShrinkGetPartition(char *mountPoint)
{
- int i;
- WiperPartition *part;
- WiperPartition_List *plist = ShrinkGetMountPoints();
- if (!plist) {
+ WiperPartition_List plist;
+ WiperPartition *p, *part = NULL;
+ DblLnkLst_Links *curr;
+
+ if (!ShrinkGetMountPoints(&plist)) {
return NULL;
}
- part = (WiperPartition *) malloc(sizeof *part);
- for (i = 0; i < plist->size; i++) {
- if (toolbox_strcmp(plist->partitions[i].mountPoint, mountPoint) == 0) {
- memcpy(part, &plist->partitions[i], sizeof *part);
- WiperPartition_Close(plist);
- return part;
+
+ DblLnkLst_ForEach(curr, &plist.link) {
+ p = DblLnkLst_Container(curr, WiperPartition, link);
+ if (toolbox_strcmp(p->mountPoint, mountPoint) == 0) {
+ part = p;
+ /*
+ * Detach the element we are interested in so it is not
+ * destroyed when we call WiperPartition_Close.
+ */
+ DblLnkLst_Unlink1(&part->link);
+ break;
}
}
- WiperPartition_Close(plist);
- return NULL;
+
+ WiperPartition_Close(&plist);
+
+ return part;
}
*-----------------------------------------------------------------------------
*/
-static WiperPartition_List*
-ShrinkGetMountPoints(void) // IN: Verbosity flag
+static Bool
+ShrinkGetMountPoints(WiperPartition_List *pl) // OUT: Known mount points
{
- if (GuestApp_IsDiskShrinkCapable()) {
- if (GuestApp_IsDiskShrinkEnabled()) {
- return WiperPartition_Open();
- } else {
- fprintf(stderr,SHRINK_DISABLED_ERR);
- }
- } else {
+ if (!GuestApp_IsDiskShrinkCapable()) {
fprintf(stderr, SHRINK_FEATURE_ERR);
+ } else if (!GuestApp_IsDiskShrinkEnabled()) {
+ fprintf(stderr, SHRINK_DISABLED_ERR);
+ } else if (!WiperPartition_Open(pl)) {
+ fprintf(stderr, "Unable to collect partition data.\n");
+ } else {
+ return TRUE;
}
- return NULL;
+ return FALSE;
}
int progress = 0;
unsigned char *err;
WiperPartition *part;
+ int rc;
+
#ifndef _WIN32
signal(SIGINT, ShrinkWiperDestroy);
#endif
- part = ShrinkGetPartition(mountPoint, quiet_flag);
+
+ part = ShrinkGetPartition(mountPoint);
if (part == NULL) {
fprintf(stderr, "Unable to find partition %s\n", mountPoint);
return EX_OSFILE;
}
- if (strlen(part->comment) != 0) {
+ if (part->type == PARTITION_UNSUPPORTED) {
fprintf(stderr, "Partition %s is not shrinkable\n", part->mountPoint);
- return EX_UNAVAILABLE;
+ rc = EX_UNAVAILABLE;
+ goto out;
}
/*
*/
if (!GuestApp_IsDiskShrinkEnabled()) {
fprintf(stderr, SHRINK_CONFLICT_ERR);
- free(part);
- return EX_TEMPFAIL;
+ rc = EX_TEMPFAIL;
+ goto out;
}
- wiper = Wiper_Start (part, MAX_WIPER_FILE_SIZE);
+ wiper = Wiper_Start(part, MAX_WIPER_FILE_SIZE);
+
while (progress < 100 && wiper != NULL) {
err = Wiper_Next(&wiper, &progress);
if (strlen(err) > 0) {
if (strcmp(err, "error.create") == 0) {
fprintf(stderr, "Error, Unable to create wiper file\n");
- free(part);
- return EX_TEMPFAIL;
- }
- else {
+ } else {
fprintf(stderr, "Error, %s", err);
- free(part);
- return EX_TEMPFAIL;
}
- free(wiper);
- wiper = NULL;
+
+ rc = EX_TEMPFAIL;
}
+
if (!quiet_flag) {
printf("\rProgress: %d [", progress);
for (i = 0; i <= progress / 10; i++) {
- printf("=");
+ putchar('=');
}
- printf(">");
- for (; i <= 100 / 10; i++) {
- printf(" ");
- }
- printf("]");
+ printf(">%*c", 10 - i + 1, ']');
+ fflush(stdout);
}
}
+
if (progress >= 100) {
char *result;
size_t resultLen;
+
if (RpcOut_sendOne(&result, &resultLen, "disk.shrink")) {
if (!quiet_flag) {
printf("\nDisk shrinking complete\n");
}
- wiper = NULL;
- free(part);
- return EXIT_SUCCESS;
- }
- if (!quiet_flag) {
- fprintf(stderr, "%s\n", result);
+ rc = EXIT_SUCCESS;
+ goto out;
}
- wiper = NULL;
- free(part);
+
+ fprintf(stderr, "%s\n", result);
}
fprintf(stderr, "Shrinking not completed\n");
- return EX_TEMPFAIL;
+ rc = EX_TEMPFAIL;
+
+out:
+ WiperSinglePartition_Close(part);
+ free(wiper);
+ wiper = NULL;
+ return rc;
}
}
-/*
- *-----------------------------------------------------------------------------
- *
- * Stat_MemorySize --
- *
- * Gets the virtual machine's memory in MBs.
- *
- * Results:
- * EXIT_SUCCESS on success.
- * EX_TEMPFAIL on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-Stat_MemorySize(void)
-{
- uint32 memsize;
- Backdoor_proto bp;
- bp.in.cx.halfs.low = BDOOR_CMD_GETMEMSIZE;
- Backdoor(&bp);
- memsize = bp.out.ax.word;
- if (memsize < 0) {
- fprintf(stderr, "Unable to get memory size\n");
- return EX_TEMPFAIL;
- }
- printf("%u MB\n", memsize);
- return EXIT_SUCCESS;
-}
-
-
/*
*-----------------------------------------------------------------------------
*
endif
vmware_user_LDADD += ../lib/user/libUser.la
vmware_user_LDADD += ../lib/vixTools/libVixTools.la
+vmware_user_LDADD += ../lib/hgfsHelper/libHgfsHelper.la
vmware_user_LDADD += ../lib/vmCheck/libVmCheck.la
vmware_user_LDADD += ../lib/vmSignal/libVmSignal.la
vmware_user_LDADD += ../lib/wiper/libWiper.la
vmware_user_LDADD += -lcrypt
vmware_user_LDADD += -lstdc++
if LINUX
-vmware_user_LDADD += -lgcc_s
+ vmware_user_LDADD += -lgcc_s
+ vmware_user_LDADD += ../lib/slashProc/libSlashProc.la
endif
vmware_user_LDADD += @GTK_LIBS@
if HAVE_GTKMM
}
Glib::RefPtr<Gtk::Clipboard> refClipboard;
+ bool flipped = false;
again:
+ bool validDataInClip = false;
refClipboard = Gtk::Clipboard::get(mGHSelection);
- Debug("%s: trying %s selection, trying again\n",
- __FUNCTION__,
+ Debug("%s: trying %s selection.\n", __FUNCTION__,
mGHSelection == GDK_SELECTION_PRIMARY ? "Primary" : "Clip");
CPClipboard_Clear(&mClipboard);
bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 &&
CPClipboard_SetItem(&mClipboard, CPFORMAT_RTF,
(const void *)sdata.get_data(), bufSize + 1)) {
- mCP.SetRemoteClipboard(&mClipboard);
+ validDataInClip = true;
Debug("%s: Got RTF\n", __FUNCTION__);
- return;
} else {
Debug("%s: Failed to get RTF size %d max %d\n",
__FUNCTION__, (int) bufSize, (int)CPCLIPITEM_MAX_SIZE_V3);
bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 &&
CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT,
(const void *)str.data(), bufSize + 1)) {
- mCP.SetRemoteClipboard(&mClipboard);
+ validDataInClip = true;
Debug("%s: Got TEXT: %"FMTSZ"u\n", __FUNCTION__, bufSize);
- return;
- } else if (mClipTime == mPrimTime && mClipTime) {
- /*
- * With 'cut' operation OpenOffice will put data into clipboard but
- * set the same timestamp for both clipboard and primary selection.
- * If primary timestamp is same as clipboard timestamp, we should try
- * clipboard again if primary selection is empty. For details, please
- * refer to bug 300780.
- */
- mClipTime = 0;
- mPrimTime = 0;
- mGHSelection = GDK_SELECTION_CLIPBOARD;
- Debug("%s: trying again with clip\n", __FUNCTION__);
- goto again;
} else {
Debug("%s: Failed to get TEXT\n", __FUNCTION__);
}
}
+
+ if (validDataInClip) {
+ /*
+ * RTF or text data (or both) in the clipboard.
+ */
+ mCP.SetRemoteClipboard(&mClipboard);
+ } else if (!flipped) {
+ /*
+ * If we get here, we got nothing (no image, URI, text) so
+ * try the other selection.
+ */
+ Debug("%s: got nothing for this selection, try the other.\n",
+ __FUNCTION__);
+ mGHSelection = mGHSelection == GDK_SELECTION_PRIMARY ?
+ GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY;
+ flipped = true;
+ goto again;
+ }
}
string::string()
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
}
string::string(ConstUnicode s) // IN
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
ASSERT(s);
mUstr = Unicode_GetUTF8(s);
string::string(const ubstr_t &s) // IN
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
// If the input is empty, then there's nothing to do.
if (s.length() == 0) {
string::string(const _bstr_t &s) // IN
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
// If the input is empty, then there's nothing to do.
if (s.length() == 0) {
string::string(const utf16string &s) // IN
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
// If the input is empty, then there's nothing to do.
if (s.empty()) {
string::string(const utf16_t *s) // IN
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
ASSERT(s != NULL);
string::string(const char *s, // IN
StringEncoding encoding) // IN
: mUstr(),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
ASSERT(s != NULL);
string::string(const Glib::ustring &s) // IN
: mUstr(s.c_str()),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
ASSERT(Validate(s));
}
string::string(const string &s) // IN
: mUstr(s.mUstr.c_str()),
- mUtf16Cache(NULL)
+ mUtf16Cache(NULL),
+ mUtf16Length(npos)
{
}
{
mUstr.swap(s.mUstr);
std::swap(mUtf16Cache, s.mUtf16Cache);
+ std::swap(mUtf16Length, s.mUtf16Length);
}
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::w_size --
+ *
+ * Results:
+ * Returns the length of this string, in UTF-16 code units,
+ * excluding NUL.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::w_size()
+ const
+{
+ if (mUtf16Length == npos) {
+ mUtf16Length = Unicode_UTF16Strlen(GetUtf16Cache());
+ }
+
+ return mUtf16Length;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
{
free(mUtf16Cache);
mUtf16Cache = NULL;
+ mUtf16Length = npos;
}
CreateWritableBuffer(const string& s, // IN:
std::vector<utf16_t>& buf) // OUT: A copy of the string, as UTF-16.
{
- CopyArray(s.w_str(), Unicode_UTF16Strlen(s.w_str()) + 1, buf);
+ CopyArray(s.w_str(), s.w_size() + 1, buf);
}
void resize(size_type n, value_type c = '\0');
bool empty() const;
size_type size() const;
+ size_type w_size() const;
size_type length() const;
size_type bytes() const;
string foldCase() const;
// Cached representations.
mutable utf16_t *mUtf16Cache;
+ mutable size_type mUtf16Length;
+
+ /*
+ * All added members need to be initialized in all constructors and need
+ * to be handled in swap().
+ */
};
// Helper operators