From 1c1235b09f0a5456df1b7a559a909f8e04e2fc51 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 Jul 2008 14:13:56 -0700 Subject: [PATCH 2/4] vmware: add vmblock driver Initially seems to build TODO: - lots of coding style issues - remove all of the needless wrappers - merge into fewer files - see what's left after all of that cleanup --- drivers/vmware/Kconfig | 5 drivers/vmware/Makefile | 1 drivers/vmware/vmblock/Makefile | 13 drivers/vmware/vmblock/block.c | 611 ++++++++++++++++++++ drivers/vmware/vmblock/block.h | 47 + drivers/vmware/vmblock/compat_completion.h | 175 +++++ drivers/vmware/vmblock/compat_file.h | 56 + drivers/vmware/vmblock/compat_fs.h | 247 ++++++++ drivers/vmware/vmblock/compat_init.h | 38 + drivers/vmware/vmblock/compat_kernel.h | 83 ++ drivers/vmware/vmblock/compat_list.h | 55 + drivers/vmware/vmblock/compat_mm.h | 134 ++++ drivers/vmware/vmblock/compat_module.h | 72 ++ drivers/vmware/vmblock/compat_namei.h | 57 + drivers/vmware/vmblock/compat_page.h | 75 ++ drivers/vmware/vmblock/compat_sched.h | 274 +++++++++ drivers/vmware/vmblock/compat_semaphore.h | 44 + drivers/vmware/vmblock/compat_slab.h | 70 ++ drivers/vmware/vmblock/compat_spinlock.h | 68 ++ drivers/vmware/vmblock/compat_statfs.h | 32 + drivers/vmware/vmblock/compat_string.h | 42 + drivers/vmware/vmblock/compat_uaccess.h | 79 ++ drivers/vmware/vmblock/compat_version.h | 121 ++++ drivers/vmware/vmblock/compat_wait.h | 225 +++++++ drivers/vmware/vmblock/control.c | 332 +++++++++++ drivers/vmware/vmblock/dbllnklst.c | 399 +++++++++++++ drivers/vmware/vmblock/dbllnklst.h | 69 ++ drivers/vmware/vmblock/dentry.c | 122 ++++ drivers/vmware/vmblock/driver-config.h | 78 ++ drivers/vmware/vmblock/file.c | 274 +++++++++ drivers/vmware/vmblock/filesystem.c | 618 +++++++++++++++++++++ drivers/vmware/vmblock/filesystem.h | 111 +++ drivers/vmware/vmblock/inode.c | 244 ++++++++ drivers/vmware/vmblock/module.c | 175 +++++ drivers/vmware/vmblock/os.h | 117 ++++ drivers/vmware/vmblock/stubs.c | 52 + drivers/vmware/vmblock/stubs.h | 36 + drivers/vmware/vmblock/super.c | 194 ++++++ drivers/vmware/vmblock/vm_assert.h | 308 ++++++++++ drivers/vmware/vmblock/vm_basic_defs.h | 553 ++++++++++++++++++ drivers/vmware/vmblock/vm_basic_types.h | 847 +++++++++++++++++++++++++++++ drivers/vmware/vmblock/vmblock.h | 105 +++ drivers/vmware/vmblock/vmblockInt.h | 94 +++ drivers/vmware/vmblock/vmblock_version.h | 32 + drivers/vmware/vmblock/vmware.h | 58 + 45 files changed, 7442 insertions(+) --- a/drivers/vmware/Kconfig +++ b/drivers/vmware/Kconfig @@ -9,5 +9,10 @@ menuconfig VMWARE_SUPPORT if VMWARE_SUPPORT +config VMWARE_BLOCK + tristate "vmWare block driver" + default N + help + vmware block driver. endif # VMWARE_SUPPORT --- a/drivers/vmware/Makefile +++ b/drivers/vmware/Makefile @@ -2,3 +2,4 @@ # Makefile for the vmware drivers. # +obj-$(CONFIG_VMWARE_BLOCK) += vmblock/ --- /dev/null +++ b/drivers/vmware/vmblock/block.c @@ -0,0 +1,611 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * block.c -- + * + * Blocking operation implementions for the vmblock driver. + */ + +/* os.h includes necessary OS-specific headers. */ +#include "os.h" + +#ifdef linux +# include "vmblockInt.h" +#elif defined(sun) +# include "module.h" +#elif defined(__FreeBSD__) +# include "vmblock_k.h" +#endif +#include "block.h" +#include "stubs.h" +#include "dbllnklst.h" + +typedef struct BlockInfo { + DblLnkLst_Links links; + os_atomic_t refcount; + os_blocker_id_t blocker; + os_completion_t completion; + char filename[OS_PATH_MAX]; +} BlockInfo; + + +/* XXX: Is it worth turning this into a hash table? */ +static DblLnkLst_Links blockedFiles; +static os_rwlock_t blockedFilesLock; +static os_kmem_cache_t *blockInfoCache = NULL; + +/* Utility functions */ +static Bool BlockExists(const char *filename); +static BlockInfo *GetBlock(const char *filename, const os_blocker_id_t blocker); +static BlockInfo *AllocBlock(os_kmem_cache_t *cache, + const char *filename, const os_blocker_id_t blocker); +static void FreeBlock(os_kmem_cache_t *cache, BlockInfo *block); + + +/* + *---------------------------------------------------------------------------- + * + * BlockInit -- + * + * Initializes blocking portion of module. + * + * Results: + * Zero on success, error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +BlockInit(void) +{ + ASSERT(!blockInfoCache); + + blockInfoCache = os_kmem_cache_create("blockInfoCache", + sizeof (BlockInfo), + 0, + NULL); + if (!blockInfoCache) { + return OS_ENOMEM; + } + + DblLnkLst_Init(&blockedFiles); + os_rwlock_init(&blockedFilesLock); + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * BlockCleanup -- + * + * Cleans up the blocking portion of the module. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +void +BlockCleanup(void) +{ + ASSERT(blockInfoCache); + ASSERT(!DblLnkLst_IsLinked(&blockedFiles)); + + os_rwlock_destroy(&blockedFilesLock); + os_kmem_cache_destroy(blockInfoCache); +} + + +/* + *---------------------------------------------------------------------------- + * + * BlockAddFileBlock -- + * + * Adds a block for the provided filename. filename should be the name of + * the actual file being blocked, not the name within our namespace. The + * provided blocker ID should uniquely identify this blocker. + * + * All calls to BlockWaitOnFile() with the same filename will not return + * until BlockRemoveFileBlock() is called. + * + * Note that this function assumes a block on filename does not already + * exist. + * + * Results: + * Zero on success, error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +BlockAddFileBlock(const char *filename, // IN: name of file to block + const os_blocker_id_t blocker) // IN: blocker adding the block +{ + BlockInfo *block; + + ASSERT(filename); + + /* Create a new block. */ + block = AllocBlock(blockInfoCache, filename, blocker); + if (!block) { + Warning("BlockAddFileBlock: out of memory\n"); + return OS_ENOMEM; + } + os_write_lock(&blockedFilesLock); + + /* + * Prevent duplicate blocks of any filename. Done under same lock as list + * addition to ensure check for and adding of file are atomic. + */ + if (BlockExists(filename)) { + Warning("BlockAddFileBlock: block already exists for [%s]\n", filename); + os_write_unlock(&blockedFilesLock); + FreeBlock(blockInfoCache, block); + return OS_EEXIST; + } + + DblLnkLst_LinkLast(&blockedFiles, &block->links); + + os_write_unlock(&blockedFilesLock); + + LOG(4, "added block for [%s]\n", filename); + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * BlockRemoveFileBlock -- + * + * Removes the provided file block and wakes up any threads waiting within + * BlockWaitOnFile(). Note that only the blocker that added a block can + * remove it. + * + * Results: + * Zero on success, error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +BlockRemoveFileBlock(const char *filename, // IN: block to remove + const os_blocker_id_t blocker) // IN: blocker removing this block +{ + BlockInfo *block; + + ASSERT(filename); + + os_write_lock(&blockedFilesLock); + + block = GetBlock(filename, blocker); + if (!block) { + os_write_unlock(&blockedFilesLock); + return OS_ENOENT; + } + + DblLnkLst_Unlink1(&block->links); + os_write_unlock(&blockedFilesLock); + + /* Undo GetBlock's refcount increment first. */ + os_atomic_dec(&block->refcount); + + /* + * Now remove /our/ reference. (As opposed to references by waiting + * threads.) + */ + if (os_atomic_dec_and_test(&block->refcount)) { + /* No threads are waiting, so clean up ourself. */ + LOG(4, "Freeing block with no waiters on [%s]\n", filename); + FreeBlock(blockInfoCache, block); + } else { + /* Wake up waiters; the last one will free the BlockInfo */ + LOG(4, "Completing block on [%s]\n", filename); + os_complete_all(&block->completion); + } + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * BlockRemoveAllBlocks -- + * + * Removes all blocks added by the provided blocker. + * + * Results: + * Returns the number of entries removed from the blocklist. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +unsigned int +BlockRemoveAllBlocks(const os_blocker_id_t blocker) // IN: blocker to remove blocks for +{ + struct DblLnkLst_Links *curr; + struct DblLnkLst_Links *tmp; + unsigned int removed = 0; + + os_write_lock(&blockedFilesLock); + + DblLnkLst_ForEachSafe(curr, tmp, &blockedFiles) { + BlockInfo *currBlock = DblLnkLst_Container(curr, BlockInfo, links); + if (currBlock->blocker == blocker || blocker == OS_UNKNOWN_BLOCKER) { + + DblLnkLst_Unlink1(&currBlock->links); + + /* + * We count only entries removed from the -list-, regardless of whether + * or not other waiters exist. + */ + ++removed; + + /* + * BlockInfos, as the result of placing a block on a file or directory, + * reference themselves. When the block is lifted, we need to remove + * this self-reference and handle the result appropriately. + */ + if (os_atomic_dec_and_test(&currBlock->refcount)) { + /* Free blocks without any waiters ... */ + LOG(4, "Freeing block with no waiters for blocker [%p] (%s)\n", + blocker, currBlock->filename); + FreeBlock(blockInfoCache, currBlock); + } else { + /* ... or wakeup the waiting threads */ + LOG(4, "Completing block for blocker [%p] (%s)\n", + blocker, currBlock->filename); + os_complete_all(&currBlock->completion); + } + } + } + + os_write_unlock(&blockedFilesLock); + + return removed; +} + + +/* + *---------------------------------------------------------------------------- + * + * BlockWaitOnFile -- + * + * Searches for a block on the provided filename. If one exists, this + * function does not return until that block has been lifted; otherwise, it + * returns right away. + * + * Results: + * Zero on success, otherwise an appropriate system error if our sleep/ + * block is interrupted. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +BlockWaitOnFile(const char *filename, // IN: file to block on + BlockHandle cookie) // IN: previously found block +{ + BlockInfo *block = NULL; + int error = 0; + + ASSERT(filename); + + /* + * Caller may have used BlockLookup to conditionally search for a + * block before actually going to sleep. (This allows the caller to + * do a little housekeeping, such as releasing vnode locks, before + * blocking here.) + */ + if (cookie == NULL) { + os_read_lock(&blockedFilesLock); + block = GetBlock(filename, NULL); + os_read_unlock(&blockedFilesLock); + + if (!block) { + /* This file is not blocked, just return */ + return 0; + } + } else { + /* + * Note that the "cookie's" reference count was incremented when it + * was fetched via BlockLookup, so this is completely safe. (We'll + * decrement it below.) + */ + block = cookie; + } + + LOG(4, "(%"OS_FMTTID") Waiting for completion on [%s]\n", os_threadid, filename); + error = os_wait_for_completion(&block->completion); + LOG(4, "(%"OS_FMTTID") Wokeup from block on [%s]\n", os_threadid, filename); + + /* + * The assumptions here are as follows: + * 1. The BlockInfo holds a reference to itself. (BlockInfo's refcount + * is initialized to 1.) + * 2. BlockInfo's self reference is deleted only when BlockInfo is + * /also/ removed removed from the block list. + * + * Therefore, if the reference count hits zero, it's because the block is + * no longer in the list, and there is no chance of another thread finding + * and referencing this block between our dec_and_test and freeing it. + */ + if (os_atomic_dec_and_test(&block->refcount)) { + /* We were the last thread, so clean up */ + LOG(4, "(%"OS_FMTTID") I am the last to wakeup, freeing the block on [%s]\n", + os_threadid, filename); + FreeBlock(blockInfoCache, block); + } + + return error; +} + + +/* + *----------------------------------------------------------------------------- + * + * BlockLookup -- + * + * VFS-exported function for searching for blocks. + * + * Results: + * Opaque pointer to a blockInfo if a block is found, NULL otherwise. + * + * Side effects: + * Located blockInfo, if any, has an incremented reference count. + * + *----------------------------------------------------------------------------- + */ + +BlockHandle +BlockLookup(const char *filename, // IN: pathname to test for + // blocking + const os_blocker_id_t blocker) // IN: specific blocker to + // search for +{ + BlockInfo *block; + + os_read_lock(&blockedFilesLock); + + block = GetBlock(filename, blocker); + + os_read_unlock(&blockedFilesLock); + + return block; +} + + +#ifdef VMX86_DEVEL +/* + *---------------------------------------------------------------------------- + * + * BlockListFileBlocks -- + * + * Lists all the current file blocks. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +void +BlockListFileBlocks(void) +{ + DblLnkLst_Links *curr; + int count = 0; + + os_read_lock(&blockedFilesLock); + + DblLnkLst_ForEach(curr, &blockedFiles) { + BlockInfo *currBlock = DblLnkLst_Container(curr, BlockInfo, links); + LOG(1, "BlockListFileBlocks: (%d) Filename: [%s], Blocker: [%p]\n", + count++, currBlock->filename, currBlock->blocker); + } + + os_read_unlock(&blockedFilesLock); + + if (!count) { + LOG(1, "BlockListFileBlocks: No blocks currently exist.\n"); + } +} +#endif + + +/* Utility functions */ + +/* + *---------------------------------------------------------------------------- + * + * BlockExists -- + * + * Checks if a block already exists for the provided filename. + * + * Note that this assumes the proper locking has been done on the data + * structure holding the blocked files (including ensuring the atomic_dec() + * without a kmem_cache_free() is safe). + * + * Results: + * TRUE if a block exists, FALSE otherwise. + * + * Side effects: + * If a block exists, its refcount is incremented and decremented. + * + *---------------------------------------------------------------------------- + */ + +static Bool +BlockExists(const char *filename) +{ + BlockInfo *block = GetBlock(filename, OS_UNKNOWN_BLOCKER); + + if (block) { + os_atomic_dec(&block->refcount); + return TRUE; + } + + return FALSE; +} + + +/* + *---------------------------------------------------------------------------- + * + * GetBlock -- + * + * Searches for a block on the provided filename by the provided blocker. + * If blocker is NULL, it is ignored and any matching filename is returned. + * If a block is found, the refcount is incremented. + * + * Note that this assumes the proper locking has been done on the data + * structure holding the blocked files. + * + * Results: + * A pointer to the corresponding BlockInfo if found, NULL otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static BlockInfo * +GetBlock(const char *filename, // IN: file to find block for + const os_blocker_id_t blocker) // IN: blocker associated with this block +{ + struct DblLnkLst_Links *curr; + + /* XXX The following is only temporary. */ +#ifdef __FreeBSD__ + os_assert_rwlock_held(&blockedFilesLock); +#else + ASSERT(os_rwlock_held(&blockedFilesLock)); +#endif + + DblLnkLst_ForEach(curr, &blockedFiles) { + BlockInfo *currBlock = DblLnkLst_Container(curr, BlockInfo, links); + if ((blocker == OS_UNKNOWN_BLOCKER || currBlock->blocker == blocker) && + strcmp(currBlock->filename, filename) == 0) { + os_atomic_inc(&currBlock->refcount); + return currBlock; + } + } + + return NULL; +} + + +/* + *---------------------------------------------------------------------------- + * + * AllocBlock -- + * + * Allocates and initializes a new block structure. + * + * Results: + * Pointer to the struct on success, NULL on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +BlockInfo * +AllocBlock(os_kmem_cache_t *cache, // IN: cache to allocate from + const char *filename, // IN: filname of block + const os_blocker_id_t blocker) // IN: blocker id +{ + BlockInfo *block; + size_t ret; + + /* Initialize this file's block structure. */ + block = os_kmem_cache_alloc(blockInfoCache); + if (!block) { + return NULL; + } + + ret = strlcpy(block->filename, filename, sizeof block->filename); + if (ret >= sizeof block->filename) { + Warning("BlockAddFileBlock: filename is too large\n"); + os_kmem_cache_free(blockInfoCache, block); + return NULL; + } + + DblLnkLst_Init(&block->links); + os_atomic_set(&block->refcount, 1); + os_completion_init(&block->completion); + block->blocker = blocker; + + return block; +} + + +/* + *---------------------------------------------------------------------------- + * + * FreeBlock -- + * + * Frees the provided block structure. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +FreeBlock(os_kmem_cache_t *cache, // IN: cache block was allocated from + BlockInfo *block) // IN: block to free +{ + ASSERT(cache); + ASSERT(block); + + os_completion_destroy(&block->completion); + os_kmem_cache_free(cache, block); +} --- /dev/null +++ b/drivers/vmware/vmblock/block.h @@ -0,0 +1,47 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * block.h -- + * + * Blocking operations for the vmblock driver. + */ + +#ifndef __BLOCK_H__ +#define __BLOCK_H__ + +#include "os.h" + +typedef struct BlockInfo * BlockHandle; + +/* + * Global functions + */ + +int BlockInit(void); +void BlockCleanup(void); +int BlockAddFileBlock(const char *filename, const os_blocker_id_t blocker); +int BlockRemoveFileBlock(const char *filename, const os_blocker_id_t blocker); +unsigned int BlockRemoveAllBlocks(const os_blocker_id_t blocker); +int BlockWaitOnFile(const char *filename, BlockHandle cookie); +BlockHandle BlockLookup(const char *filename, const os_blocker_id_t blocker); +#ifdef VMX86_DEVEL +void BlockListFileBlocks(void); +#endif + +#endif /* __BLOCK_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_completion.h @@ -0,0 +1,175 @@ +/********************************************************* + * Copyright (C) 2004 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_COMPLETION_H__ +# define __COMPAT_COMPLETION_H__ + +/* + * The kernel's completion objects were made available for module use in 2.4.9. + * + * Between 2.4.0 and 2.4.9, we implement completions on our own using + * waitqueues and counters. This was done so that we could safely support + * functions like complete_all(), which cannot be implemented using semaphores. + * + * Prior to that, the waitqueue API is substantially different, and since none + * of our modules that are built against older kernels need complete_all(), + * we fallback on a simple semaphore-based implementation. + */ + +/* + * Native completions. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 9) + +#include +#define compat_completion struct completion +#define compat_init_completion(comp) init_completion(comp) +#define COMPAT_DECLARE_COMPLETION DECLARE_COMPLETION +#define compat_wait_for_completion(comp) wait_for_completion(comp) +#define compat_complete(comp) complete(comp) + +/* complete_all() was exported in 2.6.6. */ +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6) +# include "compat_wait.h" +# include "compat_list.h" +# include "compat_spinlock.h" +# include "compat_sched.h" +# define compat_complete_all(x) \ + ({ \ + struct list_head *currLinks; \ + spin_lock(&(x)->wait.lock); \ + (x)->done += UINT_MAX/2; \ + \ + list_for_each(currLinks, &(x)->wait.task_list) { \ + wait_queue_t *currQueue = list_entry(currLinks, wait_queue_t, task_list); \ + wake_up_process(currQueue->task); \ + } \ + spin_unlock(&(x)->wait.lock); \ + }) +# else +# define compat_complete_all complete_all +# endif + +/* + * Completions via waitqueues. + */ +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) + +/* + * Kernel completions in 2.4.9 and beyond use a counter and a waitqueue, and + * our implementation is quite similar. Because __wake_up_common() is not + * exported, our implementations of compat_complete() and compat_complete_all() + * are somewhat racy: the counter is incremented outside of the waitqueue's + * lock. + * + * As a result, our completion cannot guarantee in-order wake ups. For example, + * suppose thread A is entering compat_complete(), thread B is sleeping inside + * compat_wait_for_completion(), and thread C is just now entering + * compat_wait_for_completion(). If Thread A is scheduled first and increments + * the counter, then gets swapped out, thread C may get scheduled and will + * quickly go through compat_wait_for_completion() (since done != 0) while + * thread B continues to sleep, even though thread B should have been the one + * to wake up. + */ + +#include +#include "compat_sched.h" +#include "compat_list.h" +#include // for lock_kernel()/unlock_kernel() +#include "compat_wait.h" + +typedef struct compat_completion { + unsigned int done; + wait_queue_head_t wq; +} compat_completion; + +#define compat_init_completion(comp) do { \ + (comp)->done = 0; \ + init_waitqueue_head(&(comp)->wq); \ +} while (0) +#define COMPAT_DECLARE_COMPLETION(comp) \ + compat_completion comp = { \ + .done = 0, \ + .wq = __WAIT_QUEUE_HEAD_INITIALIZER((comp).wq), \ + } + +/* + * Locking and unlocking the kernel lock here ensures that the thread + * is no longer running in module code: compat_complete_and_exit + * performs the sequence { lock_kernel(); up(comp); compat_exit(); }, with + * the final unlock_kernel performed implicitly by the resident kernel + * in do_exit. + */ +#define compat_wait_for_completion(comp) do { \ + spin_lock_irq(&(comp)->wq.lock); \ + if (!(comp)->done) { \ + DECLARE_WAITQUEUE(wait, current); \ + wait.flags |= WQ_FLAG_EXCLUSIVE; \ + __add_wait_queue_tail(&(comp)->wq, &wait); \ + do { \ + __set_current_state(TASK_UNINTERRUPTIBLE); \ + spin_unlock_irq(&(comp)->wq.lock); \ + schedule(); \ + spin_lock_irq(&(comp)->wq.lock); \ + } while (!(comp)->done); \ + __remove_wait_queue(&(comp)->wq, &wait); \ + } \ + (comp)->done--; \ + spin_unlock_irq(&(comp)->wq.lock); \ + lock_kernel(); \ + unlock_kernel(); \ +} while (0) + +/* XXX: I don't think I need to touch the BKL. */ +#define compat_complete(comp) do { \ + unsigned long flags; \ + spin_lock_irqsave(&(comp)->wq.lock, flags); \ + (comp)->done++; \ + spin_unlock_irqrestore(&(comp)->wq.lock, flags); \ + wake_up(&(comp)->wq); \ +} while (0) + +#define compat_complete_all(comp) do { \ + unsigned long flags; \ + spin_lock_irqsave(&(comp)->wq.lock, flags); \ + (comp)->done += UINT_MAX / 2; \ + spin_unlock_irqrestore(&(comp)->wq.lock, flags); \ + wake_up_all(&(comp)->wq); \ +} while (0) + +/* + * Completions via semaphores. + */ +#else + +#include "compat_semaphore.h" +#define compat_completion struct semaphore +#define compat_init_completion(comp) init_MUTEX_LOCKED(comp) +#define COMPAT_DECLARE_COMPLETION(comp) DECLARE_MUTEX_LOCKED(comp) + +#define compat_wait_for_completion(comp) do { \ + down(comp); \ + lock_kernel(); \ + unlock_kernel(); \ +} while (0) + +#define compat_complete(comp) up(comp) + +#endif + +#endif /* __COMPAT_COMPLETION_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_file.h @@ -0,0 +1,56 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_FILE_H__ +# define __COMPAT_FILE_H__ + + +/* The fput() API is modified in 2.2.0 --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +# define compat_fput(_file) fput(_file) +#else +# define compat_fput(_file) fput(_file, (_file)->f_inode) +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +# define compat_get_file(_file) get_file(_file) +# define compat_file_count(_file) file_count(_file) +#else +# define compat_get_file(_file) (_file)->f_count++ +# define compat_file_count(_file) (_file)->f_count +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 4) +# define compat_filp_close(_file, _files) filp_close(_file, _files) +#else +static inline void compat_filp_close(struct file* filp, fl_owner_t files) { + if (filp->f_op && filp->f_op->flush) { + filp->f_op->flush(filp); + } + /* + * Hopefully there are no locks to release on this filp. + * locks_remove_posix is not exported so we cannot use it... + */ + fput(filp); +} +#endif + + +#endif /* __COMPAT_FILE_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_fs.h @@ -0,0 +1,247 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_FS_H__ +# define __COMPAT_FS_H__ + +#include + +/* + * 2.6.5+ kernels define FS_BINARY_MOUNTDATA. Since it didn't exist and + * wasn't used prior, it's safe to define it to zero. + */ + +#ifndef FS_BINARY_MOUNTDATA +#define FS_BINARY_MOUNTDATA 0 +#endif + +/* + * MAX_LFS_FILESIZE wasn't defined until 2.5.4. + */ +#ifndef MAX_LFS_FILESIZE +# include +# if BITS_PER_LONG == 32 +# define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG - 1)) - 1) +# elif BITS_PER_LONG == 64 +# define MAX_LFS_FILESIZE 0x7fffffffffffffffUL +# endif +#endif + + +/* + * sendfile as a VFS op was born in 2.5.30. Unfortunately, it also changed + * signatures, first in 2.5.47, then again in 2.5.70, then again in 2.6.8. + * Luckily, the 2.6.8+ signature is the same as the 2.5.47 signature. And + * as of 2.6.23-rc1 sendfile is gone, replaced by splice_read... + * + * Let's not support sendfile from 2.5.30 to 2.5.47, because the 2.5.30 + * signature is much different and file_send_actor isn't externed. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) +#define VMW_SENDFILE_NONE +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) +#define VMW_SENDFILE_NEW +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) +#define VMW_SENDFILE_OLD +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 47) +#define VMW_SENDFILE_NEW +#else +#define VMW_SENDFILE_NONE +#endif + +/* + * splice_read is there since 2.6.17, but let's avoid 2.6.17-rcX kernels... + * After all nobody is using splice system call until 2.6.23 using it to + * implement sendfile. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) +#define VMW_SPLICE_READ 1 +#endif + +/* + * Filesystems wishing to use generic page cache read/write routines are + * supposed to implement aio_read and aio_write (calling into + * generic_file_aio_read() and generic_file_aio_write() if necessary). + * + * The VFS exports do_sync_read() and do_sync_write() as the "new" + * generic_file_read() and generic_file_write(), but filesystems need not + * actually implement read and write- the VFS will automatically call + * do_sync_write() and do_sync_read() when applications invoke the standard + * read() and write() system calls. + * + * In 2.6.19, generic_file_read() and generic_file_write() were removed, + * necessitating this change. AIO dates as far back as 2.5.42, but the API has + * changed over time, so for simplicity, we'll only enable it from 2.6.19 and + * on. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +# define VMW_USE_AIO +#endif + + +/* + * The alloc_inode and destroy_inode VFS ops didn't exist prior to 2.4.21. + * Without these functions, file systems can't embed inodes. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 21) +# define VMW_EMBED_INODE +#endif + + +/* + * iget() was removed from the VFS as of 2.6.25-rc1. The replacement for iget() + * is iget_locked() which was added in 2.5.17. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 17) +# define VMW_USE_IGET_LOCKED +#endif + +/* + * parent_ino was born in 2.5.5. For older kernels, let's use 2.5.5 + * implementation. It uses the dcache lock which is OK because per-dentry + * locking appeared after 2.5.5. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) +#define compat_parent_ino(dentry) parent_ino(dentry) +#else +#define compat_parent_ino(dentry) \ +({ \ + ino_t res; \ + spin_lock(&dcache_lock); \ + res = dentry->d_parent->d_inode->i_ino; \ + spin_unlock(&dcache_lock); \ + res; \ +}) +#endif + + +/* + * putname changed to __putname in 2.6.6. + */ +#define compat___getname() __getname() +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6) +#define compat___putname(name) putname(name) +#else +#define compat___putname(name) __putname(name) +#endif + + +/* + * inc_nlink, drop_nlink, and clear_nlink were added in 2.6.19. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +#define compat_inc_nlink(inode) ((inode)->i_nlink++) +#define compat_drop_nlink(inode) ((inode)->i_nlink--) +#define compat_clear_nlink(inode) ((inode)->i_nlink = 0) +#else +#define compat_inc_nlink(inode) inc_nlink(inode) +#define compat_drop_nlink(inode) drop_nlink(inode) +#define compat_clear_nlink(inode) clear_nlink(inode) +#endif + + +/* + * i_size_write and i_size_read were introduced in 2.6.0-test1 + * (though we'll look for them as of 2.6.1). They employ slightly different + * locking in order to guarantee atomicity, depending on the length of a long, + * whether the kernel is SMP, or whether the kernel is preemptible. Prior to + * i_size_write and i_size_read, there was no such locking, so that's the + * behavior we'll emulate. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1) +#define compat_i_size_read(inode) ((inode)->i_size) +#define compat_i_size_write(inode, size) ((inode)->i_size = size) +#else +#define compat_i_size_read(inode) i_size_read(inode) +#define compat_i_size_write(inode, size) i_size_write(inode, size) +#endif + + +/* + * filemap_fdatawrite was introduced in 2.5.12. Prior to that, modules used + * filemap_fdatasync instead. In 2.4.18, both filemap_fdatawrite and + * filemap_fdatawait began returning status codes. Prior to that, they were + * void functions, so we'll just have them return 0. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 18) +#define compat_filemap_fdatawrite(mapping) \ +({ \ + int result = 0; \ + filemap_fdatasync(mapping); \ + result; \ +}) +#define compat_filemap_fdatawait(mapping) \ +({ \ + int result = 0; \ + filemap_fdatawait(mapping); \ + result; \ +}) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) +#define compat_filemap_fdatawrite(mapping) filemap_fdatasync(mapping) +#define compat_filemap_fdatawait(mapping) filemap_fdatawait(mapping) +#else +#define compat_filemap_fdatawrite(mapping) filemap_fdatawrite(mapping) +#define compat_filemap_fdatawait(mapping) filemap_fdatawait(mapping) +#endif + + +/* + * filemap_write_and_wait was introduced in 2.6.6 and exported for module use + * in 2.6.16. It's really just a simple wrapper around filemap_fdatawrite and + * and filemap_fdatawait, which initiates a flush of all dirty pages, then + * waits for the pages to flush. The implementation here is a simplified form + * of the one found in 2.6.20-rc3. + * + * Unfortunately, it just isn't possible to implement this prior to 2.4.5, when + * neither filemap_fdatawait nor filemap_fdatasync were exported for module + * use. So we'll define it out and hope for the best. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 5) +#define compat_filemap_write_and_wait(mapping) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) +#define compat_filemap_write_and_wait(mapping) \ +({ \ + int result = 0; \ + if (mapping->nrpages) { \ + result = compat_filemap_fdatawrite(mapping); \ + if (result != -EIO) { \ + int result2 = compat_filemap_fdatawait(mapping); \ + if (!result) { \ + result = result2; \ + } \ + } \ + } \ + result; \ +}) +#else +#define compat_filemap_write_and_wait(mapping) filemap_write_and_wait(mapping) +#endif + + +/* + * invalidate_remote_inode was introduced in 2.6.0-test5. Prior to that, + * filesystems wishing to invalidate pages belonging to an inode called + * invalidate_inode_pages. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#define compat_invalidate_remote_inode(inode) invalidate_inode_pages(inode) +#else +#define compat_invalidate_remote_inode(inode) invalidate_remote_inode(inode) +#endif + +#endif /* __COMPAT_FS_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_init.h @@ -0,0 +1,38 @@ +/********************************************************* + * Copyright (C) 1999 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * compat_init.h: Initialization compatibility wrappers. + */ + +#ifndef __COMPAT_INIT_H__ +#define __COMPAT_INIT_H__ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +#include +#endif + +#ifndef module_init +#define module_init(x) int init_module(void) { return x(); } +#endif + +#ifndef module_exit +#define module_exit(x) void cleanup_module(void) { x(); } +#endif + +#endif /* __COMPAT_INIT_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_kernel.h @@ -0,0 +1,83 @@ +/********************************************************* + * Copyright (C) 2004 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_KERNEL_H__ +# define __COMPAT_KERNEL_H__ + +#include +#include + +/* + * container_of was introduced in 2.5.28 but it's easier to check like this. + */ +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +/* + * wait_for_completion and friends did not exist before 2.4.9. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 9) + +#define compat_complete_and_exit(comp, status) complete_and_exit(comp, status) + +#else + +#include "compat_completion.h" + +/* + * Used by _syscallX macros. Note that this is global variable, so + * do not rely on its contents too much. As exit() is only function + * we use, and we never check return value from exit(), we have + * no problem... + */ +extern int errno; + +/* + * compat_exit() provides an access to the exit() function. It must + * be named compat_exit(), as exit() (with different signature) is + * provided by x86-64, arm and other (but not by i386). + */ +#define __NR_compat_exit __NR_exit +static inline _syscall1(int, compat_exit, int, exit_code); + +/* + * See compat_wait_for_completion in compat_completion.h. + * compat_exit implicitly performs an unlock_kernel, in resident code, + * ensuring that the thread is no longer running in module code when the + * module is unloaded. + */ +#define compat_complete_and_exit(comp, status) do { \ + lock_kernel(); \ + compat_complete(comp); \ + compat_exit(status); \ +} while (0) + +#endif + +/* + * vsnprintf became available in 2.4.10. For older kernels, just fall back on + * vsprintf. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) +#define vsnprintf(str, size, fmt, args) vsprintf(str, fmt, args) +#endif + +#endif /* __COMPAT_KERNEL_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_list.h @@ -0,0 +1,55 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_LIST_H__ +# define __COMPAT_LIST_H__ + +#include + +/* + * list_add_tail is with us since 2.4.0, or something like that. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#define list_add_tail(newe, head) do { \ + struct list_head *__h = (head); \ + __list_add((newe), __h->prev, __h); \ +} while (0) +#endif + +/* + * list_for_each_safe() showed up in 2.4.10, but it may be backported so we + * just check for its existence. + */ +#ifndef list_for_each_safe +# define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) +#endif + +/* + * list_for_each_entry() showed up in 2.4.20, but it may be backported so we + * just check for its existence. + */ +#ifndef list_for_each_entry +# define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) +#endif + +#endif /* __COMPAT_LIST_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_mm.h @@ -0,0 +1,134 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_MM_H__ +# define __COMPAT_MM_H__ + + +#include + + +/* The get_page() API appeared in 2.3.7 --hpreg */ +/* Sometime during development it became function instead of macro --petr */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(get_page) +# define get_page(_page) atomic_inc(&(_page)->count) +/* The __free_page() API is exported in 2.1.67 --hpreg */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 67) +# define put_page __free_page +# else +# include "compat_page.h" + +# define page_to_phys(_page) (page_to_pfn(_page) << PAGE_SHIFT) +# define put_page(_page) free_page(page_to_phys(_page)) +# endif +#endif + + +/* page_count() is 2.4.0 invention. Unfortunately unavailable in some RedHat + * kernels (for example 2.4.21-4-RHEL3). */ +/* It is function since 2.6.0, and hopefully RedHat will not play silly games + * with mm_inline.h again... */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(page_count) +# define page_count(page) atomic_read(&(page)->count) +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +# define compat_vm_pgoff(vma) ((vma)->vm_offset >> PAGE_SHIFT) + +static inline unsigned long compat_do_mmap_pgoff(struct file *file, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flag, unsigned long pgoff) +{ + unsigned long ret = -EINVAL; + + if (pgoff < 1 << (32 - PAGE_SHIFT)) { + ret = do_mmap(file, addr, len, prot, flag, pgoff << PAGE_SHIFT); + } + return ret; +} + +#else +# define compat_vm_pgoff(vma) (vma)->vm_pgoff +# ifdef VMW_SKAS_MMAP +# define compat_do_mmap_pgoff(f, a, l, p, g, o) \ + do_mmap_pgoff(current->mm, f, a, l, p, g, o) +# else +# define compat_do_mmap_pgoff(f, a, l, p, g, o) \ + do_mmap_pgoff(f, a, l, p, g, o) +# endif +#endif + + +/* 2.2.x uses 0 instead of some define */ +#ifndef NOPAGE_SIGBUS +#define NOPAGE_SIGBUS (0) +#endif + + +/* 2.2.x does not have HIGHMEM support */ +#ifndef GFP_HIGHUSER +#define GFP_HIGHUSER (GFP_USER) +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + +#include "compat_page.h" + +static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) +{ + unsigned long addr; + + addr = __get_free_pages(gfp_mask, order); + if (!addr) { + return NULL; + } + return virt_to_page(addr); +} +#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) + +#endif + +/* + * In 2.4.14, the logic behind the UnlockPage macro was moved to the + * unlock_page() function. Later (in 2.5.12), the UnlockPage macro was removed + * altogether, and nowadays everyone uses unlock_page(). + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 14) +#define compat_unlock_page(page) UnlockPage(page) +#else +#define compat_unlock_page(page) unlock_page(page) +#endif + +/* + * In 2.4.10, vmtruncate was changed from returning void to returning int. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) +#define compat_vmtruncate(inode, size) \ +({ \ + int result = 0; \ + vmtruncate(inode, size); \ + result; \ +}) +#else +#define compat_vmtruncate(inode, size) vmtruncate(inode, size) +#endif + + +#endif /* __COMPAT_MM_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_module.h @@ -0,0 +1,72 @@ +/********************************************************* + * Copyright (C) 2007 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * compat_module.h -- + */ + +#ifndef __COMPAT_MODULE_H__ +# define __COMPAT_MODULE_H__ + + +#include + + +/* + * Modules wishing to use the GPL license are required to include a + * MODULE_LICENSE definition in their module source as of 2.4.10. + */ +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(license) +#endif + +/* + * To make use of our own home-brewed MODULE_INFO, we need macros to + * concatenate two expressions to "__mod_", and and to convert an + * expression into a string. I'm sure we've got these in our codebase, + * but I'd rather not introduce such a dependency in a compat header. + */ +#ifndef __module_cat +#define __module_cat_1(a, b) __mod_ ## a ## b +#define __module_cat(a, b) __module_cat_1(a, b) +#endif + +#ifndef __stringify +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) +#endif + +/* + * MODULE_INFO was born in 2.5.69. + */ +#ifndef MODULE_INFO +#define MODULE_INFO(tag, info) \ +static const char __module_cat(tag, __LINE__)[] \ + __attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info +#endif + +/* + * MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx" + * string to the module's version, but that was removed in 2.6.10, so we'll + * ignore it in our wrapper. + */ +#ifndef MODULE_VERSION +#define MODULE_VERSION(_version) MODULE_INFO(version, _version) +#endif + +#endif /* __COMPAT_MODULE_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_namei.h @@ -0,0 +1,57 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_NAMEI_H__ +# define __COMPAT_NAMEI_H__ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 18) +#include +#endif + +/* + * In 2.6.25-rc2, dentry and mount objects were removed from the nameidata + * struct. They were both replaced with a struct path. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) +#define compat_vmw_nd_to_dentry(nd) (nd).path.dentry +#else +#define compat_vmw_nd_to_dentry(nd) (nd).dentry +#endif + +/* In 2.6.25-rc2, path_release(&nd) was replaced with path_put(&nd.path). */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) +#define compat_path_release(nd) path_put(&(nd)->path) +#else +#define compat_path_release(nd) path_release(nd) +#endif + +/* path_lookup was exported in 2.4.25 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) +#define compat_path_lookup(path, flags, nd) path_lookup(path, flags, nd) +#else +#define compat_path_lookup(path, flags, nd) \ + ({ \ + int ret = 0; \ + if (path_init(path, flags, nd)) { \ + ret = path_walk(path, nd); \ + } \ + ret; \ + }) +#endif + +#endif /* __COMPAT_NAMEI_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_page.h @@ -0,0 +1,75 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_PAGE_H__ +# define __COMPAT_PAGE_H__ + + +#include +#include + + +/* The pfn_to_page() API appeared in 2.5.14 and changed to function during 2.6.x */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pfn_to_page) +# define pfn_to_page(_pfn) (mem_map + (_pfn)) +# define page_to_pfn(_page) ((_page) - mem_map) +#endif + + +/* The virt_to_page() API appeared in 2.4.0 --hpreg */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(virt_to_page) +# define virt_to_page(_kvAddr) pfn_to_page(MAP_NR(_kvAddr)) +#endif + + +/* + * The get_order() API appeared at some point in 2.3.x, and was then backported + * in 2.2.17-21mdk and in the stock 2.2.18. Because we can only detect its + * definition through makefile tricks, we provide our own for now --hpreg + */ +static inline int +compat_get_order(unsigned long size) // IN +{ + int order; + + size = (size - 1) >> (PAGE_SHIFT - 1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + + return order; +} + +/* + * BUG() was added to in 2.2.18, and was moved to + * in 2.5.58. + * + * XXX: Technically, this belongs in some sort of "compat_asm_page.h" file, but + * since our compatibility wrappers don't distinguish between and + * , putting it here is reasonable. + */ +#ifndef BUG +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + __asm__ __volatile__(".byte 0x0f,0x0b"); \ +} while (0) +#endif + +#endif /* __COMPAT_PAGE_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_sched.h @@ -0,0 +1,274 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_SCHED_H__ +# define __COMPAT_SCHED_H__ + + +#include + +/* CLONE_KERNEL available in 2.5.35 and higher. */ +#ifndef CLONE_KERNEL +#define CLONE_KERNEL CLONE_FILES | CLONE_FS | CLONE_SIGHAND +#endif + +/* TASK_COMM_LEN become available in 2.6.11. */ +#ifndef TASK_COMM_LEN +#define TASK_COMM_LEN 16 +#endif + +/* The capable() API appeared in 2.1.92 --hpreg */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 92) +# define capable(_capability) suser() +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) +# define need_resched() need_resched +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) +# define need_resched() (current->need_resched) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) +# define cond_resched() (need_resched() ? schedule() : (void) 0) +#endif + +/* Oh well. We need yield... Happy us! */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) +# ifdef __x86_64__ +# define compat_yield() there_is_nothing_like_yield() +# else +# include +# include + +/* + * Used by _syscallX macros. Note that this is global variable, so + * do not rely on its contents too much. As exit() is only function + * we use, and we never check return value from exit(), we have + * no problem... + */ +extern int errno; + +/* + * compat_exit() provides an access to the exit() function. It must + * be named compat_exit(), as exit() (with different signature) is + * provided by x86-64, arm and other (but not by i386). + */ +# define __NR_compat_yield __NR_sched_yield +static inline _syscall0(int, compat_yield); +# endif +#else +# define compat_yield() yield() +#endif + + +/* + * Since 2.5.34 there are two methods to enumerate tasks: + * for_each_process(p) { ... } which enumerates only tasks and + * do_each_thread(g,t) { ... } while_each_thread(g,t) which enumerates + * also threads even if they share same pid. + */ +#ifndef for_each_process +# define for_each_process(p) for_each_task(p) +#endif + +#ifndef do_each_thread +# define do_each_thread(g, t) for_each_task(g) { t = g; do +# define while_each_thread(g, t) while (0) } +#endif + + +/* + * Lock for signal mask is moving target... + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 40) && defined(CLONE_PID) +/* 2.4.x without NPTL patches or early 2.5.x */ +#define compat_sigmask_lock sigmask_lock +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(¤t->blocked, (siginfo_ptr)) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 60) && !defined(INIT_SIGHAND) +/* RedHat's 2.4.x with first version of NPTL support, or 2.5.40 to 2.5.59 */ +#define compat_sigmask_lock sig->siglock +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(¤t->blocked, (siginfo_ptr)) +#else +/* RedHat's 2.4.x with second version of NPTL support, or 2.5.60+. */ +#define compat_sigmask_lock sighand->siglock +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(¤t->blocked, (siginfo_ptr)) +#else +#define compat_dequeue_signal_current(siginfo_ptr) \ + dequeue_signal(current, ¤t->blocked, (siginfo_ptr)) +#endif +#endif + +/* + * recalc_sigpending() had task argument in the past + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 29) && defined(CLONE_PID) +/* 2.4.x without NPTL patches or early 2.5.x */ +#define compat_recalc_sigpending() recalc_sigpending(current) +#else +/* RedHat's 2.4.x with NPTL support, or 2.5.29+ */ +#define compat_recalc_sigpending() recalc_sigpending() +#endif + + +/* + * reparent_to_init() was introduced in 2.4.8. In 2.5.38 (or possibly + * earlier, but later than 2.5.31) a call to it was added into + * daemonize(), so compat_daemonize no longer needs to call it. + * + * In 2.4.x kernels reparent_to_init() forgets to do correct refcounting + * on current->user. It is better to count one too many than one too few... + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 38) +#define compat_reparent_to_init() do { \ + reparent_to_init(); \ + atomic_inc(¤t->user->__count); \ + } while (0) +#else +#define compat_reparent_to_init() do {} while (0) +#endif + + +/* + * daemonize appeared in 2.2.18. Except 2.2.17-4-RH7.0, which has it too. + * Fortunately 2.2.17-4-RH7.0 uses versioned symbols, so we can check + * its existence with defined(). + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) && !defined(daemonize) +static inline void daemonize(void) { + struct fs_struct *fs; + + exit_mm(current); + current->session = 1; + current->pgrp = 1; + exit_fs(current); + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); +} +#endif + + +/* + * flush_signals acquires sighand->siglock since 2.5.61... Verify RH's kernels! + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) +#define compat_flush_signals(task) do { \ + spin_lock_irq(&task->compat_sigmask_lock); \ + flush_signals(task); \ + spin_unlock_irq(&task->compat_sigmask_lock); \ + } while (0) +#else +#define compat_flush_signals(task) flush_signals(task) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) +#define compat_allow_signal(signr) do { \ + spin_lock_irq(¤t->compat_sigmask_lock); \ + sigdelset(¤t->blocked, signr); \ + compat_recalc_sigpending(); \ + spin_unlock_irq(¤t->compat_sigmask_lock); \ + } while (0) +#else +#define compat_allow_signal(signr) allow_signal(signr) +#endif + +/* + * daemonize can set process name since 2.5.61. Prior to 2.5.61, daemonize + * didn't block signals on our behalf. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) +#define compat_daemonize(x...) \ +({ \ + /* Beware! No snprintf here, so verify arguments! */ \ + sprintf(current->comm, x); \ + \ + /* Block all signals. */ \ + spin_lock_irq(¤t->compat_sigmask_lock); \ + sigfillset(¤t->blocked); \ + compat_recalc_sigpending(); \ + spin_unlock_irq(¤t->compat_sigmask_lock); \ + compat_flush_signals(current); \ + \ + daemonize(); \ + compat_reparent_to_init(); \ +}) +#else +#define compat_daemonize(x...) daemonize(x) +#endif + + +/* + * set priority for specified thread. Exists on 2.6.x kernels and some + * 2.4.x vendor's kernels. + */ +#if defined(VMW_HAVE_SET_USER_NICE) +#define compat_set_user_nice(task, n) set_user_nice((task), (n)) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#define compat_set_user_nice(task, n) do { (task)->priority = 20 - (n); } while (0) +#elif !defined(VMW_HAVE_SET_USER_NICE) +#define compat_set_user_nice(task, n) do { (task)->nice = (n); } while (0) +#endif + +/* + * try to freeze a process. For kernels 2.6.11 or newer, we know how to choose + * the interface. The problem is that the oldest interface, introduced in + * 2.5.18, was backported to 2.4.x kernels. So if we're older than 2.6.11, + * we'll decide what to do based on whether or not swsusp was configured + * for the kernel. For kernels 2.6.20 and newer, we'll also need to include + * freezer.h since the try_to_freeze definition was pulled out of sched.h. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) || defined(VMW_TL10S64_WORKAROUND) +#define compat_try_to_freeze() try_to_freeze() +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) +#define compat_try_to_freeze() try_to_freeze(PF_FREEZE) +#elif defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SOFTWARE_SUSPEND2) +#include "compat_mm.h" +#include +#include +static inline int compat_try_to_freeze(void) { + if (current->flags & PF_FREEZE) { + refrigerator(PF_FREEZE); + return 1; + } else { + return 0; + } +} +#else +static inline int compat_try_to_freeze(void) { return 0; } +#endif + +/* + * As of 2.6.23-rc1, kernel threads are no longer freezable by + * default. Instead, kernel threads that need to be frozen must opt-in + * by calling set_freezable() as soon as the thread is created. + */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) +#define compat_set_freezable() do { set_freezable(); } while (0) +#else +#define compat_set_freezable() do {} while (0) +#endif + +#endif /* __COMPAT_SCHED_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_semaphore.h @@ -0,0 +1,44 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_SEMAPHORE_H__ +# define __COMPAT_SEMAPHORE_H__ + + +#include + + +/* +* The init_MUTEX_LOCKED() API appeared in 2.2.18, and is also in +* 2.2.17-21mdk --hpreg +*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) + #ifndef init_MUTEX_LOCKED + #define init_MUTEX_LOCKED(_sem) *(_sem) = MUTEX_LOCKED + #endif + #ifndef DECLARE_MUTEX + #define DECLARE_MUTEX(name) struct semaphore name = MUTEX + #endif + #ifndef DECLARE_MUTEX_LOCKED + #define DECLARE_MUTEX_LOCKED(name) struct semaphore name = MUTEX_LOCKED + #endif +#endif + + +#endif /* __COMPAT_SEMAPHORE_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_slab.h @@ -0,0 +1,70 @@ +/********************************************************* + * Copyright (C) 2005 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_SLAB_H__ +# define __COMPAT_SLAB_H__ + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +# include +#else +# include +#endif + +/* + * Before 2.6.20, kmem_cache_t was the accepted way to refer to a kmem_cache + * structure. Prior to 2.6.15, this structure was called kmem_cache_s, and + * afterwards it was renamed to kmem_cache. Here we keep things simple and use + * the accepted typedef until it became deprecated, at which point we switch + * over to the kmem_cache name. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +# define compat_kmem_cache struct kmem_cache +#else +# define compat_kmem_cache kmem_cache_t +#endif + +/* + * Up to 2.6.22 kmem_cache_create has 6 arguments - name, size, alignment, flags, + * constructor, and destructor. Then for some time kernel was asserting that + * destructor is NULL, and since 2.6.23-pre1 kmem_cache_create takes only 5 + * arguments - destructor is gone. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) || defined(VMW_KMEMCR_HAS_DTOR) +#define compat_kmem_cache_create(name, size, align, flags, ctor) \ + kmem_cache_create(name, size, align, flags, ctor, NULL) +#else +#define compat_kmem_cache_create(name, size, align, flags, ctor) \ + kmem_cache_create(name, size, align, flags, ctor) +#endif + +/* + * Up to 2.6.23 kmem_cache constructor has three arguments - pointer to block to + * prepare (aka "this"), from which cache it came, and some unused flags. After + * 2.6.23 flags were removed, and order of "this" and cache parameters was swapped... + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) +# define VMW_KMEMCR_CTOR_HAS_3_ARGS +#endif +#ifdef VMW_KMEMCR_CTOR_HAS_3_ARGS +typedef void compat_kmem_cache_ctor(void *, compat_kmem_cache *, unsigned long); +#else +typedef void compat_kmem_cache_ctor(compat_kmem_cache *, void *); +#endif + +#endif /* __COMPAT_SLAB_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_spinlock.h @@ -0,0 +1,68 @@ +/********************************************************* + * Copyright (C) 2005 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_SPINLOCK_H__ +# define __COMPAT_SPINLOCK_H__ + + +/* + * The spin_lock() API appeared in 2.1.25 in asm/smp_lock.h + * It moved in 2.1.30 to asm/spinlock.h + * It moved again in 2.3.18 to linux/spinlock.h + * + * --hpreg + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 18) +# include +#else +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 30) +# include +# else +typedef struct {} spinlock_t; +# define spin_lock_init(lock) +# define spin_lock(lock) +# define spin_unlock(lock) +# define spin_lock_irqsave(lock, flags) do { \ + save_flags(flags); \ + cli(); \ + spin_lock(lock); \ + } while (0) +# define spin_unlock_irqrestore(lock, flags) do { \ + spin_unlock(lock); \ + restore_flags(flags); \ + } while (0) +# endif +#endif + + +/* + * Preempt support was added during 2.5.x development cycle, and later + * it was backported to 2.4.x. In 2.4.x backport these definitions + * live in linux/spinlock.h, that's why we put them here (in 2.6.x they + * are defined in linux/preempt.h which is included by linux/spinlock.h). + */ +#ifdef CONFIG_PREEMPT +#define compat_preempt_disable() preempt_disable() +#define compat_preempt_enable() preempt_enable() +#else +#define compat_preempt_disable() do { } while (0) +#define compat_preempt_enable() do { } while (0) +#endif + + +#endif /* __COMPAT_SPINLOCK_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_statfs.h @@ -0,0 +1,32 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_STATFS_H__ +# define __COMPAT_STATFS_H__ + +/* vfs.h simply include statfs.h, but it knows what directory statfs.h is in. */ +#include + +/* 2.5.74 renamed struct statfs to kstatfs. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 74) +#define compat_kstatfs kstatfs +#else +#define compat_kstatfs statfs +#endif + +#endif /* __COMPAT_STATFS_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_string.h @@ -0,0 +1,42 @@ +/********************************************************* + * Copyright (C) 2007 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_STRING_H__ +# define __COMPAT_STRING_H__ + +#include + +/* + * kstrdup was born in 2.6.13. This implementation is almost identical to the + * one found there. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) +#define compat_kstrdup(s, gfp) kstrdup(s, gfp) +#else +#define compat_kstrdup(s, gfp) \ +({ \ + size_t len; \ + char *buf; \ + len = strlen(s) + 1; \ + buf = kmalloc(len, gfp); \ + memcpy(buf, s, len); \ + buf; \ +}) +#endif + +#endif /* __COMPAT_STRING_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_uaccess.h @@ -0,0 +1,79 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_UACCESS_H__ +# define __COMPAT_UACCESS_H__ + + +/* User space access functions moved in 2.1.7 to asm/uaccess.h --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 7) +# include +#else +# include +#endif + + +/* get_user() API modified in 2.1.4 to take 2 arguments --hpreg */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 4) +# define compat_get_user get_user +#else +/* + * We assign 0 to the variable in case of failure to prevent "`_var' might be + * used uninitialized in this function" compiler warnings. I think it is OK, + * because the hardware-based version in newer kernels probably has the same + * semantics and does not guarantee that the value of _var will not be + * modified, should the access fail --hpreg + */ +# define compat_get_user(_var, _uvAddr) ({ \ + int _status; \ + \ + _status = verify_area(VERIFY_READ, _uvAddr, sizeof(*(_uvAddr))); \ + if (_status == 0) { \ + (_var) = get_user(_uvAddr); \ + } else { \ + (_var) = 0; \ + } \ + _status; \ +}) +#endif + + +/* + * The copy_from_user() API appeared in 2.1.4 + * + * The emulation is not perfect here, but it is conservative: on failure, we + * always return the total size, instead of the potentially smaller faulty + * size --hpreg + * + * Since 2.5.55 copy_from_user() is no longer macro. + */ +#if !defined(copy_from_user) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) +# define copy_from_user(_to, _from, _size) ( \ + verify_area(VERIFY_READ, _from, _size) \ + ? (_size) \ + : (memcpy_fromfs(_to, _from, _size), 0) \ +) +# define copy_to_user(_to, _from, _size) ( \ + verify_area(VERIFY_WRITE, _to, _size) \ + ? (_size) \ + : (memcpy_tofs(_to, _from, _size), 0) \ +) +#endif + + +#endif /* __COMPAT_UACCESS_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_version.h @@ -0,0 +1,121 @@ +/********************************************************* + * Copyright (C) 1998 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_VERSION_H__ +# define __COMPAT_VERSION_H__ + +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_DISTRIBUTE +//#include "includeCheck.h" + + +#ifndef __linux__ +# error "linux-version.h" +#endif + + +#include + +/* Appeared in 2.1.90 --hpreg */ +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) +#endif + + +/* + * Distinguish relevant classes of Linux kernels. + * + * The convention is that version X defines all + * the KERNEL_Y symbols where Y <= X. + * + * XXX Do not add more definitions here. This way of doing things does not + * scale, and we are going to phase it out soon --hpreg + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) +# define KERNEL_2_1 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) +# define KERNEL_2_2 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1) +# define KERNEL_2_3_1 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15) +/* new networking */ +# define KERNEL_2_3_15 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) +/* new procfs */ +# define KERNEL_2_3_25 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) +/* even newer procfs */ +# define KERNEL_2_3_29 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43) +/* softnet changes */ +# define KERNEL_2_3_43 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47) +/* more softnet changes */ +# define KERNEL_2_3_47 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99) +/* name in netdevice struct is array and not pointer */ +# define KERNEL_2_3_99 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +/* New 'owner' member at the beginning of struct file_operations */ +# define KERNEL_2_4_0 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) +/* New netif_rx_ni() --hpreg */ +# define KERNEL_2_4_8 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22) +/* New vmap() */ +# define KERNEL_2_4_22 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2) +/* New kdev_t, major()/minor() API --hpreg */ +# define KERNEL_2_5_2 +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) +/* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */ +# define KERNEL_2_5_5 +#endif + + +#endif /* __COMPAT_VERSION_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/compat_wait.h @@ -0,0 +1,225 @@ +/********************************************************* + * Copyright (C) 2002 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#ifndef __COMPAT_WAIT_H__ +# define __COMPAT_WAIT_H__ + + +#include +#include +#include + +#include "compat_file.h" + + +/* + * The DECLARE_WAITQUEUE() API appeared in 2.3.1 + * It was back ported in 2.2.18 + * + * --hpreg + */ + +#ifndef DECLARE_WAITQUEUE + +typedef struct wait_queue *wait_queue_head_t; +# define init_waitqueue_head(_headPtr) *(_headPtr) = NULL +# define DECLARE_WAITQUEUE(_var, _task) \ + struct wait_queue _var = {_task, NULL, } + +typedef struct wait_queue wait_queue_t; +# define init_waitqueue_entry(_wait, _task) ((_wait)->task = (_task)) + +#endif + +/* + * The 'struct poll_wqueues' appeared in 2.5.48, when global + * /dev/epoll interface was added. It was backported to the + * 2.4.20-wolk4.0s. + */ + +#ifdef VMW_HAVE_EPOLL // { +#define compat_poll_wqueues struct poll_wqueues +#else // } { +#define compat_poll_wqueues poll_table +#endif // } + +#ifdef VMW_HAVE_EPOLL // { + +/* If prototype does not match, build will abort here */ +extern void poll_initwait(compat_poll_wqueues *); + +#define compat_poll_initwait(wait, table) ( \ + poll_initwait((table)), \ + (wait) = &(table)->pt \ +) + +#define compat_poll_freewait(wait, table) ( \ + poll_freewait((table)) \ +) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) // { + +/* If prototype does not match, build will abort here */ +//extern void poll_initwait(compat_poll_wqueues *); + +#define compat_poll_initwait(wait, table) ( \ + (wait) = (table), \ + poll_initwait(wait) \ +) + +#define compat_poll_freewait(wait, table) ( \ + poll_freewait((table)) \ +) + +#else // } { + +#define compat_poll_initwait(wait, table) ( \ + (wait) = (table), /* confuse compiler */ \ + (wait) = (poll_table *) __get_free_page(GFP_KERNEL), \ + (wait)->nr = 0, \ + (wait)->entry = (struct poll_table_entry *)((wait) + 1), \ + (wait)->next = NULL \ +) + +static inline void +poll_freewait(poll_table *wait) +{ + while (wait) { + struct poll_table_entry * entry; + poll_table *old; + + entry = wait->entry + wait->nr; + while (wait->nr > 0) { + wait->nr--; + entry--; + remove_wait_queue(entry->wait_address, &entry->wait); + compat_fput(entry->filp); + } + old = wait; + wait = wait->next; + free_page((unsigned long) old); + } +} + +#define compat_poll_freewait(wait, table) ( \ + poll_freewait((wait)) \ +) + +#endif // } + +/* + * The wait_event_interruptible_timeout() interface is not + * defined in pre-2.6 kernels. + */ +#ifndef wait_event_interruptible_timeout +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + set_current_state(TASK_RUNNING); \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) +#endif + +/* + * The wait_event_timeout() interface is not + * defined in pre-2.6 kernels. + */ +#ifndef wait_event_timeout +#define __wait_event_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + } \ + set_current_state(TASK_RUNNING); \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_timeout(wq, condition, __ret); \ + __ret; \ +}) +#endif + +/* + * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39)) +# define COMPAT_DEFINE_WAIT(_wait) \ + DECLARE_WAITQUEUE(_wait, current) +# define compat_init_prepare_to_wait(_sleep, _wait, _state) \ + do { \ + __set_current_state(_state); \ + add_wait_queue(_sleep, _wait); \ + } while (0) +# define compat_cont_prepare_to_wait(_sleep, _wait, _state) \ + set_current_state(_state) +# define compat_finish_wait(_sleep, _wait, _state) \ + do { \ + __set_current_state(_state); \ + remove_wait_queue(_sleep, _wait); \ + } while (0) +#else +# define COMPAT_DEFINE_WAIT(_wait) \ + DEFINE_WAIT(_wait) +# define compat_init_prepare_to_wait(_sleep, _wait, _state) \ + prepare_to_wait(_sleep, _wait, _state) +# define compat_cont_prepare_to_wait(_sleep, _wait, _state) \ + prepare_to_wait(_sleep, _wait, _state) +# define compat_finish_wait(_sleep, _wait, _state) \ + finish_wait(_sleep, _wait) +#endif + +#endif /* __COMPAT_WAIT_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/control.c @@ -0,0 +1,332 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * control.c -- + * + * Control operations for the vmblock driver. + * + */ + +#include "driver-config.h" +#include +#include +#include +#include "compat_uaccess.h" +#include "compat_fs.h" + +#include "vmblockInt.h" +#include "block.h" + + +/* procfs initialization/cleanup functions */ +static int SetupProcDevice(void); +static int CleanupProcDevice(void); + +/* procfs entry file operations */ +ssize_t ControlFileOpWrite(struct file *filp, const char __user *buf, + size_t cmd, loff_t *ppos); +static int ControlFileOpRelease(struct inode *inode, struct file *file); + + +static struct proc_dir_entry *controlProcDirEntry; +struct file_operations ControlFileOps = { + .owner = THIS_MODULE, + .write = ControlFileOpWrite, + .release = ControlFileOpRelease, +}; + + +/* Public initialization/cleanup routines */ + +/* + *---------------------------------------------------------------------------- + * + * VMBlockInitControlOps -- + * + * Sets up state for control operations. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +VMBlockInitControlOps(void) +{ + int ret; + + ret = BlockInit(); + if (ret < 0) { + Warning("VMBlockInitControlOps: could not initialize blocking ops.\n"); + return ret; + } + + ret = SetupProcDevice(); + if (ret < 0) { + Warning("VMBlockInitControlOps: could not setup proc device.\n"); + BlockCleanup(); + return ret; + } + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMBlockCleanupControlOps -- + * + * Cleans up state for control operations. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +VMBlockCleanupControlOps(void) +{ + int ret; + + ret = CleanupProcDevice(); + if (ret < 0) { + Warning("VMBlockCleanupControlOps: could not cleanup proc device.\n"); + return ret; + } + + BlockCleanup(); + return 0; +} + + +/* Private initialization/cleanup routines */ + +/* + *---------------------------------------------------------------------------- + * + * SetupProcDevice -- + * + * Adds entries to /proc used to control file blocks. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +SetupProcDevice(void) +{ + struct proc_dir_entry *controlProcEntry; + struct proc_dir_entry *controlProcMountpoint; + + /* Create /proc/fs/vmblock */ + controlProcDirEntry = proc_mkdir(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); + if (!controlProcDirEntry) { + Warning("SetupProcDevice: could not create /proc/" + VMBLOCK_CONTROL_PROC_DIRNAME "\n"); + return -EINVAL; + } + + controlProcDirEntry->owner = THIS_MODULE; + + /* Create /proc/fs/vmblock/mountPoint */ + controlProcMountpoint = proc_mkdir(VMBLOCK_CONTROL_MOUNTPOINT, + controlProcDirEntry); + if (!controlProcMountpoint) { + Warning("SetupProcDevice: could not create " + VMBLOCK_MOUNT_POINT "\n"); + remove_proc_entry(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); + return -EINVAL; + } + + controlProcMountpoint->owner = THIS_MODULE; + + /* Create /proc/fs/vmblock/dev */ + controlProcEntry = create_proc_entry(VMBLOCK_CONTROL_DEVNAME, + VMBLOCK_CONTROL_MODE, + controlProcDirEntry); + if (!controlProcEntry) { + Warning("SetupProcDevice: could not create " VMBLOCK_DEVICE "\n"); + remove_proc_entry(VMBLOCK_CONTROL_MOUNTPOINT, controlProcDirEntry); + remove_proc_entry(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); + return -EINVAL; + } + + controlProcEntry->proc_fops = &ControlFileOps; + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * CleanupProcDevice -- + * + * Removes /proc entries for controlling file blocks. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +CleanupProcDevice(void) +{ + if (controlProcDirEntry) { + remove_proc_entry(VMBLOCK_CONTROL_MOUNTPOINT, controlProcDirEntry); + remove_proc_entry(VMBLOCK_CONTROL_DEVNAME, controlProcDirEntry); + remove_proc_entry(VMBLOCK_CONTROL_PROC_DIRNAME, NULL); + } + return 0; +} + + +/* procfs file operations */ + +/* + *---------------------------------------------------------------------------- + * + * ControlFileOpWrite -- + * + * write implementation for our control file. This accepts either add or + * delete commands and the buffer contains the file to block. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +ssize_t +ControlFileOpWrite(struct file *file, // IN: Opened file, used for ID + const char __user *buf, // IN: NUL-terminated filename + size_t cmd, // IN: VMBlock command (usually count) + loff_t *ppos) // IN/OUT: File offset (unused) +{ + int ret; + ssize_t i; + char *filename; + +#ifdef VMX86_DEVEL + if (cmd == VMBLOCK_LIST_FILEBLOCKS) { + BlockListFileBlocks(); + return 0; + } +#endif + + /* + * XXX: Can we GPL our modules already? This is gross. On kernels 2.6.6 + * through 2.6.12 when CONFIG_AUDITSYSCALL is defined, putname() turns into + * a macro that calls audit_putname(), which happens to only be exported to + * GPL modules (until 2.6.9). Here we work around this by calling + * __getname() and __putname() to get our path buffer directly, + * side-stepping the syscall auditing and doing the copy from user space + * ourself. Change this back once we GPL the module. + */ + filename = compat___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. + * Hard-coding this size is also gross, but it's our only option here and + * InodeOpLookup() already set a bad example by doing this. + */ + ret = strncpy_from_user(filename, buf, PATH_MAX); + if (ret < 0 || ret >= PATH_MAX) { + Warning("ControlFileOpWrite: Could not access provided user buffer.\n"); + ret = ret < 0 ? ret : -ENAMETOOLONG; + goto exit; + } + + /* Remove all trailing path separators. */ + for (i = ret - 1; i >= 0 && filename[i] == '/'; i--) { + filename[i] = '\0'; + } + + if (i < 0) { + ret = -EINVAL; + goto exit; + } + + switch (cmd) { + case VMBLOCK_ADD_FILEBLOCK: + ret = BlockAddFileBlock(filename, file); + break; + case VMBLOCK_DEL_FILEBLOCK: + ret = BlockRemoveFileBlock(filename, file); + break; + default: + Warning("ControlFileOpWrite: unrecognized command (%u) recieved\n", + (unsigned)cmd); + ret = -EINVAL; + break; + } + +exit: + compat___putname(filename); + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * ControlFileOpRelease -- + * + * Called when the file is closed. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +ControlFileOpRelease(struct inode *inode, // IN + struct file *file) // IN +{ + BlockRemoveAllBlocks(file); + return 0; +} --- /dev/null +++ b/drivers/vmware/vmblock/dbllnklst.c @@ -0,0 +1,399 @@ +/********************************************************* + * Copyright (C) 1998 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +#include "vmware.h" +#include "dbllnklst.h" + +/* + * dbllnklst.c -- + * + * Light (but nonetheless powerful) implementation of doubly linked lists + */ + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Init -- + * + * Initialize a member of a doubly linked list + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +DblLnkLst_Init(DblLnkLst_Links *l) // IN +{ + ASSERT(l); + + l->prev = l->next = l; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Link -- + * + * Merge two doubly linked lists into one + * + * The operation is commutative + * The operation is inversible (its inverse is DblLnkLst_Unlink) + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +DblLnkLst_Link(DblLnkLst_Links *l1, // IN + DblLnkLst_Links *l2) // IN +{ + DblLnkLst_Links *tmp; + + ASSERT(l1); + ASSERT(l2); + + (tmp = l1->prev)->next = l2; + (l1->prev = l2->prev)->next = l1; + l2->prev = tmp ; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Unlink -- + * + * Split one doubly linked list into two + * + * No check is performed: the caller must ensure that both members + * belong to the same doubly linked list + * + * The operation is commutative + * The operation is inversible (its inverse is DblLnkLst_Link) + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +DblLnkLst_Unlink(DblLnkLst_Links *l1, // IN + DblLnkLst_Links *l2) // IN +{ + DblLnkLst_Links *tmp; + + ASSERT(l1); + ASSERT(l2); + + tmp = l1->prev ; + (l1->prev = l2->prev)->next = l1; + (l2->prev = tmp )->next = l2; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Unlink1 -- + * + * Unlink an element from its list. + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +DblLnkLst_Unlink1(DblLnkLst_Links *l) // IN +{ + ASSERT(l); + + DblLnkLst_Unlink(l, l->next); +} + + +/* + *---------------------------------------------------------------------------- + * + * DblLnkLst_IsLinked -- + * + * Determines whether an element is linked with any other elements. + * + * Results: + * TRUE if link is linked, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +Bool +DblLnkLst_IsLinked(DblLnkLst_Links const *l) // IN +{ + ASSERT(l); + + ASSERT((l->prev == l && l->next == l) || + (l->prev != l && l->next != l)); + + /* + * A DblLnkLst_Links is either linked to itself (not linked) or linked to + * other elements in a list (linked). + */ + return l->prev != l; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_LinkFirst -- + * + * Insert 'l' at the beginning of the list anchored at 'head' + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +DblLnkLst_LinkFirst(DblLnkLst_Links *head, // IN + DblLnkLst_Links *l) // IN +{ + ASSERT(head); + ASSERT(l); + + DblLnkLst_Link(head->next, l); +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_LinkLast -- + * + * Insert 'l' at the end of the list anchored at 'head' + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +DblLnkLst_LinkLast(DblLnkLst_Links *head, // IN + DblLnkLst_Links *l) // IN +{ + ASSERT(head); + ASSERT(l); + + DblLnkLst_Link(head, l); +} + + +#if 0 +/* + * Test code (which also demonstrates how to use this library) + */ + +/* + * Add the double linked list capability to any of your data structure just by + * adding a DblLnkLst_Links field inside it. It is not required that the field + * comes first, but if it does, the execution will be slighly faster. + * + * Here we create a doubly linked list of integers + */ + +#include +#include + +typedef struct member { + int i; + DblLnkLst_Links l; +} member; + + +/* Member constructor */ +member * +make_member(int i) +{ + member *m; + + m = malloc(sizeof(*m)); + DblLnkLst_Init(&m->l); + m->i = i; + + return m; +} + + +/* Dump a circular list */ +void +dump_circular(const member *c) // IN +{ + const member *current; + + printf("forward: "); + current = c; + do { + printf("%d ", current->i); + current = DblLnkLst_Container(current->l.next, member, l); + } while (current != c); + printf("backward: "); + do { + printf("%d ", current->i); + current = DblLnkLst_Container(current->l.prev, member, l); + } while (current != c); + printf("\n"); +} + + +/* Dump an anchored list */ +void +dump_anchored(const DblLnkLst_Links *h) // IN +{ + DblLnkLst_Links *cur_l; + + printf("forward: "); + for (cur_l = h->next; cur_l != h; cur_l = cur_l->next) { + member *current; + + current = DblLnkLst_Container(cur_l, member, l); + printf("%d ", current->i); + } + printf("backward: "); + for (cur_l = h->prev; cur_l != h; cur_l = cur_l->prev) { + member *current; + + current = DblLnkLst_Container(cur_l, member, l); + printf("%d ", current->i); + } + printf("\n"); +} + + +/* Test code entry point */ +int +main(int argc, // IN + char **argv) // IN +{ + member *c1; + member *c2; + member *c3; + member *c4; + + DblLnkLst_Links h; + member *a1; + member *a2; + member *a3; + + printf("Circular list: there is no origin\n"); + + /* Create the 1st member */ + c1 = make_member(1); + /* Special case: there is no list to merge with, initially */ + + /* Add the 2nd member _after_ the 1st one */ + c2 = make_member(2); + DblLnkLst_Link(&c1->l, &c2->l); + + /* Add the 3rd member _after_ the 2nd one */ + c3 = make_member(3); + DblLnkLst_Link(&c1->l, &c3->l); + + /* Add the 4th member _before_ the 3rd one */ + c4 = make_member(4); + DblLnkLst_Link(&c3->l, &c4->l); + + printf("See it from this member...\n"); + dump_circular(c1); + printf("...Or from this one\n"); + dump_circular(c4); + + printf("\n"); + printf("Anchored (linear) list: it has a beginning and an end\n"); + + /* Create the 'head' of the list */ + DblLnkLst_Init(&h); + + /* Add the 1st member at the _end_ */ + a1 = make_member(5); + DblLnkLst_LinkLast(&h, &a1->l); + + /* Add the 2nd member at the _beginning_ */ + a2 = make_member(6); + DblLnkLst_LinkFirst(&h, &a2->l); + + /* Add the 3rd member _before_ the 1st one */ + a3 = make_member(7); + DblLnkLst_Link(&a1->l, &a3->l); + + dump_anchored(&h); + + printf("\n"); + printf("Merge both lists: the result is an anchored list\n"); + + DblLnkLst_Link(&h, &c4->l); + + dump_anchored(&h); + + printf("\n"); + printf("Remove a member\n"); + + DblLnkLst_Unlink1(&c3->l); + + dump_anchored(&h); + + printf("\n"); + printf("Split the result in two lists: an anchored one and a circular " + "one\n"); + DblLnkLst_Unlink(&h, &a1->l); + + dump_anchored(&h); + dump_circular(a1); + + return 0; +} +#endif --- /dev/null +++ b/drivers/vmware/vmblock/dbllnklst.h @@ -0,0 +1,69 @@ +/********************************************************* + * Copyright (C) 1998 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * dbllnklst.h -- + * + * Double linked lists + */ + +#ifndef _DBLLNKLST_H_ +#define _DBLLNKLST_H_ + +#include "vm_basic_types.h" + +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_USERLEVEL +//#include "includeCheck.h" + + +#define DblLnkLst_OffsetOf(type, field) ((intptr_t)&((type *)0)->field) + +#define DblLnkLst_Container(addr, type, field) \ + ((type *)((char *)addr - DblLnkLst_OffsetOf(type, field))) + +#define DblLnkLst_ForEach(curr, head) \ + for (curr = (head)->next; curr != (head); curr = (curr)->next) + +/* Safe from list element removal within loop body. */ +#define DblLnkLst_ForEachSafe(curr, nextElem, head) \ + for (curr = (head)->next, nextElem = (curr)->next; \ + curr != (head); \ + curr = nextElem, nextElem = (curr)->next) + +typedef struct DblLnkLst_Links { + struct DblLnkLst_Links *prev; + struct DblLnkLst_Links *next; +} DblLnkLst_Links; + + +/* Functions for both circular and anchored lists. --hpreg */ + +void DblLnkLst_Init(DblLnkLst_Links *l); +void DblLnkLst_Link(DblLnkLst_Links *l1, DblLnkLst_Links *l2); +void DblLnkLst_Unlink(DblLnkLst_Links *l1, DblLnkLst_Links *l2); +void DblLnkLst_Unlink1(DblLnkLst_Links *l); +Bool DblLnkLst_IsLinked(DblLnkLst_Links const *l); + +/* Functions specific to anchored lists. --hpreg */ + +void DblLnkLst_LinkFirst(DblLnkLst_Links *head, DblLnkLst_Links *l); +void DblLnkLst_LinkLast(DblLnkLst_Links *head, DblLnkLst_Links *l); + + +#endif /* _DBLLNKLST_H_ */ --- /dev/null +++ b/drivers/vmware/vmblock/dentry.c @@ -0,0 +1,122 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * dentry.c -- + * + * Dentry operations for the file system of the vmblock driver. + * + */ + +#include "driver-config.h" +#include "compat_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, +}; + + +/* + *---------------------------------------------------------------------------- + * + * DentryOpRevalidate -- + * + * This function is invoked every time the dentry is accessed from the cache + * to ensure it is still valid. We use it to block since any threads + * looking up this dentry after the initial lookup should still block if the + * block has not been cleared. + * + * Results: + * 1 if the dentry is valid, 0 if it is not. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +#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; + struct dentry *actualDentry; + int ret; + + if (!dentry || !dentry->d_inode) { + Warning("DentryOpRevalidate: invalid args from kernel\n"); + return 0; + } + + iinfo = INODE_TO_IINFO(dentry->d_inode); + if (!iinfo) { + Warning("DentryOpRevalidate: dentry has no fs-specific data\n"); + return 0; + } + + /* Block if there is a pending block on this file */ + BlockWaitOnFile(iinfo->name, NULL); + + /* + * If the actual dentry has a revalidate function, we'll let it figure out + * whether the dentry is still valid. If not, do a path lookup to ensure + * that the file still exists. + */ + actualDentry = iinfo->actualDentry; + + if (actualDentry && + actualDentry->d_op && + actualDentry->d_op->d_revalidate) { +#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)) { + LOG(4, "DentryOpRevalidate: [%s] no longer exists\n", iinfo->name); + return 0; + } + ret = compat_vmw_nd_to_dentry(actualNd) && + compat_vmw_nd_to_dentry(actualNd)->d_inode; + compat_path_release(&actualNd); + + LOG(8, "DentryOpRevalidate: [%s] %s revalidated\n", + iinfo->name, ret ? "" : "not"); + return ret; +} --- /dev/null +++ b/drivers/vmware/vmblock/driver-config.h @@ -0,0 +1,78 @@ +/********************************************************* + * Copyright (C) 1998 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * Sets the proper defines from the Linux header files + * + * This file must be included before the inclusion of any kernel header file, + * with the exception of linux/autoconf.h and linux/version.h --hpreg + */ + +#ifndef __VMX_CONFIG_H__ +#define __VMX_CONFIG_H__ + +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMNIXMOD +//#include "includeCheck.h" + +#include +#include "compat_version.h" + +/* + * We rely on Kernel Module support. Check here. + */ +#ifndef CONFIG_MODULES +# error "No Module support in this kernel. Please configure with CONFIG_MODULES" +#endif + +/* + * 2.2 kernels still use __SMP__ (derived from CONFIG_SMP + * in the main Makefile), so we do it here. + */ + +#ifdef CONFIG_SMP +# define __SMP__ 1 +#endif + +#if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) +/* + * MODVERSIONS might be already defined when using kernel's Makefiles. + */ +# ifndef MODVERSIONS +# define MODVERSIONS +# endif +# include +# endif +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +/* + * Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h. + */ +# include +# define _STDINT_H 1 +#endif + +#ifndef __KERNEL__ +# define __KERNEL__ +#endif + +#endif --- /dev/null +++ b/drivers/vmware/vmblock/file.c @@ -0,0 +1,274 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * file.c -- + * + * File operations for the file system of the vmblock driver. + * + */ + +#include "driver-config.h" +#include +#include "compat_fs.h" +#include "compat_sched.h" + +#include "vmblockInt.h" +#include "filesystem.h" + +/* Specifically for our filldir_t callback */ +typedef struct FilldirInfo { + filldir_t filldir; + void *dirent; +} FilldirInfo; + +/* File operations */ +static int FileOpOpen(struct inode *inode, struct file *file); +static int FileOpReaddir(struct file *file, void *dirent, filldir_t filldir); +static int FileOpRelease(struct inode *inode, struct file *file); + +/* Local functions */ +#if defined(VMW_FILLDIR_2618) +static int Filldir(void *buf, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 9) +static int Filldir(void *buf, const char *name, int namelen, + loff_t offset, ino_t ino, unsigned int d_type); +#else +static int Filldir(void *buf, const char *name, int namelen, + off_t offset, ino_t ino, unsigned int d_type); +#endif + +struct file_operations RootFileOps = { + .readdir = FileOpReaddir, + .open = FileOpOpen, + .release = FileOpRelease, +}; + + +/* File operations */ + +/* + *---------------------------------------------------------------------------- + * + * FileOpOpen -- + * + * Invoked when open(2) has been called on our root inode. We get an open + * file instance of the actual file that we are providing indirect access + * to. + * + * Results: + * 0 on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +FileOpOpen(struct inode *inode, // IN + struct file *file) // IN +{ + VMBlockInodeInfo *iinfo; + struct file *actualFile; + + if (!inode || !file || !INODE_TO_IINFO(inode)) { + Warning("FileOpOpen: invalid args from kernel\n"); + return -EINVAL; + } + + iinfo = INODE_TO_IINFO(inode); + + /* + * Get an open file for the directory we are redirecting to. This ensure we + * can gracefully handle cases where that directory is removed after we are + * mounted. + */ + actualFile = filp_open(iinfo->name, file->f_flags, file->f_flags); + if (IS_ERR(actualFile)) { + Warning("FileOpOpen: could not open file [%s]\n", iinfo->name); + file->private_data = NULL; + return PTR_ERR(actualFile); + } + + /* + * If the file opened is the same as the one retrieved for the file then we + * shouldn't allow the open to happen. This can only occur if the + * redirected root directory specified at mount time is the same as where + * the mount is placed. Later in FileOpReaddir() we'd call vfs_readdir() + * and that would try to acquire the inode's semaphore; if the two inodes + * are the same we'll deadlock. + */ + if (actualFile->f_dentry && inode == actualFile->f_dentry->d_inode) { + Warning("FileOpOpen: identical inode encountered, open cannot succeed.\n"); + if (filp_close(actualFile, current->files) < 0) { + Warning("FileOpOpen: unable to close opened file.\n"); + } + return -EINVAL; + } + + file->private_data = actualFile; + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * FileOpReaddir -- + * + * Invoked when a user invokes getdents(2) or readdir(2) on the root of our + * file system. We perform a readdir on the actual underlying file but + * interpose the callback by providing our own Filldir() function. This + * enables us to change dentry types to symlinks. + * + * Results: + * 0 on success, negative error code on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +FileOpReaddir(struct file *file, // IN + void *dirent, // IN + filldir_t filldir) // IN +{ + int ret; + FilldirInfo info; + struct file *actualFile; + + if (!file) { + Warning("FileOpReaddir: invalid args from kernel\n"); + return -EINVAL; + } + + actualFile = file->private_data; + if (!actualFile) { + Warning("FileOpReaddir: no actual file found\n"); + return -EINVAL; + } + + info.filldir = filldir; + info.dirent = dirent; + + actualFile->f_pos = file->f_pos; + ret = vfs_readdir(actualFile, Filldir, &info); + file->f_pos = actualFile->f_pos; + + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * FileOpRelease -- + * + * Invoked when a user close(2)s the root of our file system. Here we just + * close the actual file we opened in FileOpOpen(). + * + * Results: + * 0 on success, negative value on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +FileOpRelease(struct inode *inode, // IN + struct file *file) // IN +{ + int ret; + struct file *actualFile; + + if (!inode || !file) { + Warning("FileOpRelease: invalid args from kerel\n"); + return -EINVAL; + } + + actualFile = file->private_data; + if (!actualFile) { + Warning("FileOpRelease: no actual file found\n"); + return -EINVAL; + } + + ret = filp_close(actualFile, current->files); + + return ret; +} + + +/* Local functions */ + +/* + *---------------------------------------------------------------------------- + * + * Filldir -- + * + * Callback function for readdir that we use in place of the one provided. + * This allows us to specify that each dentry is a symlink, but pass through + * everything else to the original filldir function. + * + * Results: + * Original filldir's return value. + * + * Side effects: + * Directory information gets copied to user's buffer. + * + *---------------------------------------------------------------------------- + */ + +#if defined(VMW_FILLDIR_2618) +static int +Filldir(void *buf, // IN: Dirent buffer passed from FileOpReaddir + const char *name, // IN: Dirent name + int namelen, // IN: len of dirent's name + loff_t offset, // IN: Offset + u64 ino, // IN: Inode number of dirent + unsigned int d_type) // IN: Type of file +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 9) +static int +Filldir(void *buf, // IN: Dirent buffer passed from FileOpReaddir + const char *name, // IN: Dirent name + int namelen, // IN: len of dirent's name + loff_t offset, // IN: Offset + ino_t ino, // IN: Inode number of dirent + unsigned int d_type) // IN: Type of file +#else +static int +Filldir(void *buf, // IN: Dirent buffer passed from FileOpReaddir + const char *name, // IN: Dirent name + int namelen, // IN: len of dirent's name + off_t offset, // IN: Offset + ino_t ino, // IN: Inode number of dirent + unsigned int d_type) // IN: Type of file +#endif +{ + FilldirInfo *info = (FilldirInfo *)buf; + + /* Specify DT_LNK regardless */ + return info->filldir(info->dirent, name, namelen, offset, ino, DT_LNK); +} + + --- /dev/null +++ b/drivers/vmware/vmblock/filesystem.c @@ -0,0 +1,618 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * filesystem.c -- + * + * File system for the vmblock driver. + * + */ + +#include "driver-config.h" +#include "compat_kernel.h" +#include +#include +#include +#include "compat_fs.h" +#include "compat_spinlock.h" +#include "compat_namei.h" +#include "compat_slab.h" + +#include "os.h" +#include "vmblockInt.h" +#include "filesystem.h" + +#define VMBLOCK_ROOT_INO 1 +#define GetRootInode(sb) Iget(sb, NULL, NULL, VMBLOCK_ROOT_INO) + +#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 */ +static int FsOpGetSb(struct file_system_type *fsType, int flags, + const char *devName, void *rawData, struct vfsmount *mnt); +static int FsOpReadSuper(struct super_block *sb, void *rawData, int flags); + + +/* Utility */ +static compat_kmem_cache_ctor InodeCacheCtor; + + +/* Variables */ +compat_kmem_cache *VMBlockInodeCache; + +/* Local variables */ +static char const *fsRoot; +static size_t fsRootLen; +static struct file_system_type fsType = { + .owner = THIS_MODULE, + .name = VMBLOCK_FS_NAME, +#if KERNEL_25_FS + .get_sb = FsOpGetSb, + .kill_sb = kill_anon_super, +#else + .read_super = FsOpReadSuper24, +#endif +}; + + +/* + * Public functions (with respect to the module) + */ + +/* + *---------------------------------------------------------------------------- + * + * VMBlockInitFileSystem -- + * + * Initializes the file system and registers it with the kernel. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +VMBlockInitFileSystem(char const *root) // IN: directory redirecting to +{ + int ret; + + if (!root) { + Warning("VMBlockInitFileSystem: root not provided " + "(missing module parameter?)\n"); + return -EINVAL; + } + + /* + * Here we assume that the provided root is valid so the module will load. + * The mount operation will fail if that is not the case. + */ + fsRoot = root; + fsRootLen = strlen(fsRoot); + + if (fsRootLen >= PATH_MAX) { + return -ENAMETOOLONG; + } + + /* Initialize our inode slab allocator */ + VMBlockInodeCache = os_kmem_cache_create("VMBlockInodeCache", + sizeof (VMBlockInodeInfo), + 0, + InodeCacheCtor); + if (!VMBlockInodeCache) { + Warning("VMBlockInitFileSystem: could not initialize inode cache\n"); + return -ENOMEM; + } + + /* Tell the kernel about our file system */ + ret = register_filesystem(&fsType); + if (ret < 0) { + Warning("VMBlockInitFileSystem: could not initialize file system\n"); + kmem_cache_destroy(VMBlockInodeCache); + return ret; + } + + LOG(4, "file system registered with root of [%s]\n", fsRoot); + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMBlockCleanupFileSystem -- + * + * Cleans up file system and unregisters it with the kernel. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +VMBlockCleanupFileSystem(void) +{ + int ret; + + kmem_cache_destroy(VMBlockInodeCache); + + ret = unregister_filesystem(&fsType); + if (ret < 0) { + Warning("VMBlockCleanupFileSystem: could not unregister file system\n"); + return ret; + } + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMBlockReadInode -- + * + * A filesystem wide function that is called to initialize a new inode. + * This is called from two different places depending on the kernel version. + * In older kernels that provide the iget() interface, this function is + * called by the kernel as part of inode initialization (from + * SuperOpReadInode). In newer kernels that call iget_locked(), this + * function is called by filesystem code to initialize the new inode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +void +VMBlockReadInode(struct inode *inode) // IN: Inode to initialize +{ + VMBlockInodeInfo *iinfo = INODE_TO_IINFO(inode); + + iinfo->name[0] = '\0'; + iinfo->nameLen = 0; + iinfo->actualDentry = NULL; +} + + +/* + *---------------------------------------------------------------------------- + * + * GetNextIno -- + * + * Gets the next available inode number. + * + * Results: + * The next available inode number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +ino_t +GetNextIno(void) +{ + static spinlock_t inoLock = SPIN_LOCK_UNLOCKED; + static ino_t nextIno = VMBLOCK_ROOT_INO + 1; + ino_t ret; + + /* Too bad atomic_t's don't provide an atomic increment and read ... */ + spin_lock(&inoLock); + ret = nextIno++; + spin_unlock(&inoLock); + + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * GetInode -- + * + * This function replaces iget() and should be called instead of it. In newer + * kernels that have removed the iget() interface, GetInode() obtains an inode + * and if it is a new one, then initializes the inode by calling + * VMBlockReadInode(). In older kernels that support the iget() interface, + * VMBlockReadInode() is called by iget() internally by the superblock function + * SuperOpReadInode. + * + * Results: + * A new inode object on success, NULL on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static struct inode * +GetInode(struct super_block *sb, // IN: file system superblock object + ino_t ino) // IN: inode number to assign to new inode +{ +#ifdef VMW_USE_IGET_LOCKED + struct inode *inode; + + inode = iget_locked(sb, ino); + if (!inode) { + return NULL; + } else if (inode->i_state & I_NEW) { + VMBlockReadInode(inode); + unlock_new_inode(inode); + } + return inode; +#else + return iget(sb, ino); +#endif +} + + +/* + *---------------------------------------------------------------------------- + * + * Iget -- + * + * Lookup or create a new inode. + * + * Inode creation in detail: + * Throughout the file system, we call the VFS iget() function to get a new + * inode. This in turn invokes our file system's SuperOpAllocInode() + * function, which allocates an inode info structure (VMBlockInodeInfo) + * using the kernel's slab allocator. When a new slab is created, each + * object is initialized with the constructor (InodeCacheCtor()), but that + * occurs only once per struct (e.g., when a struct from a slab is freed and + * reused, the constructor is not invoked again). SuperOpAllocInode() then + * returns the address of the inode struct that is embedded within the inode + * info we have allocated. iget() also invokes our SuperOpReadInode() + * function to do any further file system wide initialization to the inode, + * then returns the inode to us (this function). + * + * Note that in older kernels that don't have the alloc_inode operation + * (where VMW_EMBED_INODE is undefined), the allocation is delayed until + * this function and is contained within the INODE_TO_IINFO macro. That + * allocation is freed in the SuperOpClearInode() function. + * + * This function then constructs the full path of the actual file name and + * does a path_lookup() to see if it exists. If it does, we save a pointer + * to the actual dentry within our inode info for future use. If it + * doesn't, we still provide an inode but indicate that it doesn't exist by + * setting the actual dentry to NULL. Callers that need to handle this case + * differently check for the existence of the actual dentry (and actual + * inode) to ensure the actual file exists. + * + * Results: + * A new inode object on success, NULL on error. + * + * Side effects: + * A path lookup is done for the actual file. + * + *---------------------------------------------------------------------------- + */ + +struct inode * +Iget(struct super_block *sb, // IN: file system superblock object + struct inode *dir, // IN: containing directory + struct dentry *dentry, // IN: dentry within directory + ino_t ino) // IN: inode number to assign to new inode +{ + VMBlockInodeInfo *iinfo; + struct inode *inode; + struct nameidata actualNd; + + ASSERT(sb); + + inode = GetInode(sb, ino); + if (!inode) { + return NULL; + } + + iinfo = INODE_TO_IINFO(inode); + if (!iinfo) { + Warning("Iget: invalid inode provided, or unable to allocate inode info\n"); + goto error_inode; + } + + /* Populate iinfo->name with the full path of the target file */ + if (MakeFullName(dir, dentry, iinfo->name, sizeof iinfo->name) < 0) { + Warning("Iget: could not make full name\n"); + goto error_inode; + } + + if (compat_path_lookup(iinfo->name, 0, &actualNd)) { + /* + * This file does not exist, so we create an inode that doesn't know + * about its underlying file. Operations that create files and + * directories need an inode to operate on even if there is no actual + * file yet. + */ + iinfo->actualDentry = NULL; + return inode; + } + + iinfo->actualDentry = compat_vmw_nd_to_dentry(actualNd); + compat_path_release(&actualNd); + + return inode; + +error_inode: + iput(inode); + return NULL; +} + + +/* + *---------------------------------------------------------------------------- + * + * InodeCacheCtor -- + * + * The constructor for inode info structs that occurs once at slab + * allocation. That is, this is called once for each piece of memory that + * is used to satisfy inode info allocations; it should only be used to + * initialized items that will naturally return to their initialized state + * before deallocation (such as locks, list_heads). + * + * We only invoke the inode's initialization routine since all of the inode + * info members need to be initialized on each allocation (in + * SuperOpReadInode()). + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +#ifdef VMW_KMEMCR_CTOR_HAS_3_ARGS +static void +InodeCacheCtor(void *slabElem, // IN: allocated slab item to initialize + compat_kmem_cache *cache, // IN: cache slab is from + unsigned long flags) // IN: flags associated with allocation +#else +static void +InodeCacheCtor(compat_kmem_cache *cache, // IN: cache slab is from + void *slabElem) // IN: allocated slab item to initialize +#endif +{ +#ifdef VMW_EMBED_INODE + VMBlockInodeInfo *iinfo = (VMBlockInodeInfo *)slabElem; + + inode_init_once(&iinfo->inode); +#endif +} + + +/* + *---------------------------------------------------------------------------- + * + * MakeFullName -- + * + * Constructs the full filename from the provided directory and a dentry + * contained within it. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +MakeFullName(struct inode *dir, // IN : directory + struct dentry *dentry, // IN : dentry in that directory + char *bufOut, // OUT: output buffer + size_t bufOutSize) // IN : size of output buffer +{ + ASSERT(bufOut); + + /* + * If dir is supplied, contruct the full path of the actual file, otherwise + * it's the root directory. + */ + if (dir == NULL) { + if (fsRootLen >= bufOutSize) { + Warning("MakeFullName: root path was too long.\n"); + return -ENAMETOOLONG; + } + memcpy(bufOut, fsRoot, fsRootLen); + bufOut[fsRootLen] = '\0'; + } else { + VMBlockInodeInfo *dirIinfo; + + ASSERT(dir); + ASSERT(dentry); + + if (!dentry->d_name.name) { + Warning("MakeFullName: dentry name is empty\n"); + return -EINVAL; + } + + dirIinfo = INODE_TO_IINFO(dir); + /* + * If dirIinfo->name[1] is '\0', then it is "/" and we don't need + * another '/' between it and the additional name. + */ +#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'; + } +#endif + } + + return 0; +} + + +/* File system operations */ + +/* + *----------------------------------------------------------------------------- + * + * FsOpReadSuper -- + * + * The main entry point of the filesystem side of the driver. Called when + * a userland process does a mount(2) of an hgfs filesystem. This makes the + * whole driver transition from its initial state to state 1. Fill the + * content of the uninitialized superblock provided by the kernel. + * + * 'rawData' is a pointer (that can be NULL) to a kernel buffer (whose + * size is <= PAGE_SIZE) that corresponds to the filesystem-specific 'data' + * argument passed to mount(2). + * + * Results: + * zero and initialized superblock on success + * negative value on failure + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static int +FsOpReadSuper(struct super_block *sb, // OUT: Superblock object + void *rawData, // IN: Fs-specific mount data + int flags) // IN: Mount flags +{ + struct inode *rootInode; + struct dentry *rootDentry; + + if (!sb) { + Warning("FsOpReadSuper: invalid arg from kernel\n"); + return -EINVAL; + } + + sb->s_magic = VMBLOCK_SUPER_MAGIC; + sb->s_blocksize = 1024; + sb->s_op = &VMBlockSuperOps; + + /* + * Make root inode and dentry. Ensure that the directory we are redirecting + * to has an actual dentry and inode, and that it is in fact a directory. + */ + rootInode = GetRootInode(sb); + if (!rootInode) { + return -EINVAL; + } + + if (!INODE_TO_IINFO(rootInode) || + !INODE_TO_ACTUALDENTRY(rootInode) || + !INODE_TO_ACTUALINODE(rootInode) || + !S_ISDIR(INODE_TO_ACTUALINODE(rootInode)->i_mode)) { + iput(rootInode); + return -EINVAL; + } + + rootDentry = d_alloc_root(rootInode); + if (!rootDentry) { + iput(rootInode); + return -ENOMEM; + } + sb->s_root = rootDentry; + + rootInode->i_op = &RootInodeOps; + rootInode->i_fop = &RootFileOps; + rootInode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + + LOG(4, "%s file system mounted\n", VMBLOCK_FS_NAME); + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * FsOpGetSb -- + * + * Invokes generic kernel code to prepare superblock for + * deviceless filesystem. + * + * Results: + * 0 on success + * negative error code on failure + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static int +FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount + int flags, // IN: mount flags + const char *dev_name, // IN: device mounting on + void *rawData, // IN: mount arguments + struct vfsmount *mnt) // IN: vfs mount +{ + return get_sb_nodev(fs_type, flags, rawData, FsOpReadSuper, mnt); +} + --- /dev/null +++ b/drivers/vmware/vmblock/filesystem.h @@ -0,0 +1,111 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * filesystem.h -- + * + * Definitions and prototypes for file system portion of vmblock driver. + * + * There are currently two classes of files in the blocking file system: the + * root directory and symlinks to actual files on the file system. The root + * directory provides a way to lookup directory entries in the directory we + * are redirecting to; each of these directory entries is presented as + * a symlink. These symlinks within the root directory contain the path of + * the actual file and will block any time the inode is accessed or dentry is + * revalidated (if there is a pending block). This blocking ensures that any + * access to the file through the symlink will not proceed until the block is + * lifted. + * + * Operation tables for the root directory and symlinks are are named Root*Ops + * and Link*Ops respectively. All operations are preceded by their operation + * type (e.g., the file_operation table's open is named FileOpOpen and the + * inode_operation table's lookup is named InodeOpLookup). + * + * The use of symlinks greatly simplifies the driver's implementation but also + * limits blocking to a depth of one level within the redirected directory + * (since after the symlink is followed all operations are passed on to the + * actual file system and are out of our control). This limitation is fine + * under the current use of this driver. + */ + +#ifndef __FILESYSTEM_H__ +#define __FILESYSTEM_H__ + +#include "compat_slab.h" +#include "compat_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_ACTUALDENTRY(inode) INODE_TO_IINFO(inode)->actualDentry +#define INODE_TO_ACTUALINODE(inode) INODE_TO_IINFO(inode)->actualDentry->d_inode + +#define VMBLOCK_SUPER_MAGIC 0xabababab + +typedef struct VMBlockInodeInfo { + char name[PATH_MAX]; + size_t nameLen; + struct dentry *actualDentry; +#ifdef VMW_EMBED_INODE + /* Embedded inode */ + struct inode inode; +#endif +} VMBlockInodeInfo; + + +ino_t GetNextIno(void); +struct inode *Iget(struct super_block *sb, struct inode *dir, + struct dentry *dentry, ino_t ino); +int MakeFullName(struct inode *dir, struct dentry *dentry, + char *bufOut, size_t bufOutSize); +void VMBlockReadInode(struct inode *inode); + +/* Variables */ +extern compat_kmem_cache *VMBlockInodeCache; +/* File system wide superblock operations */ +extern struct super_operations VMBlockSuperOps; +/* File operations on fs's root inode to read directory entries. */ +extern struct file_operations RootFileOps; +/* Inode operations to lookup inodes of directory entries in fs's root inode. */ +extern struct inode_operations RootInodeOps; +/* Dentry operations for our symlinks to actual files (to enable blocking). */ +extern struct dentry_operations LinkDentryOps; + +#endif /* __FILESYSTEM_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/inode.c @@ -0,0 +1,244 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * inode.c -- + * + * Inode operations for the file system of the vmblock driver. + * + */ + +#include "driver-config.h" +#include +#include "compat_fs.h" +#include +#include "compat_namei.h" +#include "compat_uaccess.h" +#include "compat_sched.h" + +#include "vmblockInt.h" +#include "filesystem.h" +#include "block.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); +#else +static int InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd); +#endif + + +struct inode_operations RootInodeOps = { + .lookup = InodeOpLookup, +}; + +static struct inode_operations LinkInodeOps = { + .readlink = InodeOpReadlink, + .follow_link = InodeOpFollowlink, +}; + + +/* + *---------------------------------------------------------------------------- + * + * InodeOpLookup -- + * + * Looks up a name (dentry) in provided directory. Invoked every time + * a directory entry is traversed in path lookups. + * + * Results: + * NULL on success, negative error code on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +#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; + int ret; + + if (!dir || !dentry) { + Warning("InodeOpLookup: invalid args from kernel\n"); + return ERR_PTR(-EINVAL); + } + + /* The kernel should only pass us our own inodes, but check just to be safe. */ + if (!INODE_TO_IINFO(dir)) { + Warning("InodeOpLookup: invalid inode provided\n"); + return ERR_PTR(-EINVAL); + } + + /* Get a slab from the kernel's names_cache of PATH_MAX-sized buffers. */ + filename = compat___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); + return ERR_PTR(ret); + } + + /* Block if there is a pending block on this file */ + BlockWaitOnFile(filename, NULL); + compat___putname(filename); + + inode = Iget(dir->i_sb, dir, dentry, GetNextIno()); + if (!inode) { + Warning("InodeOpLookup: failed to get inode\n"); + return ERR_PTR(-ENOMEM); + } + + dentry->d_op = &LinkDentryOps; + dentry->d_time = jiffies; + + /* + * If the actual file's dentry doesn't have an inode, it means the file we + * are redirecting to doesn't exist. Give back the inode that was created + * for this and add a NULL dentry->inode entry in the dcache. (The NULL + * entry is added so ops to create files/directories are invoked by VFS.) + */ + if (!INODE_TO_ACTUALDENTRY(inode) || !INODE_TO_ACTUALINODE(inode)) { + iput(inode); + d_add(dentry, NULL); + return NULL; + } + + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_size = INODE_TO_IINFO(inode)->nameLen; + inode->i_version = 1; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_uid = inode->i_gid = 0; + inode->i_op = &LinkInodeOps; + + d_add(dentry, inode); + return NULL; +} + + +/* + *---------------------------------------------------------------------------- + * + * InodeOpReadlink -- + * + * Provides the symbolic link's contents to the user. Invoked when + * readlink(2) is invoked on our symlinks. + * + * Results: + * 0 on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +InodeOpReadlink(struct dentry *dentry, // IN : dentry of symlink + char __user *buffer, // OUT: output buffer (user space) + int buflen) // IN : length of output buffer +{ + VMBlockInodeInfo *iinfo; + + if (!dentry || !buffer) { + Warning("InodeOpReadlink: invalid args from kernel\n"); + return -EINVAL; + } + + iinfo = INODE_TO_IINFO(dentry->d_inode); + if (!iinfo) { + return -EINVAL; + } + + return vfs_readlink(dentry, buffer, buflen, iinfo->name); +} + + +/* + *---------------------------------------------------------------------------- + * + * InodeOpFollowlink -- + * + * Provides the inode corresponding to this symlink through the nameidata + * structure. + * + * Results: + * 0 on success, negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) +static void * +#else +static int +#endif +InodeOpFollowlink(struct dentry *dentry, // IN : dentry of symlink + struct nameidata *nd) // OUT: stores result +{ + int ret; + VMBlockInodeInfo *iinfo; + + if (!dentry) { + Warning("InodeOpReadlink: invalid args from kernel\n"); + ret = -EINVAL; + goto out; + } + + iinfo = INODE_TO_IINFO(dentry->d_inode); + if (!iinfo) { + ret = -EINVAL; + goto out; + } + + ret = vfs_follow_link(nd, iinfo->name); + +out: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) + return ERR_PTR(ret); +#else + return ret; +#endif +} --- /dev/null +++ b/drivers/vmware/vmblock/Makefile @@ -0,0 +1,13 @@ +obj-$(CONFIG_VMWARE_BLOCK) := vmblock.o + +vmblock-y := module.o \ + control.o \ + filesystem.o \ + super.o \ + file.o \ + inode.o \ + dentry.o \ + block.o \ + stubs.o \ + dbllnklst.o + --- /dev/null +++ b/drivers/vmware/vmblock/module.c @@ -0,0 +1,175 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * module.c -- + * + * Module loading/unloading functions. + * + */ + +#include "driver-config.h" +#include "compat_init.h" +#include "compat_kernel.h" +#include "compat_module.h" +#include +#include +#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_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_AUTHOR("VMware, Inc."); +MODULE_DESCRIPTION("VMware Blocking File System"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(VMBLOCK_DRIVER_VERSION_STRING); + +/* Functions */ +static int VMBlockInit(void); +static void VMBlockExit(void); + +/* Define init/exit routines */ +module_init(VMBlockInit); +module_exit(VMBlockExit); + + +/* + *---------------------------------------------------------------------------- + * + * VMBlockInit -- + * + * Module entry point and initialization. + * + * Results: + * Zero on success, negative value on failure. + * + * Side effects: + * /proc entries are available and file system is registered with kernel and + * ready to be mounted. + * + *---------------------------------------------------------------------------- + */ + +static int +VMBlockInit(void) +{ + int ret; + + ret = VMBlockInitControlOps(); + if (ret < 0) { + goto error; + } + + ret = VMBlockInitFileSystem(root); + if (ret < 0) { + VMBlockCleanupControlOps(); + goto error; + } + + LOG(4, "module loaded\n"); + return 0; + +error: + Warning("VMBlock: could not initialize module\n"); + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMBlockExit -- + * + * Unloads module from kernel and removes associated state. + * + * Results: + * None. + * + * Side effects: + * Opposite of VMBlockInit(): /proc entries go away and file system is + * unregistered. + * + *---------------------------------------------------------------------------- + */ + +static void +VMBlockExit(void) +{ + VMBlockCleanupControlOps(); + VMBlockCleanupFileSystem(); + + LOG(4, "module unloaded\n"); +} + + +#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 --- /dev/null +++ b/drivers/vmware/vmblock/os.h @@ -0,0 +1,117 @@ +/********************************************************* + * Copyright (C) 2007 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + + +/* + * os.h -- + * + * OS-specific definitions. + */ + + +#ifndef __OS_H__ +#define __OS_H__ + +#include "driver-config.h" +#include "compat_list.h" +#include "compat_completion.h" +#include +#include "compat_slab.h" +#include "compat_wait.h" +#include +#include +#include "compat_sched.h" +#include +#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 atomic_t os_atomic_t; +typedef struct file * os_blocker_id_t; + +#define OS_UNKNOWN_BLOCKER NULL +#define OS_ENOMEM -ENOMEM +#define OS_ENOENT -ENOENT +#define OS_EEXIST -EEXIST +#define OS_PATH_MAX PATH_MAX + +#define OS_FMTTID "d" +#define os_threadid current->pid +/* + * 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) \ + ({ \ + 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) +/* + * XXX We'd like to check for kernel version 2.5.34 as the patches indicate, + * but SLES10's 2.6.16.21-0.8-i586default doesn't seem to have this defined. + */ +#if defined(rwlock_is_locked) +# define os_rwlock_held(lock) rwlock_is_locked(lock) +#else +/* XXX Is there something we can come up with for this? */ +# define os_rwlock_held(lock) TRUE +#endif +#define os_read_lock(lock) read_lock(lock) +#define os_write_lock(lock) write_lock(lock) +#define os_read_unlock(lock) read_unlock(lock) +#define os_write_unlock(lock) write_unlock(lock) + +#define os_kmem_cache_create(name, size, align, ctor) \ + compat_kmem_cache_create(name, size, align, SLAB_HWCACHE_ALIGN, ctor) +#define os_kmem_cache_destroy(cache) kmem_cache_destroy(cache) +#define os_kmem_cache_alloc(cache) kmem_cache_alloc(cache, GFP_KERNEL) +#define os_kmem_cache_free(cache, elem) kmem_cache_free(cache, elem) + +#define os_completion_init(comp) compat_init_completion(comp) +#define os_completion_destroy(comp) +/* + * XXX This should be made interruptible using + * wait_for_completion_interruptible(), and return a proper value. Callers + * would need to handle interruption, of course. + */ +#define os_wait_for_completion(comp) \ +({ \ + compat_wait_for_completion(comp); \ + 0; \ + }) +#define os_complete_all(comp) compat_complete_all(comp) + +#define os_atomic_dec_and_test(atomic) atomic_dec_and_test(atomic) +#define os_atomic_dec(atomic) atomic_dec(atomic) +#define os_atomic_set(atomic, val) atomic_set(atomic, val) +#define os_atomic_inc(atomic) atomic_inc(atomic) +#define os_atomic_read(atomic) atomic_read(atomic) + +#endif /* __OS_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/stubs.c @@ -0,0 +1,52 @@ +/********************************************************* + * Copyright (C) 2007 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + + +/* + * stubs.c -- + * + * Common stubs. + */ + +#include "os.h" + +/* + *---------------------------------------------------------------------------- + * + * Panic -- + * + * Panic implementation. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +void +Panic(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + os_panic(fmt, args); + va_end(args); +} --- /dev/null +++ b/drivers/vmware/vmblock/stubs.h @@ -0,0 +1,36 @@ +/********************************************************* + * Copyright (C) 2007 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + + +/* + * stubs.h -- + * + */ + + +#ifndef __STUBS_H__ +#define __STUBS_H__ + +#ifdef linux +# include "driver-config.h" +# include "compat_version.h" +#endif + +void Panic(const char *fmt, ...); + +#endif /* __STUBS_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/super.c @@ -0,0 +1,194 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * super.c -- + * + * Super operations for the file system portion of the vmblock driver. + * + */ + +#include "driver-config.h" +#include "compat_fs.h" +#include "compat_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); +#else +static int SuperOpStatfs(struct super_block *sb, struct compat_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 +/* + *---------------------------------------------------------------------------- + * + * SuperOpAllocInode -- + * + * Allocates an inode info from the cache. See function comment for Iget() + * for a complete explanation of how inode allocation works. + * + * Results: + * A pointer to the embedded inode on success, NULL on failure. + * + * Side effects: + * iinfo is initialized by InodeCacheCtor(). + * + *---------------------------------------------------------------------------- + */ + +static struct inode * +SuperOpAllocInode(struct super_block *sb) // IN: superblock of file system +{ + VMBlockInodeInfo *iinfo; + + iinfo = kmem_cache_alloc(VMBlockInodeCache, GFP_KERNEL); + if (!iinfo) { + Warning("SuperOpAllocInode: could not allocate iinfo\n"); + return NULL; + } + + /* The inode we give back to VFS is embedded within our inode info struct. */ + return &iinfo->inode; +} +#endif + + +/* + *---------------------------------------------------------------------------- + * + * SuperOpDestroyInode -- + * SuperOpClearInode -- + * + * Destroys the provided inode by freeing the inode info. In the embedded + * inode case, this includes the actual inode itself; in the non-embedded + * inode case, the inode is freed by the kernel. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +#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 + +/* + *---------------------------------------------------------------------------- + * + * SuperOpStatfs -- + * + * Implements a null statfs. + * + * Results: + * Zero on success, negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +#ifdef VMW_STATFS_2618 +static int +SuperOpStatfs(struct dentry *dentry, + struct compat_kstatfs *stat) +#else +static int +SuperOpStatfs(struct super_block *sb, + struct compat_kstatfs *stat) +#endif +{ + if (!stat) { + return -EINVAL; + } + + stat->f_type = VMBLOCK_SUPER_MAGIC; + stat->f_bsize = 0; + stat->f_namelen = NAME_MAX; + stat->f_blocks = 0; + stat->f_bfree = 0; + stat->f_bavail = 0; + + return 0; +} --- /dev/null +++ b/drivers/vmware/vmblock/vm_assert.h @@ -0,0 +1,308 @@ +/********************************************************* + * Copyright (C) 1998-2004 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vm_assert.h -- + * + * The basic assertion facility for all VMware code. + * + * For proper use, see + * http://vmweb.vmware.com/~mts/WebSite/guide/programming/asserts.html + */ + +#ifndef _VM_ASSERT_H_ +#define _VM_ASSERT_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" + +// XXX not necessary except some places include vm_assert.h improperly +#include "vm_basic_types.h" +#include "vm_basic_defs.h" + + +/* + * XXX old file code + */ + +#ifdef FILECODEINT +#error "Don't define FILECODEINT. It is obsolete." +#endif +#ifdef FILECODE +#error "Don't define FILECODE. It is obsolete." +#endif + + +/* + * Panic and log functions + */ + +EXTERN void Log(const char *fmt, ...) PRINTF_DECL(1, 2); +EXTERN void Warning(const char *fmt, ...) PRINTF_DECL(1, 2); +EXTERN NORETURN void Panic(const char *fmt, ...) PRINTF_DECL(1, 2); + +EXTERN void LogThrottled(uint32 *count, const char *fmt, ...) + PRINTF_DECL(2, 3); +EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...) + PRINTF_DECL(2, 3); + +/* DB family: messages which are parsed by logfile database system */ +#define WarningDB Warning +#define LogDB Log +#define WarningThrottledDB WarningThrottled +#define LogThrottledDB LogThrottled + + +/* + * Stress testing: redefine ASSERT_IFNOT() to taste + */ + +#ifndef ASSERT_IFNOT + #ifdef __cplusplus + #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0) + #else + #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0) + #endif +#endif + + +/* + * Assert, panic, and log macros + * + * Some of these are redefined below undef !VMX86_DEBUG. + * ASSERT() is special cased because of interaction with Windows DDK. + */ + +#if defined VMX86_DEBUG || defined ASSERT_ALWAYS_AVAILABLE +#undef ASSERT +#define ASSERT(cond) \ + ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertAssert)) +#endif +#define ASSERT_BUG(bug, cond) \ + ASSERT_IFNOT(cond, _ASSERT_PANIC_BUG(bug, AssertAssert)) +#define ASSERT_BUG_DEBUGONLY(bug, cond) ASSERT_BUG(bug, cond) + +#define PANIC() _ASSERT_PANIC(AssertPanic) +#define PANIC_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertPanic) + +#define ASSERT_NOT_IMPLEMENTED(cond) \ + ASSERT_IFNOT(cond, NOT_IMPLEMENTED()) +#define ASSERT_NOT_IMPLEMENTED_BUG(bug, cond) \ + ASSERT_IFNOT(cond, NOT_IMPLEMENTED_BUG(bug)) + +#define NOT_IMPLEMENTED() _ASSERT_PANIC(AssertNotImplemented) +#define NOT_IMPLEMENTED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotImplemented) + +#define NOT_REACHED() _ASSERT_PANIC(AssertNotReached) +#define NOT_REACHED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotReached) + +#define ASSERT_MEM_ALLOC(cond) \ + ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertMemAlloc)) + +#ifdef VMX86_DEVEL + #define ASSERT_LENGTH(real, expected) \ + ASSERT_IFNOT((real) == (expected), \ + Panic(AssertLengthFmt, __FILE__, __LINE__, real, expected)) +#else + #define ASSERT_LENGTH(real, expected) ASSERT((real) == (expected)) +#endif + +#ifdef VMX86_DEVEL + #define ASSERT_DEVEL(cond) ASSERT(cond) +#else + #define ASSERT_DEVEL(cond) ((void) 0) +#endif + +#define ASSERT_NO_INTERRUPTS() ASSERT(!INTERRUPTS_ENABLED()) +#define ASSERT_HAS_INTERRUPTS() ASSERT(INTERRUPTS_ENABLED()) + +#define ASSERT_LOG_UNEXPECTED(bug, cond) \ + (UNLIKELY(!(cond)) ? LOG_UNEXPECTED(bug) : 0) +#ifdef VMX86_DEVEL + #define LOG_UNEXPECTED(bug) \ + Warning(AssertUnexpectedFmt, __FILE__, __LINE__, bug) +#else + #define LOG_UNEXPECTED(bug) \ + Log(AssertUnexpectedFmt, __FILE__, __LINE__, bug) +#endif + +#define ASSERT_NOT_TESTED(cond) (UNLIKELY(!(cond)) ? NOT_TESTED() : 0) +#ifdef VMX86_DEVEL + #define NOT_TESTED() Warning(AssertNotTestedFmt, __FILE__, __LINE__) +#else + #define NOT_TESTED() Log(AssertNotTestedFmt, __FILE__, __LINE__) +#endif + +#define NOT_TESTED_ONCE() \ + do { \ + static Bool alreadyPrinted = FALSE; \ + if (UNLIKELY(!alreadyPrinted)) { \ + alreadyPrinted = TRUE; \ + NOT_TESTED(); \ + } \ + } while (0) + +#define NOT_TESTED_1024() \ + do { \ + static uint16 count = 0; \ + if (UNLIKELY(count == 0)) { NOT_TESTED(); } \ + count = (count + 1) & 1023; \ + } while (0) + +#define LOG_ONCE(_s) \ + do { \ + static Bool logged = FALSE; \ + if (!logged) { \ + Log _s; \ + logged = TRUE; \ + } \ + } while (0) + + +/* + * Redefine macros that are only in debug versions + */ + +#if !defined VMX86_DEBUG && !defined ASSERT_ALWAYS_AVAILABLE // { + +#undef ASSERT +#define ASSERT(cond) ((void) 0) + +#undef ASSERT_BUG_DEBUGONLY +#define ASSERT_BUG_DEBUGONLY(bug, cond) ((void) 0) + +#undef ASSERT_LENGTH +#define ASSERT_LENGTH(real, expected) ((void) 0) + +/* + * Expand NOT_REACHED() as appropriate for each situation. + * + * Mainly, we want the compiler to infer the same control-flow + * information as it would from Panic(). Otherwise, different + * compilation options will lead to different control-flow-derived + * errors, causing some make targets to fail while others succeed. + * + * VC++ has the __assume() built-in function which we don't trust + * (see bug 43485); gcc has no such construct; we just panic in + * userlevel code. The monitor doesn't want to pay the size penalty + * (measured at 212 bytes for the release vmm for a minimal infinite + * loop; panic would cost even more) so it does without and lives + * with the inconsistency. + */ + +#ifdef VMM +#undef NOT_REACHED +#define NOT_REACHED() ((void) 0) +#else +// keep debug definition +#endif + +#undef ASSERT_LOG_UNEXPECTED +#define ASSERT_LOG_UNEXPECTED(bug, cond) ((void) 0) + +#undef LOG_UNEXPECTED +#define LOG_UNEXPECTED(bug) ((void) 0) + +#undef ASSERT_NOT_TESTED +#define ASSERT_NOT_TESTED(cond) ((void) 0) +#undef NOT_TESTED +#define NOT_TESTED() ((void) 0) +#undef NOT_TESTED_ONCE +#define NOT_TESTED_ONCE() ((void) 0) +#undef NOT_TESTED_1024 +#define NOT_TESTED_1024() ((void) 0) + +#endif // !VMX86_DEBUG } + + +/* + * Compile-time assertions + */ + +#define ASSERT_ON_COMPILE(e) \ + do { \ + typedef char AssertOnCompileType[(e) ? 1 : -1]; \ + } while (0) + + +/* + * To put an ASSERT_ON_COMPILE() outside a function, wrap it + * in MY_ASSERTS(). The first parameter must be unique in + * each .c file where it appears. For example, + * + * MY_ASSERTS(FS3_INT, + * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128); + * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE); + * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE); + * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16); + * ) + * + * Caution: ASSERT() within MY_ASSERTS() is silently ignored. + * The same goes for anything else not evaluated at compile time. + */ + +#define MY_ASSERTS(name, assertions) \ + static INLINE void name(void) { \ + assertions \ + } + + +/* + * Internal macros, functions, and strings + * + * The monitor wants to save space at call sites, so it has specialized + * functions for each situation. User level wants to save on implementation + * so it uses generic functions. + */ + +#if !defined VMM || defined MONITOR_APP // { + +#define _ASSERT_PANIC(name) \ + Panic(_##name##Fmt "\n", __FILE__, __LINE__) +#define _ASSERT_PANIC_BUG(bug, name) \ + Panic(_##name##Fmt " bugNr=%d\n", __FILE__, __LINE__, bug) + +#define AssertLengthFmt _AssertLengthFmt +#define AssertUnexpectedFmt _AssertUnexpectedFmt +#define AssertNotTestedFmt _AssertNotTestedFmt + +#endif // } + +// these don't have newline so a bug can be tacked on +#define _AssertPanicFmt "PANIC %s:%d" +#define _AssertAssertFmt "ASSERT %s:%d" +#define _AssertNotImplementedFmt "NOT_IMPLEMENTED %s:%d" +#define _AssertNotReachedFmt "NOT_REACHED %s:%d" +#define _AssertMemAllocFmt "MEM_ALLOC %s:%d" + +// these are complete formats with newline +#define _AssertLengthFmt "LENGTH %s:%d r=%#x e=%#x\n" +#define _AssertUnexpectedFmt "UNEXPECTED %s:%d bugNr=%d\n" +#define _AssertNotTestedFmt "NOT_TESTED %s:%d\n" + +#endif /* ifndef _VM_ASSERT_H_ */ --- /dev/null +++ b/drivers/vmware/vmblock/vm_basic_defs.h @@ -0,0 +1,553 @@ +/********************************************************* + * Copyright (C) 2003 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vm_basic_defs.h -- + * + * Standard macros for VMware source code. + */ + +#ifndef _VM_BASIC_DEFS_H_ +#define _VM_BASIC_DEFS_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" +#include "vm_basic_types.h" // For INLINE. + +#if defined _WIN32 && defined USERLEVEL + #include /* + * We re-define offsetof macro from stddef, make + * sure that its already defined before we do it + */ + #include // for Sleep() and LOWORD() etc. +#endif + + +/* + * Simple macros + */ + +#if defined __APPLE__ && !defined KERNEL +# include +#else +// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning +// XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings +#ifndef offsetof +#ifdef __cplusplus +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif +#endif // __APPLE__ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof (a) / sizeof *(a)) +#endif + +#ifndef MIN +#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +/* The Solaris 9 cross-compiler complains about these not being used */ +#ifndef sun +static INLINE int +Min(int a, int b) +{ + return a < b ? a : b; +} +#endif + +#ifndef MAX +#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + +#ifndef sun +static INLINE int +Max(int a, int b) +{ + return a > b ? a : b; +} +#endif + +#define ROUNDUP(x,y) (((x) + (y) - 1) / (y) * (y)) +#define ROUNDDOWN(x,y) ((x) / (y) * (y)) +#define ROUNDUPBITS(x, bits) (((uintptr_t) (x) + MASK(bits)) & ~MASK(bits)) +#define ROUNDDOWNBITS(x, bits) ((uintptr_t) (x) & ~MASK(bits)) +#define CEILING(x, y) (((x) + (y) - 1) / (y)) +#if defined __APPLE__ +#include +#undef MASK +#endif +#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ +#define DWORD_ALIGN(x) ((((x)+3) >> 2) << 2) +#define QWORD_ALIGN(x) ((((x)+4) >> 3) << 3) + +#define IMPLIES(a,b) (!(a) || (b)) + +/* + * Not everybody (e.g., the monitor) has NULL + */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + + +/* + * Token concatenation + * + * The C preprocessor doesn't prescan arguments when they are + * concatenated or stringified. So we need extra levels of + * indirection to convince the preprocessor to expand its + * arguments. + */ + +#define CONC(x, y) x##y +#define XCONC(x, y) CONC(x, y) +#define XXCONC(x, y) XCONC(x, y) +#define MAKESTR(x) #x +#define XSTR(x) MAKESTR(x) + + +/* + * Page operations + * + * It has been suggested that these definitions belong elsewhere + * (like x86types.h). However, I deem them common enough + * (since even regular user-level programs may want to do + * page-based memory manipulation) to be here. + * -- edward + */ + +#ifndef PAGE_SHIFT // { +#if defined VM_I386 + #define PAGE_SHIFT 12 +#elif defined __APPLE__ + #define PAGE_SHIFT 12 +#else + #error +#endif +#endif // } + +#ifndef PAGE_SIZE +#define PAGE_SIZE (1<> PAGE_SHIFT) +#endif + +#ifndef BYTES_2_PAGES +#define BYTES_2_PAGES(_nbytes) ((_nbytes) >> PAGE_SHIFT) +#endif + +#ifndef PAGES_2_BYTES +#define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT) +#endif + +#ifndef MBYTES_2_PAGES +#define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT)) +#endif + +#ifndef PAGES_2_MBYTES +#define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT)) +#endif + +#ifndef VM_PAE_LARGE_PAGE_SHIFT +#define VM_PAE_LARGE_PAGE_SHIFT 21 +#endif + +#ifndef VM_PAE_LARGE_PAGE_SIZE +#define VM_PAE_LARGE_PAGE_SIZE (1 << VM_PAE_LARGE_PAGE_SHIFT) +#endif + +#ifndef VM_PAE_LARGE_PAGE_MASK +#define VM_PAE_LARGE_PAGE_MASK (VM_PAE_LARGE_PAGE_SIZE - 1) +#endif + +#ifndef VM_PAE_LARGE_2_SMALL_PAGES +#define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE)) +#endif + +/* + * Word operations + */ + +#ifndef LOWORD +#define LOWORD(_dw) ((_dw) & 0xffff) +#endif +#ifndef HIWORD +#define HIWORD(_dw) (((_dw) >> 16) & 0xffff) +#endif + +#ifndef LOBYTE +#define LOBYTE(_w) ((_w) & 0xff) +#endif +#ifndef HIBYTE +#define HIBYTE(_w) (((_w) >> 8) & 0xff) +#endif + +#define HIDWORD(_qw) ((uint32)((_qw) >> 32)) +#define LODWORD(_qw) ((uint32)(_qw)) +#define QWORD(_hi, _lo) ((((uint64)(_hi)) << 32) | ((uint32)(_lo))) + + +/* + * Deposit a field _src at _pos bits from the right, + * with a length of _len, into the integer _target. + */ + +#define DEPOSIT_BITS(_src,_pos,_len,_target) { \ + unsigned mask = ((1 << _len) - 1); \ + unsigned shiftedmask = ((1 << _len) - 1) << _pos; \ + _target = (_target & ~shiftedmask) | ((_src & mask) << _pos); \ +} + + +/* + * Get return address. + */ + +#ifdef _MSC_VER +#ifdef __cplusplus +extern "C" +#endif +void *_ReturnAddress(void); +#pragma intrinsic(_ReturnAddress) +#define GetReturnAddress() _ReturnAddress() +#elif __GNUC__ +#define GetReturnAddress() __builtin_return_address(0) +#endif + + +#ifdef __GNUC__ +#ifndef sun + +/* + * Get the frame pointer. We use this assembly hack instead of + * __builtin_frame_address() due to a bug introduced in gcc 4.1.1 + */ +static INLINE_SINGLE_CALLER uintptr_t +GetFrameAddr(void) +{ + uintptr_t bp; +#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)) + bp = (uintptr_t)__builtin_frame_address(0); +#elif (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 3) +# if defined(VMM64) || defined(VM_X86_64) + __asm__ __volatile__("movq %%rbp, %0\n" : "=g" (bp)); +# else + __asm__ __volatile__("movl %%ebp, %0\n" : "=g" (bp)); +# endif +#else + __asm__ __volatile__( +#ifdef __linux__ + ".print \"This newer version of GCC may or may not have the " + "__builtin_frame_address bug. Need to update this. " + "See bug 147638.\"\n" + ".abort" +#else /* MacOS */ + ".abort \"This newer version of GCC may or may not have the " + "__builtin_frame_address bug. Need to update this. " + "See bug 147638.\"\n" +#endif + : "=g" (bp) + ); +#endif + return bp; +} + + +/* + * Returns the frame pointer of the calling function. + * Equivalent to __builtin_frame_address(1). + */ +static INLINE_SINGLE_CALLER uintptr_t +GetCallerFrameAddr(void) +{ + return *(uintptr_t*)GetFrameAddr(); +} + +#endif // sun +#endif // __GNUC__ + + + + +#ifdef USERLEVEL // { + +/* + * Note this might be a problem on NT b/c while sched_yield guarantees it + * moves you to the end of your priority list, Sleep(0) offers no such + * guarantee. Bummer. --Jeremy. + */ + +#if defined(N_PLAT_NLM) || defined(__FreeBSD__) +/* We do not have YIELD() as we do not need it yet... */ +#elif defined(_WIN32) +# define YIELD() Sleep(0) +#else +# include // For sched_yield. Don't ask. --Jeremy. +# define YIELD() sched_yield() +#endif + + +/* + * Standardize some Posix names on Windows. + */ + +#ifdef _WIN32 // { + +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +static INLINE void +sleep(unsigned int sec) +{ + Sleep(sec * 1000); +} + +static INLINE void +usleep(unsigned long usec) +{ + Sleep(CEILING(usec, 1000)); +} + +typedef int pid_t; +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +#endif // } + +/* + * Macro for username comparison. + */ + +#ifdef _WIN32 // { +#define USERCMP(x,y) Str_Strcasecmp(x,y) +#else +#define USERCMP(x,y) strcmp(x,y) +#endif // } + + +#endif // } + +#ifndef va_copy + +#ifdef _WIN32 + +/* + * Windows needs va_copy. This works for both 32 and 64-bit Windows + * based on inspection of how varags.h from the Visual C CRTL is + * implemented. (Future versions of the RTL may break this). + */ + +#define va_copy(dest, src) ((dest) = (src)) + +#elif defined(__APPLE__) && defined(KERNEL) + +/* + * MacOS kernel-mode needs va_copy. Based on inspection of stdarg.h + * from the MacOSX10.4u.sdk kernel framework, this should work. + * (Future versions of the SDK may break this). + */ + +#define va_copy(dest, src) ((dest) = (src)) + +#elif defined(__GNUC__) && (__GNUC__ < 3) + +/* + * Old versions of gcc recognize __va_copy, but not va_copy. + */ + +#define va_copy(dest, src) __va_copy(dest, src) + +#endif // _WIN32 + +#endif // va_copy + +/* + * This one is outside USERLEVEL because it's used by + * files compiled into the Windows hgfs driver or the display + * driver. + */ + +#ifdef _WIN32 +#define PATH_MAX 256 +#ifndef strcasecmp +#define strcasecmp(_s1,_s2) _stricmp((_s1),(_s2)) +#endif +#ifndef strncasecmp +#define strncasecmp(_s1,_s2,_n) _strnicmp((_s1),(_s2),(_n)) +#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. + */ + +#undef DEBUG_ONLY +#ifdef VMX86_DEBUG +#define vmx86_debug 1 +#define DEBUG_ONLY(x) x +#else +#define vmx86_debug 0 +#define DEBUG_ONLY(x) +#endif + +#ifdef VMX86_STATS +#define vmx86_stats 1 +#define STATS_ONLY(x) x +#else +#define vmx86_stats 0 +#define STATS_ONLY(x) +#endif + +#ifdef VMX86_DEVEL +#define vmx86_devel 1 +#define DEVEL_ONLY(x) x +#else +#define vmx86_devel 0 +#define DEVEL_ONLY(x) +#endif + +#ifdef VMX86_LOG +#define vmx86_log 1 +#define LOG_ONLY(x) x +#else +#define vmx86_log 0 +#define LOG_ONLY(x) +#endif + +#ifdef VMX86_VMM_SERIAL_LOGGING +#define vmx86_vmm_serial_log 1 +#define VMM_SERIAL_LOG_ONLY(x) x +#else +#define vmx86_vmm_serial_log 0 +#define VMM_SERIAL_LOG_ONLY(x) +#endif + +#ifdef VMX86_SERVER +#define vmx86_server 1 +#define SERVER_ONLY(x) x +#define HOSTED_ONLY(x) +#else +#define vmx86_server 0 +#define SERVER_ONLY(x) +#define HOSTED_ONLY(x) x +#endif + +#ifdef VMX86_WGS +#define vmx86_wgs 1 +#define WGS_ONLY(x) x +#else +#define vmx86_wgs 0 +#define WGS_ONLY(x) +#endif + +#ifdef VMKERNEL +#define vmkernel 1 +#define VMKERNEL_ONLY(x) x +#else +#define vmkernel 0 +#define VMKERNEL_ONLY(x) +#endif + +#ifdef _WIN32 +#define WIN32_ONLY(x) x +#define POSIX_ONLY(x) +#else +#define WIN32_ONLY(x) +#define POSIX_ONLY(x) x +#endif + +#ifdef VMM +#define VMM_ONLY(x) x +#define USER_ONLY(x) +#else +#define VMM_ONLY(x) +#define USER_ONLY(x) x +#endif + +/* VMVISOR ifdef only allowed in the vmkernel */ +#ifdef VMKERNEL +#ifdef VMVISOR +#define vmvisor 1 +#define VMVISOR_ONLY(x) x +#else +#define vmvisor 0 +#define VMVISOR_ONLY(x) +#endif +#endif + +#ifdef _WIN32 +#define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE +#else +#define VMW_INVALID_HANDLE -1 +#endif + +#endif // ifndef _VM_BASIC_DEFS_H_ --- /dev/null +++ b/drivers/vmware/vmblock/vm_basic_types.h @@ -0,0 +1,847 @@ +/********************************************************* + * Copyright (C) 1998-2008 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * + * vm_basic_types.h -- + * + * basic data types. + */ + + +#ifndef _VM_BASIC_TYPES_H_ +#define _VM_BASIC_TYPES_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" + +/* STRICT ANSI means the Xserver build and X defines Bool differently. */ +#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__) +typedef char Bool; +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#define IsBool(x) (((x) & ~1) == 0) +#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0) + +/* + * Macros __i386__ and __ia64 are intrinsically defined by GCC + */ +#ifdef __i386__ +#define VM_I386 +#endif + +#ifdef _WIN64 +#define __x86_64__ +#endif + +#ifdef __x86_64__ +#define VM_X86_64 +#define VM_I386 +#define vm_x86_64 (1) +#else +#define vm_x86_64 (0) +#endif + + + +#ifdef _WIN32 +/* safe assumption for a while */ +#define VM_I386 +#endif + +#ifdef _MSC_VER +typedef unsigned __int64 uint64; +typedef signed __int64 int64; + +#pragma warning (3 :4505) // unreferenced local function +#pragma warning (disable :4018) // signed/unsigned mismatch +#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied +#pragma warning (disable :4305) // truncation from 'const int' to 'short' +#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char' +#pragma warning (disable :4267) // truncation of 'size_t' +#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning (disable :4142) // benign redefinition of type + +#elif __GNUC__ +/* The Xserver source compiles with -ansi -pendantic */ +#ifndef __STRICT_ANSI__ +#if defined(VM_X86_64) +typedef unsigned long uint64; +typedef long int64; +#else +typedef unsigned long long uint64; +typedef long long int64; +#endif +#elif __FreeBSD__ +typedef unsigned long long uint64; +typedef long long int64; +#endif +#else +#error - Need compiler define for int64/uint64 +#endif + +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef int int32; +typedef short int16; +typedef char int8; + +/* + * FreeBSD (for the tools build) unconditionally defines these in + * sys/inttypes.h so don't redefine them if this file has already + * been included. [greg] + * + * This applies to Solaris as well. + */ + +/* + * Before trying to do the includes based on OS defines, see if we can use + * feature-based defines to get as much functionality as possible + */ + +#ifdef HAVE_INTTYPES_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_INTTYPES_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#if !defined(USING_AUTOCONF) +# if defined(__FreeBSD__) || defined(sun) +# ifdef KLD_MODULE +# include +# else +# if (BSD_VERSION >= 50) +# include +# include +# else +# include +# endif +# endif +# elif defined __APPLE__ +# if KERNEL +# include +# include /* mostly for size_t */ +# include +# else +# include +# include +# include +# include +# endif +# else +# if !defined(__intptr_t_defined) && !defined(intptr_t) +# define __intptr_t_defined +# define intptr_t intptr_t +# ifdef VM_I386 +# ifdef VM_X86_64 +typedef int64 intptr_t; +# else +typedef int32 intptr_t; +# endif +# endif +# endif + +# ifndef _STDINT_H +# ifdef VM_I386 +# ifdef VM_X86_64 +typedef uint64 uintptr_t; +# else +typedef uint32 uintptr_t; +# endif +# endif +# endif +# endif +#endif + + +/* + * Time + * XXX These should be cleaned up. -- edward + */ + +typedef int64 VmTimeType; /* Time in microseconds */ +typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */ +typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */ + +/* + * Printf format specifiers for size_t and 64-bit number. + * Use them like this: + * printf("%"FMT64"d\n", big); + * + * FMTH is for handles/fds. + */ + +#ifdef _MSC_VER + #define FMT64 "I64" + #ifdef VM_X86_64 + #define FMTSZ "I64" + #define FMTPD "I64" + #define FMTH "I64" + #else + #define FMTSZ "I" + #define FMTPD "I" + #define FMTH "I" + #endif +#elif __GNUC__ + #define FMTH "" + #if defined(N_PLAT_NLM) || defined(sun) || \ + (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5)) + /* + * Why (__FreeBSD__ + 0)? See bug 141008. + * Yes, we really need to test both (__FreeBSD__ + 0) and + * ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from + * ((__FreeBSD__ + 0) < 5). + */ + #ifdef VM_X86_64 + #define FMTSZ "l" + #define FMTPD "l" + #else + #define FMTSZ "" + #define FMTPD "" + #endif + #elif defined(__linux__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \ + || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \ + || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L) + /* BSD/Darwin, Linux */ + #define FMTSZ "z" + #define FMTPD "t" + #else + /* Systems with a pre-C99 libc */ + #define FMTSZ "Z" + #ifdef VM_X86_64 + #define FMTPD "l" + #else + #define FMTPD "" + #endif + #endif + #ifdef VM_X86_64 + #define FMT64 "l" + #elif defined(sun) || defined(__APPLE__) || defined(__FreeBSD__) + #define FMT64 "ll" + #else + #define FMT64 "L" + #endif +#else + #error - Need compiler define for FMT64 and FMTSZ +#endif + +/* + * Suffix for 64-bit constants. Use it like this: + * CONST64(0x7fffffffffffffff) for signed or + * CONST64U(0x7fffffffffffffff) for unsigned. + * + * 2004.08.30(thutt): + * The vmcore/asm64/gen* programs are compiled as 32-bit + * applications, but must handle 64 bit constants. If the + * 64-bit-constant defining macros are already defined, the + * definition will not be overwritten. + */ + +#if !defined(CONST64) || !defined(CONST64U) +#ifdef _MSC_VER +#define CONST64(c) c##I64 +#define CONST64U(c) c##uI64 +#elif __GNUC__ +#ifdef VM_X86_64 +#define CONST64(c) c##L +#define CONST64U(c) c##uL +#else +#define CONST64(c) c##LL +#define CONST64U(c) c##uLL +#endif +#else +#error - Need compiler define for CONST64 +#endif +#endif + +/* + * Use CONST3264/CONST3264U if you want a constant to be + * treated as a 32-bit number on 32-bit compiles and + * a 64-bit number on 64-bit compiles. Useful in the case + * of shifts, like (CONST3264U(1) << x), where x could be + * more than 31 on a 64-bit compile. + */ + +#ifdef VM_X86_64 + #define CONST3264(a) CONST64(a) + #define CONST3264U(a) CONST64U(a) +#else + #define CONST3264(a) (a) + #define CONST3264U(a) (a) +#endif + +#define MIN_INT32 ((int32)0x80000000) +#define MAX_INT32 ((int32)0x7fffffff) + +#define MIN_UINT32 ((uint32)0) +#define MAX_UINT32 ((uint32)0xffffffff) + +#define MIN_INT64 (CONST64(0x8000000000000000)) +#define MAX_INT64 (CONST64(0x7fffffffffffffff)) + +#define MIN_UINT64 (CONST64U(0)) +#define MAX_UINT64 (CONST64U(0xffffffffffffffff)) + +typedef uint8 *TCA; /* Pointer into TC (usually). */ + +/* + * Type big enough to hold an integer between 0..100 + */ +typedef uint8 Percent; +#define asPercent(v) ((Percent)(v)) +#define CHOOSE_PERCENT asPercent(-1) + + +typedef uintptr_t VA; +typedef uintptr_t VPN; + +typedef uint64 PA; +typedef uint32 PPN; + +typedef uint64 PhysMemOff; +typedef uint64 PhysMemSize; + +/* The Xserver source compiles with -ansi -pendantic */ +#ifndef __STRICT_ANSI__ +typedef uint64 BA; +#endif +typedef uint32 BPN; +typedef uint32 PageNum; +typedef unsigned MemHandle; +typedef int32 World_ID; + +#define INVALID_WORLD_ID ((World_ID)0) + +typedef World_ID User_CartelID; +#define INVALID_CARTEL_ID INVALID_WORLD_ID + +typedef User_CartelID User_SessionID; +#define INVALID_SESSION_ID INVALID_CARTEL_ID + +typedef User_CartelID User_CartelGroupID; +#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID + +/* world page number */ +typedef uint32 WPN; + +/* The Xserver source compiles with -ansi -pendantic */ +#ifndef __STRICT_ANSI__ +typedef uint64 MA; +typedef uint32 MPN; +#endif + +/* + * This type should be used for variables that contain sector + * position/quantity. + */ +typedef uint64 SectorType; + +/* + * Linear address + */ + +typedef uintptr_t LA; +typedef uintptr_t LPN; +#define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT) +#define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT) + +#define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1) +#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1) +#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1) + +/* Valid bits in a LPN. */ +#define LPN_MASK LAST_LPN +#define LPN_MASK32 LAST_LPN32 +#define LPN_MASK64 LAST_LPN64 + +/* + * On 64 bit platform, address and page number types default + * to 64 bit. When we need to represent a 32 bit address, we use + * types defined below. + * + * On 32 bit platform, the following types are the same as the + * default types. + */ +typedef uint32 VA32; +typedef uint32 VPN32; +typedef uint32 LA32; +typedef uint32 LPN32; +typedef uint32 PA32; +typedef uint32 PPN32; +typedef uint32 MA32; +typedef uint32 MPN32; + +/* + * On 64 bit platform, the following types are the same as the + * default types. + */ +typedef uint64 VA64; +typedef uint64 VPN64; +typedef uint64 LA64; +typedef uint64 LPN64; +typedef uint64 PA64; +typedef uint64 PPN64; +typedef uint64 MA64; +typedef uint64 MPN64; + +/* + * VA typedefs for user world apps. + */ +typedef VA32 UserVA32; +typedef VA64 UserVA64; +typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */ +typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */ +#ifdef VMKERNEL +typedef UserVA32 UserVA; +#else +typedef void * UserVA; +#endif + + +/* + * Maximal possible PPN value (errors too) that PhysMem can handle. + * Must be at least as large as MAX_PPN which is the maximum PPN + * for any region other than buserror. + */ +#define PHYSMEM_MAX_PPN ((PPN)0xffffffff) +#define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */ +#define INVALID_PPN ((PPN)0xffffffff) + +#define INVALID_BPN ((BPN) 0x1fffffff) + +#define INVALID_MPN ((MPN)-1) +#define MEMREF_MPN ((MPN)-2) +#define RESERVED_MPN ((MPN) 0) +/* Support 39 bits of address space, minus one page. */ +#define MAX_MPN ((MPN) 0x07ffffff) + +#define INVALID_LPN ((LPN)-1) +#define INVALID_VPN ((VPN)-1) +#define INVALID_LPN64 ((LPN64)-1) +#define INVALID_PAGENUM ((PageNum)-1) +#define INVALID_WPN ((WPN) -1) + + +/* + * Format modifier for printing VA, LA, and VPN. + * Use them like this: Log("%#"FMTLA"x\n", laddr) + */ + +#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__ +# define FMTLA "l" +# define FMTVA "l" +# define FMTVPN "l" +#else +# define FMTLA "" +# define FMTVA "" +# define FMTVPN "" +#endif + + +#define EXTERN extern +#define CONST const + + +#ifndef INLINE +# ifdef _MSC_VER +# define INLINE __inline +# else +# define INLINE inline +# endif +#endif + + +/* + * Annotation for data that may be exported into a DLL and used by other + * apps that load that DLL and import the data. + */ +#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA) +# define VMX86_EXTERN_DATA extern __declspec(dllimport) +#else // !_WIN32 +# define VMX86_EXTERN_DATA extern +#endif + +#if defined(_WIN32) && !defined(VMX86_NO_THREADS) +#define THREADSPECIFIC __declspec(thread) +#else +#define THREADSPECIFIC +#endif + +/* + * Due to the wonderful "registry redirection" feature introduced in + * 64-bit Windows, if you access any key under HKLM\Software in 64-bit + * code, you need to open/create/delete that key with + * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code. + */ + +#ifdef _WIN32 +#ifdef _WIN64 +#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY +#else +#define VMW_KEY_WOW64_32KEY 0x0 +#endif +#endif + + +/* + * Consider the following reasons functions are inlined: + * + * 1) inlined for performance reasons + * 2) inlined because it's a single-use function + * + * Functions which meet only condition 2 should be marked with this + * inline macro; It is not critical to be inlined (but there is a + * code-space & runtime savings by doing so), so when other callers + * are added the inline-ness should be removed. + */ + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +/* + * Starting at version 3.3, gcc does not always inline functions marked + * 'inline' (it depends on their size). To force gcc to do so, one must use the + * extra __always_inline__ attribute. + */ +# define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__)) +# if defined(VMM) \ + && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) +# warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \ + monitor size change?) +# endif +#else +# define INLINE_SINGLE_CALLER INLINE +#endif + +/* + * Used when a hard guaranteed of no inlining is needed. Very few + * instances need this since the absence of INLINE is a good hint + * that gcc will not do inlining. + */ + +#if defined(__GNUC__) && defined(VMM) +#define ABSOLUTELY_NOINLINE __attribute__((__noinline__)) +#endif + +/* + * Attributes placed on function declarations to tell the compiler + * that the function never returns. + */ + +#ifdef _MSC_VER +#define NORETURN __declspec(noreturn) +#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9) +#define NORETURN __attribute__((__noreturn__)) +#else +#define NORETURN +#endif + +/* + * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands. + * Older GCCs don't know about it --hpreg + */ + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) +# define VM_ASM_PLUS 1 +#else +# define VM_ASM_PLUS 0 +#endif + +/* + * Branch prediction hints: + * LIKELY(exp) - Expression exp is likely TRUE. + * UNLIKELY(exp) - Expression exp is likely FALSE. + * Usage example: + * if (LIKELY(excCode == EXC_NONE)) { + * or + * if (UNLIKELY(REAL_MODE(vc))) { + * + * We know how to predict branches on gcc3 and later (hopefully), + * all others we don't so we do nothing. + */ + +#if (__GNUC__ >= 3) +/* + * gcc3 uses __builtin_expect() to inform the compiler of an expected value. + * We use this to inform the static branch predictor. The '!!' in LIKELY + * will convert any !=0 to a 1. + */ +#define LIKELY(_exp) __builtin_expect(!!(_exp), 1) +#define UNLIKELY(_exp) __builtin_expect((_exp), 0) +#else +#define LIKELY(_exp) (_exp) +#define UNLIKELY(_exp) (_exp) +#endif + +/* + * GCC's argument checking for printf-like functions + * This is conditional until we have replaced all `"%x", void *' + * with `"0x%08x", (uint32) void *'. Note that %p prints different things + * on different platforms. Argument checking is enabled for the + * vmkernel, which has already been cleansed. + * + * fmtPos is the position of the format string argument, beginning at 1 + * varPos is the position of the variable argument, beginning at 1 + */ + +#if defined(__GNUC__) +# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos))) +#else +# define PRINTF_DECL(fmtPos, varPos) +#endif + +/* + * UNUSED_PARAM should surround the parameter name and type declaration, + * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))" + * + */ + +#ifndef UNUSED_PARAM +# if defined(__GNUC__) +# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__)) +# else +# define UNUSED_PARAM(_parm) _parm +# endif +#endif + +/* + * REGPARM defaults to REGPARM3, i.e., a requent that gcc + * puts the first three arguments in registers. (It is fine + * if the function has fewer than three args.) Gcc only. + * Syntactically, put REGPARM where you'd put INLINE or NORETURN. + */ + +#if defined(__GNUC__) +# define REGPARM0 __attribute__((regparm(0))) +# define REGPARM1 __attribute__((regparm(1))) +# define REGPARM2 __attribute__((regparm(2))) +# define REGPARM3 __attribute__((regparm(3))) +# define REGPARM REGPARM3 +#else +# define REGPARM0 +# define REGPARM1 +# define REGPARM2 +# define REGPARM3 +# define REGPARM +#endif + +/* + * ALIGNED specifies minimum alignment in "n" bytes. + */ + +#ifdef __GNUC__ +#define ALIGNED(n) __attribute__((__aligned__(n))) +#else +#define ALIGNED(n) +#endif + +/* + * __func__ is a stringified function name that is part of the C99 standard. The block + * below defines __func__ on older systems where the compiler does not support that + * macro. + */ +#if defined(__GNUC__) \ + && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \ + || (__GNUC__ < 2)) +# define __func__ __FUNCTION__ +#endif + +/* + * Once upon a time, this was used to silence compiler warnings that + * get generated when the compiler thinks that a function returns + * when it is marked noreturn. Don't do it. Use NOT_REACHED(). + */ + +#define INFINITE_LOOP() do { } while (1) + +/* + * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_ + * is defined. Use the same logic here so we don't define it twice. [greg] + */ +#ifdef __FreeBSD__ +# ifdef _BSD_SIZE_T_ +# undef _BSD_SIZE_T_ +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef uint64 size_t; +# else + typedef uint32 size_t; +# endif +# endif /* VM_I386 */ +# endif + +# ifdef _BSD_SSIZE_T_ +# undef _BSD_SSIZE_T_ +# define _SSIZE_T +# define __ssize_t_defined +# define _SSIZE_T_DECLARED +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef int64 ssize_t; +# else + typedef int32 ssize_t; +# endif +# endif /* VM_I386 */ +# endif + +#else +# ifndef _SIZE_T +# define _SIZE_T +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef uint64 size_t; +# else + typedef uint32 size_t; +# endif +# endif /* VM_I386 */ +# endif + +# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \ + !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED) +# define _SSIZE_T +# define __ssize_t_defined +# define _SSIZE_T_DECLARED +# ifdef VM_I386 +# ifdef VM_X86_64 + typedef int64 ssize_t; +# else + typedef int32 ssize_t; +# endif +# endif /* VM_I386 */ +# endif + +#endif + +/* + * Format modifier for printing pid_t. On sun the pid_t is a ulong, but on + * Linux it's an int. + * Use this like this: printf("The pid is %"FMTPID".\n", pid); + */ +#ifdef sun +# ifdef VM_X86_64 +# define FMTPID "d" +# else +# define FMTPID "lu" +# endif +#else +# define FMTPID "d" +#endif + +/* + * Format modifier for printing uid_t. On sun the uid_t is a ulong, but on + * Linux it's an int. + * Use this like this: printf("The uid is %"FMTUID".\n", uid); + */ +#ifdef sun +# ifdef VM_X86_64 +# define FMTUID "u" +# else +# define FMTUID "lu" +# endif +#else +# define FMTUID "u" +#endif + +/* + * Format modifier for printing mode_t. On sun the mode_t is a ulong, but on + * Linux it's an int. + * Use this like this: printf("The mode is %"FMTMODE".\n", mode); + */ +#ifdef sun +# ifdef VM_X86_64 +# define FMTMODE "o" +# else +# define FMTMODE "lo" +# endif +#else +# define FMTMODE "o" +#endif + +/* + * Format modifier for printing time_t. Most platforms define a time_t to be + * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed + * size quantity. Refer to the definition of FMTSZ to see why we need silly + * preprocessor arithmetic. + * Use this like this: printf("The mode is %"FMTTIME".\n", time); + */ +#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5) +# define FMTTIME FMTSZ"d" +#else +# define FMTTIME "ld" +#endif + +/* + * Define MXSemaHandle here so both vmmon and vmx see this definition. + */ + +#ifdef _WIN32 +typedef uintptr_t MXSemaHandle; +#else +typedef int MXSemaHandle; +#endif + +/* + * Define type for poll device handles. + */ + +#ifdef _WIN32 +typedef uintptr_t PollDevHandle; +#else +typedef int PollDevHandle; +#endif + +/* + * Define the utf16_t type. + */ + +#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED) +typedef wchar_t utf16_t; +#else +typedef uint16 utf16_t; +#endif + +#endif /* _VM_BASIC_TYPES_H_ */ --- /dev/null +++ b/drivers/vmware/vmblock/vmblock.h @@ -0,0 +1,105 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vmblock.h -- + * + * User-level interface to the vmblock device. + */ + +#ifndef _VMBLOCK_H_ +#define _VMBLOCK_H_ + +#if defined(sun) || defined(__FreeBSD__) +# include +#endif + +#if defined(__FreeBSD__) +# include +#endif + +#define VMBLOCK_FS_NAME "vmblock" + +/* Commands for the control half of vmblock driver */ +#if defined(linux) +# define VMBLOCK_ADD_FILEBLOCK 98 +# define VMBLOCK_DEL_FILEBLOCK 99 +# ifdef VMX86_DEVEL +# define VMBLOCK_LIST_FILEBLOCKS 100 +# endif +# define VMBLOCK_CONTROL_DIRNAME VMBLOCK_FS_NAME +# define VMBLOCK_CONTROL_DEVNAME "dev" +# define VMBLOCK_CONTROL_MOUNTPOINT "mountPoint" +# define VMBLOCK_CONTROL_PROC_DIRNAME "fs/" VMBLOCK_CONTROL_DIRNAME + +# define VMBLOCK_MOUNT_POINT "/proc/" VMBLOCK_CONTROL_PROC_DIRNAME \ + "/" VMBLOCK_CONTROL_MOUNTPOINT +# define VMBLOCK_DEVICE "/proc/" VMBLOCK_CONTROL_PROC_DIRNAME \ + "/" VMBLOCK_CONTROL_DEVNAME +# define VMBLOCK_DEVICE_MODE O_WRONLY +# define VMBLOCK_CONTROL(fd, op, path) write(fd, path, op) + +#elif defined(sun) || defined(__FreeBSD__) +# define VMBLOCK_MOUNT_POINT "/var/run/" VMBLOCK_FS_NAME +# define VMBLOCK_DEVICE VMBLOCK_MOUNT_POINT +# define VMBLOCK_DEVICE_MODE O_RDONLY +# if defined(sun) /* if (sun) { */ + /* + * Construct ioctl(2) commands for blocks. _IO() is a helper macro to + * construct unique command values more easily. I chose 'v' because I + * didn't see it being used elsewhere, and the command numbers begin at one. + */ +# define VMBLOCK_ADD_FILEBLOCK _IO('v', 1) +# define VMBLOCK_DEL_FILEBLOCK _IO('v', 2) +# ifdef VMX86_DEVEL +# define VMBLOCK_LIST_FILEBLOCKS _IO('v', 3) +# endif +# define VMBLOCK_CONTROL(fd, op, path) ioctl(fd, op, path) + +# elif defined(__FreeBSD__) /* } else if (FreeBSD) { */ + /* + * Similar to Solaris, construct ioctl(2) commands for block operations. + * Since the FreeBSD implementation does not change the user's passed-in + * data (pathname), we use the _IOW macro to define commands which write + * to the kernel. (As opposed to _IOR or _IOWR.) Groups 'v' and 'V' + * are taken by terminal drivers, so I opted for group 'Z'. + */ +# define VMBLOCK_ADD_FILEBLOCK _IOW('Z', 1, char[MAXPATHLEN] ) +# define VMBLOCK_DEL_FILEBLOCK _IOW('Z', 2, char[MAXPATHLEN] ) +# ifdef VMX86_DEVEL +# define VMBLOCK_LIST_FILEBLOCKS _IO('Z', 3) +# define VMBLOCK_PURGE_FILEBLOCKS _IO('Z', 4) +# endif + /* + * 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. + */ +# define VMBLOCK_CONTROL(fd, cmd, path) \ +({ \ + char tpath[MAXPATHLEN]; \ + if (path != NULL) { \ + strlcpy(tpath, path, MAXPATHLEN); \ + } \ + ioctl((fd), (cmd), tpath); \ +}) +# endif /* } */ +#else +# error "Unknown platform for vmblock." +#endif + +#endif /* _VMBLOCK_H_ */ --- /dev/null +++ b/drivers/vmware/vmblock/vmblockInt.h @@ -0,0 +1,94 @@ +/********************************************************* + * Copyright (C) 2006 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vmblockInt.h -- + * + * Definitions and prototypes for entire module. + * + * The module is split into two halves, a control half and a file system + * half, and the halves communicate through the blocking functionality in + * block.c. The control half creates a device node for a user space program + * (running as root) to add and delete blocks on files in the file system's + * namespace. The file system provides links to the contents of the + * directory it is redirecting to and blocks according to the file blocks set + * through the control half. + */ + +#ifndef __VMBLOCKINT_H__ +#define __VMBLOCKINT_H__ + +#include "compat_version.h" +#include "compat_mm.h" + +#include "vmblock.h" +#include "vm_basic_types.h" +#include "vm_assert.h" + +#ifdef __KERNEL__ +#ifdef VMX86_DEVEL +extern int LOGLEVEL_THRESHOLD; +# define LOG(level, fmt, args...) \ + ((void) (LOGLEVEL_THRESHOLD >= (level) ? \ + printk(KERN_DEBUG "VMBlock: " fmt, ## args) : \ + 0) \ + ) +#else +# define LOG(level, fmt, args...) +#endif +#define Warning(fmt, args...) \ + printk(KERN_WARNING "VMBlock warning: " fmt, ## args) +/* + * Some kernel versions, bld-2.4.21-32.EL_x86_64-ia32e-RHEL3 and perhaps more, + * don't define __user in uaccess.h, so let's do it here so we don't have to + * ifdef all the __user annotations. + */ +#ifndef __user +#define __user +#endif +#endif /* __KERNEL__ */ + +#define VMBLOCK_CONTROL_MODE S_IRUSR | S_IFREG + +/* + * Our modules may be compatible with kernels built for different processors. + * This can cause problems, so we add a reference to the __alloc_pages symbol + * below since it is versioned per-processor and will cause modules to only + * load on kernels built for the same processor as our module. + * + * XXX This should go in driver-config.h, but vmmon's hostKernel.h is retarded. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) +static const void *forceProcessorCheck __attribute__((unused)) = __alloc_pages; +#endif + + +/* + * Initialization and cleanup routines for control and file system halves of + * vmblock driver + */ +int VMBlockInitControlOps(void); +int VMBlockCleanupControlOps(void); +int VMBlockInitFileSystem(char const *root); +int VMBlockCleanupFileSystem(void); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70) +size_t strlcpy(char *dest, const char *src, size_t count); +#endif + +#endif /* __VMBLOCK_H__ */ --- /dev/null +++ b/drivers/vmware/vmblock/vmblock_version.h @@ -0,0 +1,32 @@ +/********************************************************* + * Copyright (C) 2007 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vmblock_version.h -- + * + * Version definitions for the Linux vmblock driver. + */ + +#ifndef _VMBLOCK_VERSION_H_ +#define _VMBLOCK_VERSION_H_ + +#define VMBLOCK_DRIVER_VERSION 1.1.2.0 +#define VMBLOCK_DRIVER_VERSION_COMMAS 1,1,2,0 +#define VMBLOCK_DRIVER_VERSION_STRING "1.1.2.0" + +#endif /* _VMBLOCK_VERSION_H_ */ --- /dev/null +++ b/drivers/vmware/vmblock/vmware.h @@ -0,0 +1,58 @@ +/********************************************************* + * Copyright (C) 2003 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *********************************************************/ + +/* + * vmware.h -- + * + * Standard include file for VMware source code. + */ + +#ifndef _VMWARE_H_ +#define _VMWARE_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_DISTRIBUTE +//#include "includeCheck.h" + +#include "vm_basic_types.h" +#include "vm_basic_defs.h" +#include "vm_assert.h" + +/* + * Global error codes. Currently used internally, but may be exported + * to customers one day, like VM_E_XXX in vmcontrol_constants.h + */ + +typedef enum VMwareStatus { + VMWARE_STATUS_SUCCESS, /* success */ + VMWARE_STATUS_ERROR, /* generic error */ + VMWARE_STATUS_NOMEM, /* generic memory allocation error */ + VMWARE_STATUS_INSUFFICIENT_RESOURCES, /* internal or system resource limit exceeded */ + VMWARE_STATUS_INVALID_ARGS /* invalid arguments */ +} VMwareStatus; + +#define VMWARE_SUCCESS(s) ((s) == VMWARE_STATUS_SUCCESS) + + +#endif // ifndef _VMWARE_H_