vboxfs_vnode.c revision f001425d2b0a661d4cd1f7ea07b4e7454538c829
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * VirtualBox File System for Solaris Guests, vnode implementation.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Portions contributed by: Ronald.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright (C) 2009-2010 Oracle Corporation
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This file is part of VirtualBox Open Source Edition (OSE), as
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * available from http://www.virtualbox.org. This file is free software;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * you can redistribute it and/or modify it under the terms of the GNU
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * General Public License (GPL) as published by the Free Software
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Foundation, in version 2 as it comes in the "COPYING" file of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The contents of this file may alternatively be used under the terms
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * of the Common Development and Distribution License Version 1.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * VirtualBox OSE distribution, in which case the provisions of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * CDDL are applicable instead of those of the GPL.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * You may elect to license modified versions of this file under the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * terms and conditions of either the GPL or the CDDL or both.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Shared Folder File System is used from Solaris when run as a guest operating
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * system on VirtualBox, though is meant to be usable with any hypervisor that
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * can provide similar functionality. The sffs code handles all the Solaris
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * specific semantics and relies on a provider module to actually access
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * directories, files, etc. The provider interfaces are described in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * "vboxfs_prov.h" and the module implementing them is shipped as part of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * VirtualBox Guest Additions for Solaris.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The shared folder file system is similar to a networked file system,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * but with some caveats. The sffs code caches minimal information and proxies
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * out to the provider whenever possible. Here are some things that are
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * handled in this code and not by the proxy:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * - a way to open ".." from any already open directory
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * - st_ino numbers
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * - detecting directory changes that happened on the host.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The implementation builds a cache of information for every file/directory
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * ever accessed in all mounted sffs filesystems using sf_node structures.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This information for both open or closed files can become invalid if
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * asynchronous changes are made on the host. Solaris should not panic() in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * this event, but some file system operations may return unexpected errors.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Information for such directories or files while they have active vnodes
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * is removed from the regular cache and stored in a "stale" bucket until
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the vnode becomes completely inactive.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * No file data is cached in the guest. This means we don't support mmap() yet.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * A future version could relatively easily add support for read-only
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * mmap(MAP_SHARED) and any mmap(MAP_PRIVATE). But a la ZFS, this data caching
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * would not be coherent with normal simultaneous read()/write() operations,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * nor will it be coherent with data access on the host. Writable
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * mmap(MAP_SHARED) access is possible, but guaranteeing any kind of coherency
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * with concurrent activity on the host would be near impossible with the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * existing interfaces.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * A note about locking. sffs is not a high performance file system.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * No fine grained locking is done. The one sffs_lock protects just about
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * everything.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * For now we'll use an I/O buffer that doesn't page fault for VirtualBox
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * to transfer data into.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * sfnode_compare() is needed for AVL tree functionality.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The nodes are sorted by mounted filesystem, then path. If the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * nodes are stale, the node pointer itself is used to force uniqueness.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersfnode_compare(const void *a, const void *b)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster diff = (uintptr_t)y->sf_sffs - (uintptr_t)x->sf_sffs;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return (-1);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Construct a new pathname given an sfnode plus an optional tail component.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This handles ".." and "."
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic char *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersfnode_construct_path(sfnode_t *node, char *tail)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (strcmp(tail, ".") == 0 || strcmp(tail, "..") == 0)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster p = kmem_alloc(strlen(node->sf_path) + 1 + strlen(tail) + 1, KM_SLEEP);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Clears the (cached) directory listing for the node.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster sffs_dirents_t *next = node->sf_dir_list->sf_next;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster kmem_free(node->sf_dir_list, SFFS_DIRENTS_SIZE);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster sffs_stats_t *next = node->sf_dir_stats->sf_next;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster kmem_free(node->sf_dir_stats, sizeof(*node->sf_dir_stats));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Open the provider file associated with a vnode. Holding the file open is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the only way we have of trying to have a vnode continue to refer to the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * same host file in the host in light of the possibility of host side renames.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster error = sfprov_open(node->sf_sffs->sf_handle, node->sf_path, &fp);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * get a new vnode reference for an sfnode
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster LogFlowFunc((" %s gets vnode 0x%p\n", node->sf_path, vp));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Allocate and initialize a new sfnode and assign it a vnode
if (parent)
return (node);
top:
goto top;
sfnode_t *n;
int len;
n = node;
sfnode_destroy(n);
n->sf_path);
static uint64_t
sfnode_cur_time_usec(void)
int error;
if (error == 0)
return (error);
sfnode_t *n;
int old_len;
char *new_path;
char *tail;
if (n != NULL)
KM_SLEEP);
n->sf_path);
n->sf_path);
static sfnode_t *
char *name,
int *err)
int error = 0;
int type;
char *fullpath;
if (err)
return (dir);
return (NULL);
return (node);
mode_t m;
error = 0;
if (error != 0)
else if (S_ISDIR(m))
else if (S_ISREG(m))
if (err)
if (error) {
return (NULL);
return (node);
mode_t m;
int shift = 0;
int error;
error = 0;
if (mode == 0) {
error = 0;
return (error);
int *eofp,
int flags)
int cur_snum;
int dummy_eof;
int error = 0;
return (EINVAL);
return (ENOTDIR);
*eofp = 0;
if (error != 0)
goto done;
offset = 0;
cur_snum = 0;
cur_snum = 0;
++cur_snum;
if (error != 0)
done:
return (error);
#if defined(VBOX_VFS_SOLARIS_10U6)
int cmd,
int cmd,
int flags,
int error = 0;
if (error != 0)
goto done;
done:
return (error);
int flags,
int error;
return (error);
int cmd,
int flags,
int error;
return ENOSYS;
return (error);
int ioflag,
int error = 0;
return (EISDIR);
return (EINVAL);
return (EINVAL);
if (total == 0)
return (EINVAL);
error = 0;
return (error);
int ioflag,
int error = 0;
return (EISDIR);
return (EINVAL);
return (EINVAL);
if (error != 0) {
return (error);
return (EINVAL);
p, RCA_UNSAFE_SIGINFO);
return (EFBIG);
return (EFBIG);
if (total == 0) {
if (error != 0)
if (error == 0)
error = 0;
return (error);
int error;
return (error);
int flags,
int *direntflags,
int error;
return (ENOTDIR);
if (error) {
return (error);
char *name,
int mode,
int flag,
int error;
return (EISDIR);
return (EINVAL);
else if (error != 0)
return (error);
return (EEXIST);
return (EISDIR);
if (error != 0) {
return (error);
if (error) {
return (error);
return (EEXIST);
int lookuperr;
if (error)
return (lookuperr);
char *nm,
int flags,
int error;
if (error == 0) {
return (EEXIST);
return (error);
if (error) {
return (error);
if (error)
return (lookuperr);
char *nm,
int flags)
int error;
return (EINVAL);
return (EEXIST);
if (error)
return (error);
return (ENOTDIR);
return (EBUSY);
return (EBUSY);
if (error)
goto done;
goto done;
done:
return (error);
char *name,
int flags)
int error;
if (error)
return (error);
if (error)
goto done;
goto done;
done:
return (error);
char *old_nm,
char *new_nm,
int flags)
char *newpath;
int error;
return (EINVAL);
if (error)
goto done;
goto done;
if (error == 0)
done:
return (error);
int error;
error = 0;
return (error);
#if defined(VBOX_VFS_SOLARIS_10U6)
int flag,
int count,
return (EINVAL);
return (ENOTSUP);
#if defined(VBOX_VFS_SOLARIS_10U6)
sffs_vnode_init(void)
int err;
if (err)
return (err);
sffs_vnode_fini(void)
if (sffs_ops)
sfnode_t *n;
sfnode_print(n);
sfnode_print(n);