All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hans de Goede <hdegoede@redhat.com>
To: Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Hans de Goede <hdegoede@redhat.com>,
	Michael Thayer <michael.thayer@oracle.com>,
	"Knut St . Osmundsen" <knut.osmundsen@oracle.com>,
	Larry Finger <Larry.Finger@lwfinger.net>,
	linux-kernel@vger.kernel.org
Subject: [RFC v2 2/2] fs: Add VirtualBox guest shared folder (vboxsf) support
Date: Fri, 25 Aug 2017 16:37:32 +0200	[thread overview]
Message-ID: <20170825143732.10836-3-hdegoede@redhat.com> (raw)
In-Reply-To: <20170825143732.10836-1-hdegoede@redhat.com>

VirtualBox hosts can share folders with guests, this commit adds a
VFS driver implementing the Linux-guest side of this, allowing folders
exported by the host to be mounted under Linux.

This driver depends on the guest <-> host IPC functions exported by
the vboxguest driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 fs/Kconfig                     |    1 +
 fs/Makefile                    |    1 +
 fs/vboxsf/Kconfig              |    9 +
 fs/vboxsf/Makefile             |    3 +
 fs/vboxsf/dirops.c             |  705 ++++++++++++++++++++++
 fs/vboxsf/lnkops.c             |   37 ++
 fs/vboxsf/regops.c             |  558 +++++++++++++++++
 fs/vboxsf/shfl_hostintf.h      | 1283 ++++++++++++++++++++++++++++++++++++++++
 fs/vboxsf/utils.c              |  674 +++++++++++++++++++++
 fs/vboxsf/vboxsf_wrappers.c    |  519 ++++++++++++++++
 fs/vboxsf/vboxsf_wrappers.h    |   98 +++
 fs/vboxsf/vfsmod.c             |  386 ++++++++++++
 fs/vboxsf/vfsmod.h             |  113 ++++
 include/uapi/linux/vbsfmount.h |   62 ++
 14 files changed, 4449 insertions(+)
 create mode 100644 fs/vboxsf/Kconfig
 create mode 100644 fs/vboxsf/Makefile
 create mode 100644 fs/vboxsf/dirops.c
 create mode 100644 fs/vboxsf/lnkops.c
 create mode 100644 fs/vboxsf/regops.c
 create mode 100644 fs/vboxsf/shfl_hostintf.h
 create mode 100644 fs/vboxsf/utils.c
 create mode 100644 fs/vboxsf/vboxsf_wrappers.c
 create mode 100644 fs/vboxsf/vboxsf_wrappers.h
 create mode 100644 fs/vboxsf/vfsmod.c
 create mode 100644 fs/vboxsf/vfsmod.h
 create mode 100644 include/uapi/linux/vbsfmount.h

diff --git a/fs/Kconfig b/fs/Kconfig
index 7aee6d699fd6..7f80ad1cf591 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -248,6 +248,7 @@ source "fs/pstore/Kconfig"
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 source "fs/exofs/Kconfig"
+source "fs/vboxsf/Kconfig"
 
 endif # MISC_FILESYSTEMS
 
diff --git a/fs/Makefile b/fs/Makefile
index 7bbaca9c67b1..6b5039e3ade5 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -128,3 +128,4 @@ obj-y				+= exofs/ # Multiple modules
 obj-$(CONFIG_CEPH_FS)		+= ceph/
 obj-$(CONFIG_PSTORE)		+= pstore/
 obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
+obj-$(CONFIG_VBOXSF_FS)		+= vboxsf/
diff --git a/fs/vboxsf/Kconfig b/fs/vboxsf/Kconfig
new file mode 100644
index 000000000000..620e2232969c
--- /dev/null
+++ b/fs/vboxsf/Kconfig
@@ -0,0 +1,9 @@
+config VBOXSF_FS
+	tristate "VirtualBox guest shared folder (vboxsf) support"
+	depends on VBOXGUEST
+	help
+	  VirtualBox hosts can share folders with guests, this driver
+	  implements the Linux-guest side of this allowing folders exported
+	  by the host to be mounted under Linux.
+
+	  If you want to use shared folders in VirtualBox guests, answer Y or M.
diff --git a/fs/vboxsf/Makefile b/fs/vboxsf/Makefile
new file mode 100644
index 000000000000..f3529ea02d5c
--- /dev/null
+++ b/fs/vboxsf/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VBOXSF_FS) += vboxsf.o
+
+vboxsf-objs := dirops.o lnkops.o regops.o utils.o vboxsf_wrappers.o vfsmod.o
diff --git a/fs/vboxsf/dirops.c b/fs/vboxsf/dirops.c
new file mode 100644
index 000000000000..20b9a5b14dbb
--- /dev/null
+++ b/fs/vboxsf/dirops.c
@@ -0,0 +1,705 @@
+/*
+ * VirtualBox Guest Shared Folders support: Directory inode and file operations
+ *
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/vbox_err.h>
+#include <linux/vbox_utils.h>
+#include "vfsmod.h"
+
+/**
+ * Open a directory. Read the complete content into a buffer.
+ *
+ * @param inode     inode
+ * @param file      file
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_dir_open(struct inode *inode, struct file *file)
+{
+	int rc;
+	int err;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_dir_info *sf_d;
+	struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+	struct shfl_createparms params = {};
+
+	if (file->private_data)
+		return 0;
+
+	sf_d = sf_dir_info_alloc();
+	if (!sf_d)
+		return -ENOMEM;
+
+	params.handle = SHFL_HANDLE_NIL;
+	params.create_flags = 0
+	    | SHFL_CF_DIRECTORY
+	    | SHFL_CF_ACT_OPEN_IF_EXISTS
+	    | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
+
+	rc = vboxsf_create(sf_g->root, sf_i->path, &params);
+	if (rc >= 0) {
+		if (params.result == SHFL_FILE_EXISTS) {
+			err = sf_dir_read_all(sf_g, sf_i, sf_d, params.handle);
+			if (!err)
+				file->private_data = sf_d;
+		} else
+			err = -ENOENT;
+
+		vboxsf_close(sf_g->root, params.handle);
+	} else
+		err = -EPERM;
+
+	if (err)
+		sf_dir_info_free(sf_d);
+
+	return err;
+}
+
+/**
+ * This is called when reference count of [file] goes to zero. Notify
+ * the host that it can free whatever is associated with this directory
+ * and deallocate our own internal buffers
+ *
+ * @param inode     inode
+ * @param file      file
+ * returns 0 on success, Linux error code otherwise
+ */
+static int sf_dir_release(struct inode *inode, struct file *file)
+{
+	if (file->private_data)
+		sf_dir_info_free(file->private_data);
+
+	return 0;
+}
+
+/**
+ * Translate RTFMODE into DT_xxx (in conjunction to rtDirType())
+ * @param mode     file mode
+ * returns d_type
+ */
+static int sf_get_d_type(u32 mode)
+{
+	int d_type;
+
+	switch (mode & SHFL_TYPE_MASK) {
+	case SHFL_TYPE_FIFO:
+		d_type = DT_FIFO;
+		break;
+	case SHFL_TYPE_DEV_CHAR:
+		d_type = DT_CHR;
+		break;
+	case SHFL_TYPE_DIRECTORY:
+		d_type = DT_DIR;
+		break;
+	case SHFL_TYPE_DEV_BLOCK:
+		d_type = DT_BLK;
+		break;
+	case SHFL_TYPE_FILE:
+		d_type = DT_REG;
+		break;
+	case SHFL_TYPE_SYMLINK:
+		d_type = DT_LNK;
+		break;
+	case SHFL_TYPE_SOCKET:
+		d_type = DT_SOCK;
+		break;
+	case SHFL_TYPE_WHITEOUT:
+		d_type = DT_WHT;
+		break;
+	default:
+		d_type = DT_UNKNOWN;
+		break;
+	}
+	return d_type;
+}
+
+/**
+ * Extract element ([dir]->f_pos) from the directory [dir] into [d_name].
+ *
+ * @returns 0 for success, 1 for end reached, Linux error code otherwise.
+ */
+static int sf_getdent(struct file *dir, char d_name[NAME_MAX], int *d_type)
+{
+	loff_t cur;
+	struct sf_glob_info *sf_g;
+	struct sf_dir_info *sf_d;
+	struct sf_inode_info *sf_i;
+	struct inode *inode;
+	struct list_head *pos, *list;
+
+	inode = GET_F_DENTRY(dir)->d_inode;
+	sf_i = GET_INODE_INFO(inode);
+	sf_g = GET_GLOB_INFO(inode->i_sb);
+	sf_d = dir->private_data;
+
+	if (sf_i->force_reread) {
+		int rc;
+		int err;
+		struct shfl_createparms params = {};
+
+		params.handle = SHFL_HANDLE_NIL;
+		params.create_flags = 0
+		    | SHFL_CF_DIRECTORY
+		    | SHFL_CF_ACT_OPEN_IF_EXISTS
+		    | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
+
+		rc = vboxsf_create(sf_g->root, sf_i->path, &params);
+		if (rc < 0)
+			return -EPERM;
+
+		if (params.result != SHFL_FILE_EXISTS) {
+			sf_dir_info_free(sf_d);
+			return -ENOENT;
+		}
+
+		sf_dir_info_empty(sf_d);
+		err = sf_dir_read_all(sf_g, sf_i, sf_d, params.handle);
+		vboxsf_close(sf_g->root, params.handle);
+		if (err)
+			return err;
+
+		sf_i->force_reread = 0;
+	}
+
+	cur = 0;
+	list = &sf_d->info_list;
+	list_for_each(pos, list) {
+		struct sf_dir_buf *b;
+		struct shfl_dirinfo *info;
+		loff_t i;
+
+		b = list_entry(pos, struct sf_dir_buf, head);
+		if (dir->f_pos >= cur + b->entries) {
+			cur += b->entries;
+			continue;
+		}
+
+		for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i) {
+			size_t size;
+
+			size = offsetof(struct shfl_dirinfo, name.string) +
+			       info->name.size;
+			info = (struct shfl_dirinfo *)((uintptr_t) info + size);
+		}
+
+		*d_type = sf_get_d_type(info->info.attr.mode);
+
+		return sf_nlscpy(sf_g, d_name, NAME_MAX,
+				 info->name.string.utf8, info->name.length);
+	}
+
+	return 1;
+}
+
+/**
+ * This is called when vfs wants to populate internal buffers with
+ * directory [dir]s contents. [opaque] is an argument to the
+ * [filldir]. [filldir] magically modifies it's argument - [opaque]
+ * and takes following additional arguments (which i in turn get from
+ * the host via sf_getdent):
+ *
+ * name : name of the entry (i must also supply it's length huh?)
+ * type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
+ * pos : position/index of the entry
+ * ino : inode number of the entry (i fake those)
+ *
+ * [dir] contains:
+ * f_pos : cursor into the directory listing
+ * private_data : mean of communication with the host side
+ *
+ * Extract elements from the directory listing (incrementing f_pos
+ * along the way) and feed them to [filldir] until:
+ *
+ * a. there are no more entries (i.e. sf_getdent set done to 1)
+ * b. failure to compute fake inode number
+ * c. filldir returns an error (see comment on that)
+ */
+static int sf_dir_iterate(struct file *dir, struct dir_context *ctx)
+{
+	for (;;) {
+		int err;
+		ino_t fake_ino;
+		loff_t sanity;
+		char d_name[NAME_MAX];
+		int d_type = DT_UNKNOWN;
+
+		err = sf_getdent(dir, d_name, &d_type);
+		switch (err) {
+		case 1:
+			return 0;
+
+		case 0:
+			break;
+
+		case -1:
+		default:
+			/* skip erroneous entry and proceed */
+			dir->f_pos += 1;
+			ctx->pos += 1;
+			continue;
+		}
+
+		/* d_name now contains a valid entry name */
+		sanity = ctx->pos + 0xbeef;
+		fake_ino = sanity;
+		/*
+		 * On 32 bit systems pos is 64 signed, while ino is 32 bit
+		 * unsigned so fake_ino may overflow, check for this.
+		 */
+		if (sanity - fake_ino) {
+			vbg_err("vboxsf: can not compute ino\n");
+			return -EINVAL;
+		}
+		if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, d_type))
+			return 0;
+
+		dir->f_pos += 1;
+		ctx->pos += 1;
+	}
+}
+
+const struct file_operations sf_dir_fops = {
+	.open = sf_dir_open,
+	.iterate = sf_dir_iterate,
+	.release = sf_dir_release,
+	.read = generic_read_dir,
+	.llseek = generic_file_llseek,
+};
+
+/* iops */
+
+/**
+ * This is called when vfs failed to locate dentry in the cache. The
+ * job of this function is to allocate inode and link it to dentry.
+ * [dentry] contains the name to be looked in the [parent] directory.
+ * Failure to locate the name is not a "hard" error, in this case NULL
+ * inode is added to [dentry] and vfs should proceed trying to create
+ * the entry via other means. NULL(or "positive" pointer) ought to be
+ * returned in case of success and "negative" pointer on error
+ */
+static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry,
+				unsigned int flags)
+{
+	int err;
+	struct sf_inode_info *sf_i, *sf_new_i;
+	struct sf_glob_info *sf_g;
+	struct shfl_string *path;
+	struct inode *inode;
+	ino_t ino;
+	struct shfl_fsobjinfo fsinfo;
+
+	sf_g = GET_GLOB_INFO(parent->i_sb);
+	sf_i = GET_INODE_INFO(parent);
+
+	err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+	if (err)
+		goto fail0;
+
+	err = sf_stat(__func__, sf_g, path, &fsinfo, 1);
+	if (err) {
+		if (err == -ENOENT) {
+			/*
+			 * -ENOENT: add NULL inode to dentry so it later can
+			 * be created via call to create/mkdir/open
+			 */
+			kfree(path);
+			inode = NULL;
+		} else {
+			goto fail1;
+		}
+	} else {
+		sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
+		if (!sf_new_i) {
+			err = -ENOMEM;
+			goto fail1;
+		}
+		sf_new_i->handle = SHFL_HANDLE_NIL;
+		sf_new_i->force_reread = 0;
+
+		ino = iunique(parent->i_sb, 1);
+		inode = iget_locked(parent->i_sb, ino);
+		if (!inode) {
+			err = -ENOMEM;	/* XXX: ??? */
+			goto fail2;
+		}
+
+		SET_INODE_INFO(inode, sf_new_i);
+		sf_init_inode(sf_g, inode, &fsinfo);
+		sf_new_i->path = path;
+
+		unlock_new_inode(inode);
+	}
+
+	sf_i->force_restat = 0;
+	dentry->d_time = jiffies;
+	d_set_d_op(dentry, &sf_dentry_ops);
+	d_add(dentry, inode);
+	return NULL;
+
+fail2:
+	kfree(sf_new_i);
+
+fail1:
+	kfree(path);
+
+fail0:
+	return ERR_PTR(err);
+}
+
+/**
+ * This should allocate memory for sf_inode_info, compute a unique inode
+ * number, get an inode from vfs, initialize inode info, instantiate
+ * dentry.
+ *
+ * @param parent        inode entry of the directory
+ * @param dentry        directory cache entry
+ * @param path          path name
+ * @param info          file information
+ * @param handle        handle
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_instantiate(struct inode *parent, struct dentry *dentry,
+			  struct shfl_string *path, struct shfl_fsobjinfo *info,
+			  SHFLHANDLE handle)
+{
+	int err;
+	ino_t ino;
+	struct inode *inode;
+	struct sf_inode_info *sf_new_i;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
+
+	sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
+	if (!sf_new_i) {
+		err = -ENOMEM;
+		goto fail0;
+	}
+
+	ino = iunique(parent->i_sb, 1);
+	inode = iget_locked(parent->i_sb, ino);
+	if (!inode) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	sf_init_inode(sf_g, inode, info);
+	sf_new_i->path = path;
+	SET_INODE_INFO(inode, sf_new_i);
+	sf_new_i->force_restat = 1;
+	sf_new_i->force_reread = 0;
+
+	d_instantiate(dentry, inode);
+	unlock_new_inode(inode);
+
+	/* Store this handle if we leave the handle open. */
+	sf_new_i->handle = handle;
+	return 0;
+
+fail1:
+	kfree(sf_new_i);
+
+fail0:
+	return err;
+
+}
+
+/**
+ * Create a new regular file / directory.
+ *
+ * @param parent        inode of the directory
+ * @param dentry        directory cache entry
+ * @param mode          file mode
+ * @param fDirectory    true if directory, false otherwise
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_create_aux(struct inode *parent, struct dentry *dentry,
+			 umode_t mode, int fDirectory)
+{
+	int rc, err;
+	struct shfl_createparms params = {};
+	struct shfl_string *path;
+	struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
+
+	err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+	if (err)
+		goto fail0;
+
+	params.handle = SHFL_HANDLE_NIL;
+	params.create_flags = 0
+	    | SHFL_CF_ACT_CREATE_IF_NEW
+	    | SHFL_CF_ACT_FAIL_IF_EXISTS
+	    | SHFL_CF_ACCESS_READWRITE | (fDirectory ? SHFL_CF_DIRECTORY : 0);
+	params.info.attr.mode = 0
+	    | (fDirectory ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE)
+	    | (mode & 0777);
+	params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING;
+
+	rc = vboxsf_create(sf_g->root, path, &params);
+	if (rc < 0) {
+		if (rc == VERR_WRITE_PROTECT) {
+			err = -EROFS;
+			goto fail1;
+		}
+		err = -EPROTO;
+		goto fail1;
+	}
+
+	if (params.result != SHFL_FILE_CREATED) {
+		err = -EPERM;
+		goto fail1;
+	}
+
+	err = sf_instantiate(parent, dentry, path, &params.info,
+			     fDirectory ? SHFL_HANDLE_NIL : params.handle);
+	if (err)
+		goto fail2;
+
+	/*
+	 * Don't close this handle right now. We assume that the same file is
+	 * opened with sf_reg_open() and later closed with sf_reg_close(). Save
+	 * the handle in between. Does not apply to directories. True?
+	 */
+	if (fDirectory)
+		vboxsf_close(sf_g->root, params.handle);
+
+	sf_i->force_restat = 1;
+	return 0;
+
+fail2:
+	vboxsf_close(sf_g->root, params.handle);
+
+fail1:
+	kfree(path);
+
+fail0:
+	return err;
+}
+
+/**
+ * Create a new regular file.
+ *
+ * @param parent        inode of the directory
+ * @param dentry        directory cache entry
+ * @param mode          file mode
+ * @param excl          Possible O_EXCL...
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode,
+		     bool excl)
+{
+	return sf_create_aux(parent, dentry, mode, 0);
+}
+
+/**
+ * Create a new directory.
+ *
+ * @param parent        inode of the directory
+ * @param dentry        directory cache entry
+ * @param mode          file mode
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
+{
+	return sf_create_aux(parent, dentry, mode, 1);
+}
+
+/**
+ * Remove a regular file / directory.
+ *
+ * @param parent        inode of the directory
+ * @param dentry        directory cache entry
+ * @param fDirectory    true if directory, false otherwise
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_unlink_aux(struct inode *parent, struct dentry *dentry,
+			 int fDirectory)
+{
+	int rc, err;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
+	struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
+	struct shfl_string *path;
+	uint32_t flags;
+
+	err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+	if (err)
+		goto fail0;
+
+	flags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
+	if (dentry
+	    && dentry->d_inode
+	    && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
+		flags |= SHFL_REMOVE_SYMLINK;
+	rc = vboxsf_remove(sf_g->root, path, flags);
+	if (rc < 0) {
+		err = vbg_status_code_to_errno(rc);
+		goto fail1;
+	}
+
+	/* directory access/change time changed */
+	sf_i->force_restat = 1;
+	/* directory content changed */
+	sf_i->force_reread = 1;
+
+	err = 0;
+
+fail1:
+	kfree(path);
+
+fail0:
+	return err;
+}
+
+/**
+ * Remove a regular file.
+ *
+ * @param parent        inode of the directory
+ * @param dentry        directory cache entry
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_unlink(struct inode *parent, struct dentry *dentry)
+{
+	return sf_unlink_aux(parent, dentry, 0);
+}
+
+/**
+ * Remove a directory.
+ *
+ * @param parent        inode of the directory
+ * @param dentry        directory cache entry
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_rmdir(struct inode *parent, struct dentry *dentry)
+{
+	return sf_unlink_aux(parent, dentry, 1);
+}
+
+/**
+ * Rename a regular file / directory.
+ *
+ * @param old_parent    inode of the old parent directory
+ * @param old_dentry    old directory cache entry
+ * @param new_parent    inode of the new parent directory
+ * @param new_dentry    new directory cache entry
+ * @param flags         flags
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
+		     struct inode *new_parent, struct dentry *new_dentry,
+		     unsigned int flags)
+{
+	int err = 0, rc = VINF_SUCCESS;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb);
+	u32 shfl_flags = SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS;
+
+	if (flags)
+		return -EINVAL;
+
+	if (sf_g != GET_GLOB_INFO(new_parent->i_sb)) {
+		err = -EINVAL;
+	} else {
+		struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent);
+		struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent);
+		/*
+		 * As we save the relative path inside the inode structure,
+		 * we need to change this if the rename is successful.
+		 */
+		struct sf_inode_info *sf_file_i =
+		    GET_INODE_INFO(old_dentry->d_inode);
+		struct shfl_string *old_path;
+		struct shfl_string *new_path;
+
+		old_path = sf_file_i->path;
+		err = sf_path_from_dentry(__func__, sf_g, sf_new_i,
+					  new_dentry, &new_path);
+		if (err == 0) {
+			if (old_dentry->d_inode->i_mode & S_IFDIR)
+				shfl_flags = 0;
+
+			rc = vboxsf_rename(sf_g->root, old_path, new_path,
+					   shfl_flags);
+			if (rc >= 0) {
+				kfree(old_path);
+				sf_new_i->force_restat = 1;
+				sf_old_i->force_restat = 1; /* XXX: needed? */
+				/* Set the new relative path in the inode. */
+				sf_file_i->path = new_path;
+			} else {
+				err = vbg_status_code_to_errno(rc);
+				kfree(new_path);
+			}
+		}
+	}
+	return err;
+}
+
+static int sf_symlink(struct inode *parent, struct dentry *dentry,
+		      const char *symname)
+{
+	int err;
+	int rc;
+	struct sf_inode_info *sf_i;
+	struct sf_glob_info *sf_g;
+	struct shfl_string *path, *ssymname;
+	struct shfl_fsobjinfo info;
+	int symname_len = strlen(symname) + 1;
+
+	sf_g = GET_GLOB_INFO(parent->i_sb);
+	sf_i = GET_INODE_INFO(parent);
+
+	err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
+	if (err)
+		goto fail0;
+
+	ssymname =
+	    kmalloc(offsetof(struct shfl_string, string.utf8) + symname_len,
+		    GFP_KERNEL);
+	if (!ssymname) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	ssymname->length = symname_len - 1;
+	ssymname->size = symname_len;
+	memcpy(ssymname->string.utf8, symname, symname_len);
+
+	rc = vboxsf_symlink(sf_g->root, path, ssymname, &info);
+	kfree(ssymname);
+
+	if (rc < 0) {
+		if (rc == VERR_WRITE_PROTECT) {
+			err = -EROFS;
+			goto fail1;
+		}
+		err = -EPROTO;
+		goto fail1;
+	}
+
+	err = sf_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
+	if (err)
+		goto fail1;
+
+	sf_i->force_restat = 1;
+	return 0;
+
+fail1:
+	kfree(path);
+fail0:
+	return err;
+}
+
+const struct inode_operations sf_dir_iops = {
+	.lookup = sf_lookup,
+	.create = sf_create,
+	.mkdir = sf_mkdir,
+	.rmdir = sf_rmdir,
+	.unlink = sf_unlink,
+	.rename = sf_rename,
+	.getattr = sf_getattr,
+	.setattr = sf_setattr,
+	.symlink = sf_symlink
+};
diff --git a/fs/vboxsf/lnkops.c b/fs/vboxsf/lnkops.c
new file mode 100644
index 000000000000..da4cbfa3c886
--- /dev/null
+++ b/fs/vboxsf/lnkops.c
@@ -0,0 +1,37 @@
+/*
+ * VirtualBox Guest Shared Folders: Operations for symbolic links.
+ *
+ * Copyright (C) 2010-2016 Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "vfsmod.h"
+
+static const char *sf_get_link(struct dentry *dentry, struct inode *inode,
+			       struct delayed_call *done)
+{
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+	char *path;
+	int rc;
+
+	if (!dentry)
+		return ERR_PTR(-ECHILD);
+	path = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!path)
+		return ERR_PTR(-ENOMEM);
+	rc = vboxsf_readlink(sf_g->root, sf_i->path, PATH_MAX, path);
+	if (rc < 0) {
+		kfree(path);
+		return ERR_PTR(-EPROTO);
+	}
+	set_delayed_call(done, kfree_link, path);
+	return path;
+}
+
+const struct inode_operations sf_lnk_iops = {
+	.get_link = sf_get_link
+};
diff --git a/fs/vboxsf/regops.c b/fs/vboxsf/regops.c
new file mode 100644
index 000000000000..879793065f7e
--- /dev/null
+++ b/fs/vboxsf/regops.c
@@ -0,0 +1,558 @@
+/*
+ * VirtualBox Guest Shared Folders support: Regular file inode and file ops.
+ *
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Limitations: only COW memory mapping is supported
+ */
+
+#include <linux/vbox_utils.h>
+#include "vfsmod.h"
+
+static void *alloc_bounce_buffer(size_t *tmp_sizep, u64 *physp, size_t
+				 xfer_size, const char *caller)
+{
+	size_t tmp_size;
+	void *tmp;
+
+	/* try for big first. */
+	tmp_size = PAGE_ALIGN(xfer_size);
+	if (tmp_size > SZ_16K)
+		tmp_size = SZ_16K;
+	tmp = kmalloc(tmp_size, GFP_KERNEL);
+	if (!tmp) {
+		/* fall back on a page sized buffer. */
+		tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!tmp)
+			return NULL;
+		tmp_size = PAGE_SIZE;
+	}
+
+	*tmp_sizep = tmp_size;
+	*physp = virt_to_phys(tmp);
+	return tmp;
+}
+
+static void free_bounce_buffer(void *tmp)
+{
+	kfree(tmp);
+}
+
+/* fops */
+static int sf_reg_read_aux(const char *caller, struct sf_glob_info *sf_g,
+			   struct sf_reg_info *sf_r, void *buf,
+			   u32 *nread, u64 pos)
+{
+	int rc;
+
+	/**
+	 * @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
+	 * contiguous in physical memory (kmalloc or single page), we should
+	 * use a physical address here to speed things up.
+	 */
+	rc = vboxsf_read(sf_g->root, sf_r->handle, pos, nread, buf);
+	if (rc < 0)
+		return -EPROTO;
+
+	return 0;
+}
+
+static int sf_reg_write_aux(const char *caller, struct sf_glob_info *sf_g,
+			    struct sf_reg_info *sf_r, void *buf,
+			    u32 *nwritten, u64 pos)
+{
+	int rc;
+
+	/** @todo bird: see sf_reg_read_aux */
+	rc = vboxsf_write(sf_g->root, sf_r->handle, pos, nwritten, buf);
+	if (rc < 0)
+		return -EPROTO;
+
+	return 0;
+}
+
+/**
+ * Read from a regular file.
+ *
+ * @param file          the file
+ * @param buf           the buffer
+ * @param size          length of the buffer
+ * @param off           offset within the file
+ * @returns the number of read bytes on success, Linux error code otherwise
+ */
+static ssize_t sf_reg_read(struct file *file, char *buf, size_t size,
+			   loff_t *off)
+{
+	int err;
+	void *tmp;
+	u64 tmp_phys;
+	size_t tmp_size;
+	size_t left = size;
+	ssize_t total_bytes_read = 0;
+	struct inode *inode = GET_F_DENTRY(file)->d_inode;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_reg_info *sf_r = file->private_data;
+	loff_t pos = *off;
+
+	if (!S_ISREG(inode->i_mode))
+		return -EINVAL;
+
+	/** XXX Check read permission according to inode->i_mode! */
+
+	if (!size)
+		return 0;
+
+	tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size,
+				  __PRETTY_FUNCTION__);
+	if (!tmp)
+		return -ENOMEM;
+
+	while (left) {
+		u32 to_read, nread;
+
+		to_read = tmp_size;
+		if (to_read > left)
+			to_read = left;
+
+		nread = to_read;
+
+		err = sf_reg_read_aux(__func__, sf_g, sf_r, tmp, &nread, pos);
+		if (err)
+			goto fail;
+
+		if (copy_to_user(buf, tmp, nread)) {
+			err = -EFAULT;
+			goto fail;
+		}
+
+		pos += nread;
+		left -= nread;
+		buf += nread;
+		total_bytes_read += nread;
+		if (nread != to_read)
+			break;
+	}
+
+	*off += total_bytes_read;
+	free_bounce_buffer(tmp);
+	return total_bytes_read;
+
+fail:
+	free_bounce_buffer(tmp);
+	return err;
+}
+
+/**
+ * Write to a regular file.
+ *
+ * @param file          the file
+ * @param buf           the buffer
+ * @param size          length of the buffer
+ * @param off           offset within the file
+ * @returns the number of written bytes on success, Linux error code otherwise
+ */
+static ssize_t sf_reg_write(struct file *file, const char *buf, size_t size,
+			    loff_t *off)
+{
+	int err;
+	void *tmp;
+	u64 tmp_phys;
+	size_t tmp_size;
+	size_t left = size;
+	ssize_t total_bytes_written = 0;
+	struct inode *inode = GET_F_DENTRY(file)->d_inode;
+	struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_reg_info *sf_r = file->private_data;
+	loff_t pos;
+
+	if (!S_ISREG(inode->i_mode))
+		return -EINVAL;
+
+	pos = *off;
+	if (file->f_flags & O_APPEND) {
+		pos = inode->i_size;
+		*off = pos;
+	}
+
+    /** XXX Check write permission according to inode->i_mode! */
+
+	if (!size)
+		return 0;
+
+	tmp =
+	    alloc_bounce_buffer(&tmp_size, &tmp_phys, size,
+				__PRETTY_FUNCTION__);
+	if (!tmp)
+		return -ENOMEM;
+
+	while (left) {
+		u32 to_write, nwritten;
+
+		to_write = tmp_size;
+		if (to_write > left)
+			to_write = (u32) left;
+
+		nwritten = to_write;
+
+		if (copy_from_user(tmp, buf, to_write)) {
+			err = -EFAULT;
+			goto fail;
+		}
+
+		err = vboxsf_write_physcont(sf_g->root, sf_r->handle, pos,
+					    &nwritten, tmp_phys);
+		if (err < 0) {
+			err = -EPROTO;
+			goto fail;
+		}
+
+		pos += nwritten;
+		left -= nwritten;
+		buf += nwritten;
+		total_bytes_written += nwritten;
+		if (nwritten != to_write)
+			break;
+	}
+
+	*off += total_bytes_written;
+	if (*off > inode->i_size)
+		inode->i_size = *off;
+
+	sf_i->force_restat = 1;
+	free_bounce_buffer(tmp);
+	return total_bytes_written;
+
+fail:
+	free_bounce_buffer(tmp);
+	return err;
+}
+
+/**
+ * Open a regular file.
+ *
+ * @param inode         the inode
+ * @param file          the file
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_reg_open(struct inode *inode, struct file *file)
+{
+	int rc, rc_linux = 0;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+	struct sf_reg_info *sf_r;
+	struct shfl_createparms params = {};
+
+	sf_r = kmalloc(sizeof(*sf_r), GFP_KERNEL);
+	if (!sf_r)
+		return -ENOMEM;
+
+	/* Already open? */
+	if (sf_i->handle != SHFL_HANDLE_NIL) {
+		/*
+		 * This inode was created with sf_create_aux(). Check the
+		 * create_flags: O_CREAT, O_TRUNC: inherent true (file was
+		 * just created).
+		 * Not sure about the access flags (SHFL_CF_ACCESS_*).
+		 */
+		sf_i->force_restat = 1;
+		sf_r->handle = sf_i->handle;
+		sf_i->handle = SHFL_HANDLE_NIL;
+		sf_i->file = file;
+		file->private_data = sf_r;
+		return 0;
+	}
+
+	params.handle = SHFL_HANDLE_NIL;
+
+	/*
+	 * We check the value of params.handle afterwards to find out if
+	 * the call succeeded or failed, as the API does not seem to cleanly
+	 * distinguish error and informational messages.
+	 *
+	 * Furthermore, we must set params.handle to SHFL_HANDLE_NIL to
+	 * make the shared folders host service use our mode parameter.
+	 */
+	if (file->f_flags & O_CREAT) {
+		params.create_flags |= SHFL_CF_ACT_CREATE_IF_NEW;
+		/*
+		 * We ignore O_EXCL, as the Linux kernel seems to call create
+		 * beforehand itself, so O_EXCL should always fail.
+		 */
+		if (file->f_flags & O_TRUNC)
+			params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+		else
+			params.create_flags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
+	} else {
+		params.create_flags |= SHFL_CF_ACT_FAIL_IF_NEW;
+		if (file->f_flags & O_TRUNC)
+			params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
+	}
+
+	switch (file->f_flags & O_ACCMODE) {
+	case O_RDONLY:
+		params.create_flags |= SHFL_CF_ACCESS_READ;
+		break;
+
+	case O_WRONLY:
+		params.create_flags |= SHFL_CF_ACCESS_WRITE;
+		break;
+
+	case O_RDWR:
+		params.create_flags |= SHFL_CF_ACCESS_READWRITE;
+		break;
+
+	default:
+		WARN_ON(1);
+	}
+
+	if (file->f_flags & O_APPEND)
+		params.create_flags |= SHFL_CF_ACCESS_APPEND;
+
+	params.info.attr.mode = inode->i_mode;
+	rc = vboxsf_create(sf_g->root, sf_i->path, &params);
+	if (rc < 0) {
+		kfree(sf_r);
+		return vbg_status_code_to_errno(rc);
+	}
+
+	if (params.handle == SHFL_HANDLE_NIL) {
+		switch (params.result) {
+		case SHFL_PATH_NOT_FOUND:
+		case SHFL_FILE_NOT_FOUND:
+			rc_linux = -ENOENT;
+			break;
+		case SHFL_FILE_EXISTS:
+			rc_linux = -EEXIST;
+			break;
+		default:
+			break;
+		}
+	}
+
+	sf_i->force_restat = 1;
+	sf_r->handle = params.handle;
+	sf_i->file = file;
+	file->private_data = sf_r;
+	return rc_linux;
+}
+
+/**
+ * Close a regular file.
+ *
+ * @param inode         the inode
+ * @param file          the file
+ * @returns 0 on success, Linux error code otherwise
+ */
+static int sf_reg_release(struct inode *inode, struct file *file)
+{
+	struct sf_reg_info *sf_r;
+	struct sf_glob_info *sf_g;
+	struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+
+	sf_g = GET_GLOB_INFO(inode->i_sb);
+	sf_r = file->private_data;
+
+	filemap_write_and_wait(inode->i_mapping);
+
+	vboxsf_close(sf_g->root, sf_r->handle);
+
+	kfree(sf_r);
+	sf_i->file = NULL;
+	sf_i->handle = SHFL_HANDLE_NIL;
+	file->private_data = NULL;
+	return 0;
+}
+
+static int sf_reg_fault(struct vm_fault *vmf)
+{
+	struct page *page;
+	char *buf;
+	loff_t off;
+	u32 nread = PAGE_SIZE;
+	int err;
+	struct vm_area_struct *vma = vmf->vma;
+	struct file *file = vma->vm_file;
+	struct inode *inode = GET_F_DENTRY(file)->d_inode;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_reg_info *sf_r = file->private_data;
+
+	if (vmf->pgoff > vma->vm_end)
+		return VM_FAULT_SIGBUS;
+
+	/*
+	 * Don't use GFP_HIGHUSER as long as sf_reg_read_aux() calls
+	 * vboxsf_read() which works on virtual addresses.
+	 */
+	page = alloc_page(GFP_USER);
+	if (!page)
+		return VM_FAULT_OOM;
+
+	buf = kmap(page);
+	off = (vmf->pgoff << PAGE_SHIFT);
+	err = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off);
+	if (err) {
+		kunmap(page);
+		put_page(page);
+		return VM_FAULT_SIGBUS;
+	}
+
+	if (!nread)
+		clear_user_page(page_address(page), vmf->pgoff, page);
+	else
+		memset(buf + nread, 0, PAGE_SIZE - nread);
+
+	flush_dcache_page(page);
+	kunmap(page);
+	vmf->page = page;
+	return 0;
+}
+
+static const struct vm_operations_struct sf_vma_ops = {
+	.fault = sf_reg_fault
+};
+
+static int sf_reg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (vma->vm_flags & VM_SHARED)
+		return -EINVAL;
+
+	vma->vm_ops = &sf_vma_ops;
+	return 0;
+}
+
+const struct file_operations sf_reg_fops = {
+	.read = sf_reg_read,
+	.open = sf_reg_open,
+	.write = sf_reg_write,
+	.release = sf_reg_release,
+	.mmap = sf_reg_mmap,
+	.splice_read = generic_file_splice_read,
+	.read_iter = generic_file_read_iter,
+	.write_iter = generic_file_write_iter,
+	.fsync = noop_fsync,
+	.llseek = generic_file_llseek,
+};
+
+const struct inode_operations sf_reg_iops = {
+	.getattr = sf_getattr,
+	.setattr = sf_setattr
+};
+
+static int sf_readpage(struct file *file, struct page *page)
+{
+	struct inode *inode = GET_F_DENTRY(file)->d_inode;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_reg_info *sf_r = file->private_data;
+	u32 nread = PAGE_SIZE;
+	char *buf;
+	loff_t off = ((loff_t) page->index) << PAGE_SHIFT;
+	int err;
+
+	buf = kmap(page);
+	err = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off);
+	if (err) {
+		kunmap(page);
+		if (PageLocked(page))
+			unlock_page(page);
+		return err;
+	}
+	memset(&buf[nread], 0, PAGE_SIZE - nread);
+	flush_dcache_page(page);
+	kunmap(page);
+	SetPageUptodate(page);
+	unlock_page(page);
+	return 0;
+}
+
+static int sf_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct address_space *mapping = page->mapping;
+	struct inode *inode = mapping->host;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
+	struct file *file = sf_i->file;
+	struct sf_reg_info *sf_r = file->private_data;
+	char *buf;
+	u32 nwritten = PAGE_SIZE;
+	int end_index = inode->i_size >> PAGE_SHIFT;
+	loff_t off = ((loff_t) page->index) << PAGE_SHIFT;
+	int err;
+
+	if (page->index >= end_index)
+		nwritten = inode->i_size & (PAGE_SIZE - 1);
+
+	buf = kmap(page);
+
+	err = sf_reg_write_aux(__func__, sf_g, sf_r, buf, &nwritten, off);
+	if (err < 0) {
+		ClearPageUptodate(page);
+		goto out;
+	}
+
+	if (off > inode->i_size)
+		inode->i_size = off;
+
+	if (PageError(page))
+		ClearPageError(page);
+	err = 0;
+
+out:
+	kunmap(page);
+
+	unlock_page(page);
+	return err;
+}
+
+int sf_write_begin(struct file *file, struct address_space *mapping, loff_t pos,
+		   unsigned int len, unsigned int flags, struct page **pagep,
+		   void **fsdata)
+{
+	return simple_write_begin(file, mapping, pos, len, flags, pagep,
+				  fsdata);
+}
+
+int sf_write_end(struct file *file, struct address_space *mapping, loff_t pos,
+		 unsigned int len, unsigned int copied, struct page *page,
+		 void *fsdata)
+{
+	struct inode *inode = mapping->host;
+	struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
+	struct sf_reg_info *sf_r = file->private_data;
+	unsigned int from = pos & (PAGE_SIZE - 1);
+	u32 nwritten = len;
+	void *buf;
+	int err;
+
+	buf = kmap(page);
+	err =
+	    sf_reg_write_aux(__func__, sf_g, sf_r, buf + from, &nwritten, pos);
+	kunmap(page);
+
+	if (!PageUptodate(page) && err == PAGE_SIZE)
+		SetPageUptodate(page);
+
+	if (err >= 0) {
+		pos += nwritten;
+		if (pos > inode->i_size)
+			inode->i_size = pos;
+	}
+
+	unlock_page(page);
+	put_page(page);
+
+	return nwritten;
+}
+
+const struct address_space_operations sf_reg_aops = {
+	.readpage = sf_readpage,
+	.writepage = sf_writepage,
+	.write_begin = sf_write_begin,
+	.write_end = sf_write_end,
+};
diff --git a/fs/vboxsf/shfl_hostintf.h b/fs/vboxsf/shfl_hostintf.h
new file mode 100644
index 000000000000..42e5509ceb1c
--- /dev/null
+++ b/fs/vboxsf/shfl_hostintf.h
@@ -0,0 +1,1283 @@
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * VirtualBox Shared Folders: host interface definition.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, in which case the provisions of the CDDL are applicable
+ * instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef SHFL_HOSTINTF_H
+#define SHFL_HOSTINTF_H
+
+#include <linux/vbox_vmmdev.h>
+
+/*
+ * We cannot use linux' compiletime_assert here because it expects to be used
+ * inside a function only. Use a typedef to a char array with a negative size.
+ */
+#define VBOXSF_ASSERT_SIZE(type, size) \
+	typedef char type ## _asrt_size[1 - 2*!!(sizeof(struct type) != (size))]
+#define VBOXSF_ASSERT_MEMBER_OFFSET(type, member, offset) \
+	typedef char type ## _ ## member ## _asrt_member_offset \
+	[1 - 2*!!(offsetof(struct type, member) != (offset))]
+
+/**
+ * Structures shared between guest and the service
+ * can be relocated and use offsets to point to variable
+ * length parts.
+ */
+
+/**
+ * Shared folders protocol works with handles.
+ * Before doing any action on a file system object,
+ * one have to obtain the object handle via a SHFL_FN_CREATE
+ * request. A handle must be closed with SHFL_FN_CLOSE.
+ */
+
+/**
+ * Shared Folders service functions. (guest)
+ * @{
+ */
+
+/** Query mappings changes. */
+#define SHFL_FN_QUERY_MAPPINGS      (1)
+/** Query mappings changes. */
+#define SHFL_FN_QUERY_MAP_NAME      (2)
+/** Open/create object. */
+#define SHFL_FN_CREATE              (3)
+/** Close object handle. */
+#define SHFL_FN_CLOSE               (4)
+/** Read object content. */
+#define SHFL_FN_READ                (5)
+/** Write new object content. */
+#define SHFL_FN_WRITE               (6)
+/** Lock/unlock a range in the object. */
+#define SHFL_FN_LOCK                (7)
+/** List object content. */
+#define SHFL_FN_LIST                (8)
+/** Query/set object information. */
+#define SHFL_FN_INFORMATION         (9)
+/** Remove object */
+#define SHFL_FN_REMOVE              (11)
+/** Map folder (legacy) */
+#define SHFL_FN_MAP_FOLDER_OLD      (12)
+/** Unmap folder */
+#define SHFL_FN_UNMAP_FOLDER        (13)
+/** Rename object (possibly moving it to another directory) */
+#define SHFL_FN_RENAME              (14)
+/** Flush file */
+#define SHFL_FN_FLUSH               (15)
+/** @todo macl, a description, please. */
+#define SHFL_FN_SET_UTF8            (16)
+#define SHFL_CPARMS_SET_UTF8        0
+/** Map folder */
+#define SHFL_FN_MAP_FOLDER          (17)
+/** Read symlink destination (as of VBox 4.0) */
+#define SHFL_FN_READLINK            (18)
+/** Create symlink (as of VBox 4.0) */
+#define SHFL_FN_SYMLINK             (19)
+/** Ask host to show symlinks (as of VBox 4.0) */
+#define SHFL_FN_SET_SYMLINKS        (20)
+#define SHFL_CPARMS_SET_SYMLINKS    0
+
+/** @} */
+
+/**
+ * Shared Folders service functions. (host)
+ * @{
+ */
+
+/** Add shared folder mapping. */
+#define SHFL_FN_ADD_MAPPING         (1)
+/** Remove shared folder mapping. */
+#define SHFL_FN_REMOVE_MAPPING      (2)
+/** Set the led status light address. */
+#define SHFL_FN_SET_STATUS_LED      (3)
+/** Allow the guest to create symbolic links (as of VBox 4.0) */
+#define SHFL_FN_ALLOW_SYMLINKS_CREATE (4)
+/** @} */
+
+/**
+ * Root handle for a mapping. Root handles are unique.
+ *  @note
+ *  Function parameters structures consider
+ *  the root handle as 32 bit value. If the typedef
+ *  will be changed, then function parameters must be
+ *  changed accordingly. All those parameters are marked
+ *  with SHFLROOT in comments.
+ */
+#define SHFLROOT u32
+
+#define SHFL_ROOT_NIL ((SHFLROOT)~0)
+
+/** A shared folders handle for an opened object. */
+#define SHFLHANDLE u64
+
+#define SHFL_HANDLE_NIL  ((SHFLHANDLE)~0LL)
+#define SHFL_HANDLE_ROOT ((SHFLHANDLE)0LL)
+
+/** Hardcoded maximum length (in chars) of a shared folder name. */
+#define SHFL_MAX_LEN         (256)
+/** Hardcoded maximum number of shared folder mapping available to the guest. */
+#define SHFL_MAX_MAPPINGS    (64)
+
+/**
+ * @name Shared Folders strings. They can be either UTF-8 or UTF-16.
+ * @{
+ */
+
+/** Shared folder string buffer structure. */
+struct shfl_string {
+	/** Allocated size of the string member in bytes. */
+	u16 size;
+
+	/** Length of string without trailing nul in bytes. */
+	u16 length;
+
+	/** UTF-8 or UTF-16 string. Nul terminated. */
+	union {
+		u8 utf8[1];
+		u16 utf16[1];
+		u16 ucs2[1];  /**< misnomer, use utf16. */
+	} string;
+};
+VBOXSF_ASSERT_SIZE(shfl_string, 6);
+VBOXSF_ASSERT_MEMBER_OFFSET(shfl_string, string, 4);
+
+/** The size of shfl_string w/o the string part. */
+#define SHFLSTRING_HEADER_SIZE  4
+
+/** Calculate size of the string. */
+static inline u32 shfl_string_buf_size(const struct shfl_string *string)
+{
+	return string ? SHFLSTRING_HEADER_SIZE + string->size : 0;
+}
+
+/** @} */
+
+/** Set user id on execution (S_ISUID). */
+#define SHFL_UNIX_ISUID             0004000U
+/** Set group id on execution (S_ISGID). */
+#define SHFL_UNIX_ISGID             0002000U
+/** Sticky bit (S_ISVTX / S_ISTXT). */
+#define SHFL_UNIX_ISTXT             0001000U
+
+/** Owner readable (S_IRUSR). */
+#define SHFL_UNIX_IRUSR             0000400U
+/** Owner writable (S_IWUSR). */
+#define SHFL_UNIX_IWUSR             0000200U
+/** Owner executable (S_IXUSR). */
+#define SHFL_UNIX_IXUSR             0000100U
+
+/** Group readable (S_IRGRP). */
+#define SHFL_UNIX_IRGRP             0000040U
+/** Group writable (S_IWGRP). */
+#define SHFL_UNIX_IWGRP             0000020U
+/** Group executable (S_IXGRP). */
+#define SHFL_UNIX_IXGRP             0000010U
+
+/** Other readable (S_IROTH). */
+#define SHFL_UNIX_IROTH             0000004U
+/** Other writable (S_IWOTH). */
+#define SHFL_UNIX_IWOTH             0000002U
+/** Other executable (S_IXOTH). */
+#define SHFL_UNIX_IXOTH             0000001U
+
+/** Named pipe (fifo) (S_IFIFO). */
+#define SHFL_TYPE_FIFO              0010000U
+/** Character device (S_IFCHR). */
+#define SHFL_TYPE_DEV_CHAR          0020000U
+/** Directory (S_IFDIR). */
+#define SHFL_TYPE_DIRECTORY         0040000U
+/** Block device (S_IFBLK). */
+#define SHFL_TYPE_DEV_BLOCK         0060000U
+/** Regular file (S_IFREG). */
+#define SHFL_TYPE_FILE              0100000U
+/** Symbolic link (S_IFLNK). */
+#define SHFL_TYPE_SYMLINK           0120000U
+/** Socket (S_IFSOCK). */
+#define SHFL_TYPE_SOCKET            0140000U
+/** Whiteout (S_IFWHT). */
+#define SHFL_TYPE_WHITEOUT          0160000U
+/** Type mask (S_IFMT). */
+#define SHFL_TYPE_MASK              0170000U
+
+/** Checks the mode flags indicate a directory (S_ISDIR). */
+#define SHFL_IS_DIRECTORY(m)   (((m) & SHFL_TYPE_MASK) == SHFL_TYPE_DIRECTORY)
+/** Checks the mode flags indicate a symbolic link (S_ISLNK). */
+#define SHFL_IS_SYMLINK(m)     (((m) & SHFL_TYPE_MASK) == SHFL_TYPE_SYMLINK)
+
+/**
+ * The available additional information in a shfl_fsobjattr object.
+ */
+enum shfl_fsobjattr_add {
+	/** No additional information is available / requested. */
+	SHFLFSOBJATTRADD_NOTHING = 1,
+	/**
+	 * The additional unix attributes (shfl_fsobjattr::u::unix_attr) are
+	 *  available / requested.
+	 */
+	SHFLFSOBJATTRADD_UNIX,
+	/**
+	 * The additional extended attribute size (shfl_fsobjattr::u::size) is
+	 *  available / requested.
+	 */
+	SHFLFSOBJATTRADD_EASIZE,
+	/**
+	 * The last valid item (inclusive).
+	 * The valid range is SHFLFSOBJATTRADD_NOTHING thru
+	 * SHFLFSOBJATTRADD_LAST.
+	 */
+	SHFLFSOBJATTRADD_LAST = SHFLFSOBJATTRADD_EASIZE,
+
+	/** The usual 32-bit hack. */
+	SHFLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff
+};
+
+/**
+ * Additional unix Attributes, these are available when
+ * shfl_fsobjattr.additional == SHFLFSOBJATTRADD_UNIX.
+ */
+struct shfl_fsobjattr_unix {
+	/**
+	 * The user owning the filesystem object (st_uid).
+	 * This field is ~0U if not supported.
+	 */
+	u32 uid;
+
+	/**
+	 * The group the filesystem object is assigned (st_gid).
+	 * This field is ~0U if not supported.
+	 */
+	u32 gid;
+
+	/**
+	 * Number of hard links to this filesystem object (st_nlink).
+	 * This field is 1 if the filesystem doesn't support hardlinking or
+	 * the information isn't available.
+	 */
+	u32 hardlinks;
+
+	/**
+	 * The device number of the device which this filesystem object resides
+	 * on (st_dev). This field is 0 if this information is not available.
+	 */
+	u32 inode_id_device;
+
+	/**
+	 * The unique identifier (within the filesystem) of this filesystem
+	 * object (st_ino). Together with inode_id_device, this field can be
+	 * used as a OS wide unique id, when both their values are not 0.
+	 * This field is 0 if the information is not available.
+	 */
+	u64 inode_id;
+
+	/**
+	 * User flags (st_flags).
+	 * This field is 0 if this information is not available.
+	 */
+	u32 flags;
+
+	/**
+	 * The current generation number (st_gen).
+	 * This field is 0 if this information is not available.
+	 */
+	u32 generation_id;
+
+	/**
+	 * The device number of a char. or block device type object (st_rdev).
+	 * This field is 0 if the file isn't a char. or block device or when
+	 * the OS doesn't use the major+minor device idenfication scheme.
+	 */
+	u32 device;
+} __packed;
+
+/** Extended attribute size. */
+struct shfl_fsobjattr_easize {
+	s64 cb; /**< Size of EAs. */
+} __packed;
+
+/** Shared folder filesystem object attributes. */
+struct shfl_fsobjattr {
+	/**
+	 * Mode flags (st_mode). SHFL_UNIX_*, SHFL_TYPE_*, and SHFL_DOS_*.
+	 * @remarks We depend on a number of SHFL_ defines to remain unchanged.
+	 *          Fortuntately, these are depending on windows, dos and unix
+	 *          standard values, so this shouldn't be much of a pain.
+	 */
+	u32 mode;
+
+	/** The additional attributes available. */
+	enum shfl_fsobjattr_add additional;
+
+	/**
+	 * Additional attributes.
+	 *
+	 * Unless explicitly specified to an API, the API can provide additional
+	 * data as it is provided by the underlying OS.
+	 */
+	union {
+		struct shfl_fsobjattr_unix unix_attr;
+		struct shfl_fsobjattr_easize size;
+	} __packed u;
+} __packed;
+VBOXSF_ASSERT_SIZE(shfl_fsobjattr, 44);
+
+struct shfl_timespec {
+	s64 ns_relative_to_unix_epoch;
+};
+
+/**
+ * Filesystem object information structure.
+ */
+struct shfl_fsobjinfo {
+	/**
+	 * Logical size (st_size).
+	 * For normal files this is the size of the file.
+	 * For symbolic links, this is the length of the path name contained
+	 * in the symbolic link.
+	 * For other objects this fields needs to be specified.
+	 */
+	s64 size;
+
+	/** Disk allocation size (st_blocks * DEV_BSIZE). */
+	s64 allocated;
+
+	/**
+	 * Time of last access (st_atime).
+	 * @remarks  Here (and other places) we depend on the IPRT timespec to
+	 *           remain unchanged.
+	 */
+	struct shfl_timespec access_time;
+
+	/** Time of last data modification (st_mtime). */
+	struct shfl_timespec modification_time;
+
+	/**
+	 * Time of last status change (st_ctime).
+	 * If not available this is set to modification_time.
+	 */
+	struct shfl_timespec change_time;
+
+	/**
+	 * Time of file birth (st_birthtime).
+	 * If not available this is set to change_time.
+	 */
+	struct shfl_timespec birth_time;
+
+	/** Attributes. */
+	struct shfl_fsobjattr attr;
+
+} __packed;
+VBOXSF_ASSERT_SIZE(shfl_fsobjinfo, 92);
+
+/**
+ * result of an open/create request.
+ * Along with handle value the result code
+ * identifies what has happened while
+ * trying to open the object.
+ */
+enum shfl_create_result {
+	SHFL_NO_RESULT,
+	/** Specified path does not exist. */
+	SHFL_PATH_NOT_FOUND,
+	/** Path to file exists, but the last component does not. */
+	SHFL_FILE_NOT_FOUND,
+	/** File already exists and either has been opened or not. */
+	SHFL_FILE_EXISTS,
+	/** New file was created. */
+	SHFL_FILE_CREATED,
+	/** Existing file was replaced or overwritten. */
+	SHFL_FILE_REPLACED
+};
+
+/**
+ * Open/create flags.
+ * @{
+ */
+
+/** No flags. Initialization value. */
+#define SHFL_CF_NONE                  (0x00000000)
+
+/**
+ * Only lookup the object, do not return a handle. When this is set all other
+ * flags are ignored.
+ */
+#define SHFL_CF_LOOKUP                (0x00000001)
+
+/**
+ * Open parent directory of specified object.
+ * Useful for the corresponding Windows FSD flag
+ * and for opening paths like \\dir\\*.* to search the 'dir'.
+ * @todo possibly not needed???
+ */
+#define SHFL_CF_OPEN_TARGET_DIRECTORY (0x00000002)
+
+/** Create/open a directory. */
+#define SHFL_CF_DIRECTORY             (0x00000004)
+
+/**
+ *  Open/create action to do if object exists
+ *  and if the object does not exists.
+ *  REPLACE file means atomically DELETE and CREATE.
+ *  OVERWRITE file means truncating the file to 0 and
+ *  setting new size.
+ *  When opening an existing directory REPLACE and OVERWRITE
+ *  actions are considered invalid, and cause returning
+ *  FILE_EXISTS with NIL handle.
+ */
+#define SHFL_CF_ACT_MASK_IF_EXISTS      (0x000000f0)
+#define SHFL_CF_ACT_MASK_IF_NEW         (0x00000f00)
+
+/** What to do if object exists. */
+#define SHFL_CF_ACT_OPEN_IF_EXISTS      (0x00000000)
+#define SHFL_CF_ACT_FAIL_IF_EXISTS      (0x00000010)
+#define SHFL_CF_ACT_REPLACE_IF_EXISTS   (0x00000020)
+#define SHFL_CF_ACT_OVERWRITE_IF_EXISTS (0x00000030)
+
+/** What to do if object does not exist. */
+#define SHFL_CF_ACT_CREATE_IF_NEW       (0x00000000)
+#define SHFL_CF_ACT_FAIL_IF_NEW         (0x00000100)
+
+/** Read/write requested access for the object. */
+#define SHFL_CF_ACCESS_MASK_RW          (0x00003000)
+
+/** No access requested. */
+#define SHFL_CF_ACCESS_NONE             (0x00000000)
+/** Read access requested. */
+#define SHFL_CF_ACCESS_READ             (0x00001000)
+/** Write access requested. */
+#define SHFL_CF_ACCESS_WRITE            (0x00002000)
+/** Read/Write access requested. */
+#define SHFL_CF_ACCESS_READWRITE	(0x00003000)
+
+/** Requested share access for the object. */
+#define SHFL_CF_ACCESS_MASK_DENY        (0x0000c000)
+
+/** Allow any access. */
+#define SHFL_CF_ACCESS_DENYNONE         (0x00000000)
+/** Do not allow read. */
+#define SHFL_CF_ACCESS_DENYREAD         (0x00004000)
+/** Do not allow write. */
+#define SHFL_CF_ACCESS_DENYWRITE        (0x00008000)
+/** Do not allow access. */
+#define SHFL_CF_ACCESS_DENYALL          (0x0000c000)
+
+/** Requested access to attributes of the object. */
+#define SHFL_CF_ACCESS_MASK_ATTR        (0x00030000)
+
+/** No access requested. */
+#define SHFL_CF_ACCESS_ATTR_NONE        (0x00000000)
+/** Read access requested. */
+#define SHFL_CF_ACCESS_ATTR_READ        (0x00010000)
+/** Write access requested. */
+#define SHFL_CF_ACCESS_ATTR_WRITE       (0x00020000)
+/** Read/Write access requested. */
+#define SHFL_CF_ACCESS_ATTR_READWRITE   (0x00030000)
+
+/**
+ * The file is opened in append mode.
+ * Ignored if SHFL_CF_ACCESS_WRITE is not set.
+ */
+#define SHFL_CF_ACCESS_APPEND           (0x00040000)
+
+/** @} */
+
+struct shfl_createparms {
+	/* Returned handle of opened object. */
+	SHFLHANDLE handle;
+
+	/* Returned result of the operation */
+	enum shfl_create_result result;
+
+	/* SHFL_CF_* */
+	u32 create_flags;
+
+	/*
+	 * Attributes of object to create and
+	 * returned actual attributes of opened/created object.
+	 */
+	struct shfl_fsobjinfo info;
+} __packed;
+
+/**
+ * Shared Folders mappings.
+ * @{
+ */
+
+/** The mapping has been added since last query. */
+#define SHFL_MS_NEW        (1)
+/** The mapping has been deleted since last query. */
+#define SHFL_MS_DELETED    (2)
+
+struct shfl_mapping {
+	/** Mapping status. */
+	u32 status;
+	/** Root handle. */
+	SHFLROOT root;
+};
+
+/** @} */
+
+/**
+ * Shared Folder directory information
+ * @{
+ */
+
+struct shfl_dirinfo {
+	/** Full information about the object. */
+	struct shfl_fsobjinfo info;
+	/**
+	 * The length of the short field (number of UTF16 chars).
+	 * It is 16-bit for reasons of alignment.
+	 */
+	u16 short_name_len;
+	/**
+	 * The short name for 8.3 compatibility.
+	 * Empty string if not available.
+	 */
+	u16 short_name[14];
+	/** @todo malc, a description, please. */
+	struct shfl_string name;
+};
+
+/** Shared folder filesystem properties. */
+struct shfl_fsproperties {
+	/**
+	 * The maximum size of a filesystem object name.
+	 * This does not include the '\\0'.
+	 */
+	u32 max_component_len;
+
+	/**
+	 * True if the filesystem is remote.
+	 * False if the filesystem is local.
+	 */
+	bool remote;
+
+	/**
+	 * True if the filesystem is case sensitive.
+	 * False if the filesystem is case insensitive.
+	 */
+	bool case_sensitive;
+
+	/**
+	 * True if the filesystem is mounted read only.
+	 * False if the filesystem is mounted read write.
+	 */
+	bool read_only;
+
+	/**
+	 * True if the filesystem can encode unicode object names.
+	 * False if it can't.
+	 */
+	bool supports_unicode;
+
+	/**
+	 * True if the filesystem is compresses.
+	 * False if it isn't or we don't know.
+	 */
+	bool compressed;
+
+	/**
+	 * True if the filesystem compresses of individual files.
+	 * False if it doesn't or we don't know.
+	 */
+	bool file_compression;
+
+	/** @todo more? */
+};
+VBOXSF_ASSERT_SIZE(shfl_fsproperties, 12);
+
+struct shfl_volinfo {
+	s64 total_allocation_bytes;
+	s64 available_allocation_bytes;
+	u32 bytes_per_allocation_unit;
+	u32 bytes_per_sector;
+	u32 serial;
+	struct shfl_fsproperties properties;
+};
+
+/** @} */
+
+/**
+ * Function parameter structures.
+ * @{
+ */
+
+/** SHFL_FN_QUERY_MAPPINGS */
+
+/**
+ * Validation mask.  Needs to be adjusted
+ * whenever a new SHFL_MF_ flag is added.
+ */
+#define SHFL_MF_MASK       (0x00000011)
+/** UC2 enconded strings. */
+#define SHFL_MF_UCS2       (0x00000000)
+/** Guest uses UTF8 strings, if not set then the strings are unicode (UCS2). */
+#define SHFL_MF_UTF8       (0x00000001)
+/** Just handle the auto-mounted folders. */
+#define SHFL_MF_AUTOMOUNT  (0x00000010)
+
+/** Type of guest system. For future system dependent features. */
+#define SHFL_MF_SYSTEM_MASK    (0x0000ff00)
+#define SHFL_MF_SYSTEM_NONE    (0x00000000)
+#define SHFL_MF_SYSTEM_WINDOWS (0x00000100)
+#define SHFL_MF_SYSTEM_LINUX   (0x00000200)
+
+/** Parameters structure. */
+struct shfl_query_mappings {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * 32bit, in:
+	 * Flags describing various client needs.
+	 */
+	HGCMFunctionParameter flags;
+
+	/**
+	 * 32bit, in/out:
+	 * Number of mappings the client expects.
+	 * This is the number of elements in the
+	 * mappings array.
+	 */
+	HGCMFunctionParameter number_of_mappings;
+
+	/**
+	 * pointer, in/out:
+	 * Points to array of struct shfl_mapping structures.
+	 */
+	HGCMFunctionParameter mappings;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_QUERY_MAPPINGS (3)
+
+/**
+ * SHFL_FN_QUERY_MAP_NAME
+ */
+
+/** Parameters structure. */
+struct shfl_query_map_name {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * 32bit, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in/out:
+	 * Points to struct shfl_string buffer.
+	 */
+	HGCMFunctionParameter name;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_QUERY_MAP_NAME (2)
+
+/**
+ * SHFL_FN_MAP_FOLDER
+ */
+
+/** Parameters structure. */
+struct shfl_map_folder {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string buffer.
+	 */
+	HGCMFunctionParameter path;
+
+	/**
+	 * pointer, out: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in: UTF16
+	 * Path delimiter
+	 */
+	HGCMFunctionParameter delimiter;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Case senstive flag
+	 */
+	HGCMFunctionParameter case_sensitive;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_MAP_FOLDER (4)
+
+/**
+ * SHFL_FN_UNMAP_FOLDER
+ */
+
+/** Parameters structure. */
+struct shfl_unmap_folder {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_UNMAP_FOLDER (1)
+
+/**
+ * SHFL_FN_CREATE
+ */
+
+/** Parameters structure. */
+struct shfl_create {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string buffer.
+	 */
+	HGCMFunctionParameter path;
+
+	/**
+	 * pointer, in/out:
+	 * Points to SHFLCREATEPARMS buffer.
+	 */
+	HGCMFunctionParameter parms;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_CREATE (3)
+
+/**
+ * SHFL_FN_CLOSE
+ */
+
+/** Parameters structure. */
+struct shfl_close {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to close.
+	 */
+	HGCMFunctionParameter handle;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_CLOSE (2)
+
+/**
+ * SHFL_FN_READ
+ */
+
+/** Parameters structure. */
+struct shfl_read {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to read from.
+	 */
+	HGCMFunctionParameter handle;
+
+	/**
+	 * value64, in:
+	 * Offset to read from.
+	 */
+	HGCMFunctionParameter offset;
+
+	/**
+	 * value64, in/out:
+	 * Bytes to read/How many were read.
+	 */
+	HGCMFunctionParameter cb;
+
+	/**
+	 * pointer, out:
+	 * Buffer to place data to.
+	 */
+	HGCMFunctionParameter buffer;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_READ (5)
+
+/**
+ * SHFL_FN_WRITE
+ */
+
+/** Parameters structure. */
+struct shfl_write {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to write to.
+	 */
+	HGCMFunctionParameter handle;
+
+	/**
+	 * value64, in:
+	 * Offset to write to.
+	 */
+	HGCMFunctionParameter offset;
+
+	/**
+	 * value64, in/out:
+	 * Bytes to write/How many were written.
+	 */
+	HGCMFunctionParameter cb;
+
+	/**
+	 * pointer, in:
+	 * Data to write.
+	 */
+	HGCMFunctionParameter buffer;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_WRITE (5)
+
+/**
+ * SHFL_FN_LOCK
+ */
+
+/** Lock owner is the HGCM client. */
+
+/** Lock mode bit mask. */
+#define SHFL_LOCK_MODE_MASK  (0x3)
+/** Cancel lock on the given range. */
+#define SHFL_LOCK_CANCEL     (0x0)
+/** Acquire read only lock. Prevent write to the range. */
+#define SHFL_LOCK_SHARED     (0x1)
+/** Acquire write lock. Prevent both write and read to the range. */
+#define SHFL_LOCK_EXCLUSIVE  (0x2)
+
+/** Do not wait for lock if it can not be acquired at the time. */
+#define SHFL_LOCK_NOWAIT     (0x0)
+/** Wait and acquire lock. */
+#define SHFL_LOCK_WAIT       (0x4)
+
+/** Lock the specified range. */
+#define SHFL_LOCK_PARTIAL    (0x0)
+/** Lock entire object. */
+#define SHFL_LOCK_ENTIRE     (0x8)
+
+/** Parameters structure. */
+struct shfl_lock {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to be locked.
+	 */
+	HGCMFunctionParameter handle;
+
+	/**
+	 * value64, in:
+	 * Starting offset of lock range.
+	 */
+	HGCMFunctionParameter offset;
+
+	/**
+	 * value64, in:
+	 * Length of range.
+	 */
+	HGCMFunctionParameter length;
+
+	/**
+	 * value32, in:
+	 * Lock flags SHFL_LOCK_*.
+	 */
+	HGCMFunctionParameter flags;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_LOCK (5)
+
+/**
+ * SHFL_FN_FLUSH
+ */
+
+/** Parameters structure. */
+struct shfl_flush {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to be locked.
+	 */
+	HGCMFunctionParameter handle;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_FLUSH (2)
+
+/**
+ * SHFL_FN_LIST
+ */
+
+/** Listing information includes variable length RTDIRENTRY[EX] structures. */
+
+/** @todo might be necessary for future. */
+#define SHFL_LIST_NONE			0
+#define SHFL_LIST_RETURN_ONE		1
+
+/** Parameters structure. */
+struct shfl_list {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to be listed.
+	 */
+	HGCMFunctionParameter handle;
+
+	/**
+	 * value32, in:
+	 * List flags SHFL_LIST_*.
+	 */
+	HGCMFunctionParameter flags;
+
+	/**
+	 * value32, in/out:
+	 * Bytes to be used for listing information/How many bytes were used.
+	 */
+	HGCMFunctionParameter cb;
+
+	/**
+	 * pointer, in/optional
+	 * Points to struct shfl_string buffer that specifies a search path.
+	 */
+	HGCMFunctionParameter path;
+
+	/**
+	 * pointer, out:
+	 * Buffer to place listing information to. (struct shfl_dirinfo)
+	 */
+	HGCMFunctionParameter buffer;
+
+	/**
+	 * value32, in/out:
+	 * Indicates a key where the listing must be resumed.
+	 * in: 0 means start from begin of object.
+	 * out: 0 means listing completed.
+	 */
+	HGCMFunctionParameter resume_point;
+
+	/**
+	 * pointer, out:
+	 * Number of files returned
+	 */
+	HGCMFunctionParameter file_count;
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_LIST (8)
+
+/**
+ * SHFL_FN_READLINK
+ */
+
+/** Parameters structure. */
+struct shfl_readLink {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string buffer.
+	 */
+	HGCMFunctionParameter path;
+
+	/**
+	 * pointer, out:
+	 * Buffer to place data to.
+	 */
+	HGCMFunctionParameter buffer;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_READLINK (3)
+
+/**
+ * SHFL_FN_INFORMATION
+ */
+
+/** Mask of Set/Get bit. */
+#define SHFL_INFO_MODE_MASK    (0x1)
+/** Get information */
+#define SHFL_INFO_GET          (0x0)
+/** Set information */
+#define SHFL_INFO_SET          (0x1)
+
+/** Get name of the object. */
+#define SHFL_INFO_NAME         (0x2)
+/** Set size of object (extend/trucate); only applies to file objects */
+#define SHFL_INFO_SIZE         (0x4)
+/** Get/Set file object info. */
+#define SHFL_INFO_FILE         (0x8)
+/** Get volume information. */
+#define SHFL_INFO_VOLUME       (0x10)
+
+/** @todo different file info structures */
+
+/** Parameters structure. */
+struct shfl_information {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * value64, in:
+	 * SHFLHANDLE of object to be listed.
+	 */
+	HGCMFunctionParameter handle;
+
+	/**
+	 * value32, in:
+	 * SHFL_INFO_*
+	 */
+	HGCMFunctionParameter flags;
+
+	/**
+	 * value32, in/out:
+	 * Bytes to be used for information/How many bytes were used.
+	 */
+	HGCMFunctionParameter cb;
+
+	/**
+	 * pointer, in/out:
+	 * Information to be set/get (shfl_fsobjinfo or shfl_string). Do not
+	 * forget to set the shfl_fsobjinfo::attr::additional for a get
+	 * operation as well.
+	 */
+	HGCMFunctionParameter info;
+
+};
+
+/** Number of parameters */
+#define SHFL_CPARMS_INFORMATION (5)
+
+/**
+ * SHFL_FN_REMOVE
+ */
+
+#define SHFL_REMOVE_FILE        (0x1)
+#define SHFL_REMOVE_DIR         (0x2)
+#define SHFL_REMOVE_SYMLINK     (0x4)
+
+/** Parameters structure. */
+struct shfl_remove {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string buffer.
+	 */
+	HGCMFunctionParameter path;
+
+	/**
+	 * value32, in:
+	 * remove flags (file/directory)
+	 */
+	HGCMFunctionParameter flags;
+
+};
+
+#define SHFL_CPARMS_REMOVE  (3)
+
+/**
+ * SHFL_FN_RENAME
+ */
+
+#define SHFL_RENAME_FILE                (0x1)
+#define SHFL_RENAME_DIR                 (0x2)
+#define SHFL_RENAME_REPLACE_IF_EXISTS   (0x4)
+
+/** Parameters structure. */
+struct shfl_rename {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string src.
+	 */
+	HGCMFunctionParameter src;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string dest.
+	 */
+	HGCMFunctionParameter dest;
+
+	/**
+	 * value32, in:
+	 * rename flags (file/directory)
+	 */
+	HGCMFunctionParameter flags;
+
+};
+
+#define SHFL_CPARMS_RENAME  (4)
+
+/**
+ * SHFL_FN_SYMLINK
+ */
+
+/** Parameters structure. */
+struct shfl_symlink {
+	VBoxGuestHGCMCallInfo call_info;
+
+	/**
+	 * pointer, in: SHFLROOT
+	 * Root handle of the mapping which name is queried.
+	 */
+	HGCMFunctionParameter root;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string of path for the new symlink.
+	 */
+	HGCMFunctionParameter new_path;
+
+	/**
+	 * pointer, in:
+	 * Points to struct shfl_string of destination for symlink.
+	 */
+	HGCMFunctionParameter old_path;
+
+	/**
+	 * pointer, out:
+	 * Information about created symlink.
+	 */
+	HGCMFunctionParameter info;
+
+};
+
+#define SHFL_CPARMS_SYMLINK  (4)
+
+/**
+ * SHFL_FN_ADD_MAPPING
+ * Host call, no guest structure is used.
+ */
+
+/** mapping is writable */
+#define SHFL_ADD_MAPPING_F_WRITABLE         BIT(0)
+/** mapping is automounted by the guest */
+#define SHFL_ADD_MAPPING_F_AUTOMOUNT        BIT(1)
+/** allow the guest to create symlinks */
+#define SHFL_ADD_MAPPING_F_CREATE_SYMLINKS  BIT(2)
+/** mapping is actually missing on the host */
+#define SHFL_ADD_MAPPING_F_MISSING          BIT(3)
+
+#define SHFL_CPARMS_ADD_MAPPING  (3)
+
+/**
+ * SHFL_FN_REMOVE_MAPPING
+ * Host call, no guest structure is used.
+ */
+
+#define SHFL_CPARMS_REMOVE_MAPPING (1)
+
+/**
+ * SHFL_FN_SET_STATUS_LED
+ * Host call, no guest structure is used.
+ */
+
+#define SHFL_CPARMS_SET_STATUS_LED (1)
+
+/** @} */
+
+#endif
diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c
new file mode 100644
index 000000000000..861afb421b5e
--- /dev/null
+++ b/fs/vboxsf/utils.c
@@ -0,0 +1,674 @@
+/*
+ * VirtualBox Guest Shared Folders support: Utility functions.
+ * Mainly conversion from/to VirtualBox/Linux data structures.
+ *
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/namei.h>
+#include <linux/nfs_fs.h>
+#include <linux/nls.h>
+#include <linux/vfs.h>
+#include <linux/vbox_err.h>
+#include <linux/vbox_utils.h>
+#include "vfsmod.h"
+
+/*
+ * sf_reg_aops and sf_backing_dev_info are just quick implementations to make
+ * sendfile work. For more information have a look at
+ *
+ *   http://us1.samba.org/samba/ftp/cifs-cvs/ols2006-fs-tutorial-smf.odp
+ *
+ * and the sample implementation
+ *
+ *   http://pserver.samba.org/samba/ftp/cifs-cvs/samplefs.tar.gz
+ */
+
+static void sf_timespec_from_vbox(struct timespec *tv,
+				  const struct shfl_timespec *ts)
+{
+	s64 nsec, t = ts->ns_relative_to_unix_epoch;
+
+	nsec = do_div(t, 1000000000);
+	tv->tv_sec = t;
+	tv->tv_nsec = nsec;
+}
+
+static void sf_timespec_to_vbox(struct shfl_timespec *ts,
+				const struct timespec *tv)
+{
+	s64 t = (s64) tv->tv_nsec + (s64) tv->tv_sec * 1000000000;
+
+	ts->ns_relative_to_unix_epoch = t;
+}
+
+/* set [inode] attributes based on [info], uid/gid based on [sf_g] */
+void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode,
+		   const struct shfl_fsobjinfo *info)
+{
+	const struct shfl_fsobjattr *attr;
+	s64 allocated;
+	int mode;
+
+	attr = &info->attr;
+
+#define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0)
+
+	mode = mode_set(ISUID);
+	mode |= mode_set(ISGID);
+
+	mode |= mode_set(IRUSR);
+	mode |= mode_set(IWUSR);
+	mode |= mode_set(IXUSR);
+
+	mode |= mode_set(IRGRP);
+	mode |= mode_set(IWGRP);
+	mode |= mode_set(IXGRP);
+
+	mode |= mode_set(IROTH);
+	mode |= mode_set(IWOTH);
+	mode |= mode_set(IXOTH);
+
+#undef mode_set
+
+	inode->i_mapping->a_ops = &sf_reg_aops;
+
+	if (SHFL_IS_DIRECTORY(attr->mode)) {
+		inode->i_mode = sf_g->dmode != ~0 ? (sf_g->dmode & 0777) : mode;
+		inode->i_mode &= ~sf_g->dmask;
+		inode->i_mode |= S_IFDIR;
+		inode->i_op = &sf_dir_iops;
+		inode->i_fop = &sf_dir_fops;
+		/*
+		 * XXX: this probably should be set to the number of entries
+		 * in the directory plus two (. ..)
+		 */
+		set_nlink(inode, 1);
+	} else if (SHFL_IS_SYMLINK(attr->mode)) {
+		inode->i_mode = sf_g->fmode != ~0 ? (sf_g->fmode & 0777) : mode;
+		inode->i_mode &= ~sf_g->fmask;
+		inode->i_mode |= S_IFLNK;
+		inode->i_op = &sf_lnk_iops;
+		set_nlink(inode, 1);
+	} else {
+		inode->i_mode = sf_g->fmode != ~0 ? (sf_g->fmode & 0777) : mode;
+		inode->i_mode &= ~sf_g->fmask;
+		inode->i_mode |= S_IFREG;
+		inode->i_op = &sf_reg_iops;
+		inode->i_fop = &sf_reg_fops;
+		set_nlink(inode, 1);
+	}
+
+	inode->i_uid = make_kuid(current_user_ns(), sf_g->uid);
+	inode->i_gid = make_kgid(current_user_ns(), sf_g->gid);
+
+	inode->i_size = info->size;
+	inode->i_blkbits = 12;
+	/* i_blocks always in units of 512 bytes! */
+	allocated = info->allocated + 511;
+	do_div(allocated, 512);
+	inode->i_blocks = allocated;
+
+	sf_timespec_from_vbox(&inode->i_atime, &info->access_time);
+	sf_timespec_from_vbox(&inode->i_ctime, &info->change_time);
+	sf_timespec_from_vbox(&inode->i_mtime, &info->modification_time);
+}
+
+int sf_stat(const char *caller, struct sf_glob_info *sf_g,
+	    struct shfl_string *path, struct shfl_fsobjinfo *result,
+	    int ok_to_fail)
+{
+	struct shfl_createparms params = {};
+	int rc;
+
+	params.handle = SHFL_HANDLE_NIL;
+	params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
+	rc = vboxsf_create(sf_g->root, path, &params);
+	if (rc == VERR_INVALID_NAME) {
+		/* this can happen for names like 'foo*' on a Windows host */
+		return -ENOENT;
+	}
+	if (rc < 0)
+		return -EPROTO;
+
+	if (params.result != SHFL_FILE_EXISTS)
+		return -ENOENT;
+
+	*result = params.info;
+	return 0;
+}
+
+/*
+ * This is called indirectly as iop through [sf_getattr]. The job is to find
+ * out whether dentry/inode is still valid. the test is failed if [dentry]
+ * does not have an inode or [sf_stat] is unsuccessful, otherwise we return
+ * success and update inode attributes.
+ */
+int sf_inode_revalidate(struct dentry *dentry)
+{
+	int err;
+	struct sf_glob_info *sf_g;
+	struct sf_inode_info *sf_i;
+	struct shfl_fsobjinfo info;
+
+	if (!dentry || !dentry->d_inode)
+		return -EINVAL;
+
+	sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
+	sf_i = GET_INODE_INFO(dentry->d_inode);
+
+	if (!sf_i->force_restat) {
+		if (jiffies - dentry->d_time < sf_g->ttl)
+			return 0;
+	}
+
+	err = sf_stat(__func__, sf_g, sf_i->path, &info, 1);
+	if (err)
+		return err;
+
+	dentry->d_time = jiffies;
+	sf_init_inode(sf_g, dentry->d_inode, &info);
+	return 0;
+}
+
+/*
+ * This is called during name resolution/lookup to check if the [dentry] in the
+ * cache is still valid. the job is handled by [sf_inode_revalidate].
+ */
+static int sf_dentry_revalidate(struct dentry *dentry, unsigned int flags)
+{
+	if (flags & LOOKUP_RCU)
+		return -ECHILD;
+
+	if (sf_inode_revalidate(dentry))
+		return 0;
+
+	return 1;
+}
+
+int sf_getattr(const struct path *path, struct kstat *kstat, u32 request_mask,
+	       unsigned int flags)
+{
+	int err;
+	struct dentry *dentry = path->dentry;
+
+	err = sf_inode_revalidate(dentry);
+	if (err)
+		return err;
+
+	generic_fillattr(dentry->d_inode, kstat);
+	return 0;
+}
+
+int sf_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+	struct sf_glob_info *sf_g;
+	struct sf_inode_info *sf_i;
+	struct shfl_createparms params = {};
+	struct shfl_fsobjinfo info = {};
+	uint32_t buf_len;
+	int rc, err;
+
+	sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
+	sf_i = GET_INODE_INFO(dentry->d_inode);
+	err = 0;
+
+	params.handle = SHFL_HANDLE_NIL;
+	params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS
+	    | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_ATTR_WRITE;
+
+	/* this is at least required for Posix hosts */
+	if (iattr->ia_valid & ATTR_SIZE)
+		params.create_flags |= SHFL_CF_ACCESS_WRITE;
+
+	rc = vboxsf_create(sf_g->root, sf_i->path, &params);
+	if (rc < 0) {
+		err = vbg_status_code_to_errno(rc);
+		goto fail2;
+	}
+	if (params.result != SHFL_FILE_EXISTS) {
+		err = -ENOENT;
+		goto fail1;
+	}
+#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0)
+
+	/*
+	 * Setting the file size and setting the other attributes has to
+	 * be handled separately.
+	 */
+	if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) {
+		if (iattr->ia_valid & ATTR_MODE) {
+			info.attr.mode = mode_set(ISUID);
+			info.attr.mode |= mode_set(ISGID);
+			info.attr.mode |= mode_set(IRUSR);
+			info.attr.mode |= mode_set(IWUSR);
+			info.attr.mode |= mode_set(IXUSR);
+			info.attr.mode |= mode_set(IRGRP);
+			info.attr.mode |= mode_set(IWGRP);
+			info.attr.mode |= mode_set(IXGRP);
+			info.attr.mode |= mode_set(IROTH);
+			info.attr.mode |= mode_set(IWOTH);
+			info.attr.mode |= mode_set(IXOTH);
+
+			if (iattr->ia_mode & S_IFDIR)
+				info.attr.mode |= SHFL_TYPE_DIRECTORY;
+			else
+				info.attr.mode |= SHFL_TYPE_FILE;
+		}
+
+		if (iattr->ia_valid & ATTR_ATIME)
+			sf_timespec_to_vbox(&info.access_time,
+					    &iattr->ia_atime);
+
+		if (iattr->ia_valid & ATTR_MTIME)
+			sf_timespec_to_vbox(&info.modification_time,
+					    &iattr->ia_mtime);
+
+		/*
+		 * Ignore ctime (inode change time) as it can't be set
+		 * from userland anyway.
+		 */
+
+		buf_len = sizeof(info);
+		rc = vboxsf_fsinfo(sf_g->root, params.handle,
+				   SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len,
+				   &info);
+		if (rc < 0) {
+			err = vbg_status_code_to_errno(rc);
+			goto fail1;
+		}
+	}
+#undef mode_set
+
+	if (iattr->ia_valid & ATTR_SIZE) {
+		memset(&info, 0, sizeof(info));
+		info.size = iattr->ia_size;
+		buf_len = sizeof(info);
+		rc = vboxsf_fsinfo(sf_g->root, params.handle,
+				   SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len,
+				   &info);
+		if (rc < 0) {
+			err = vbg_status_code_to_errno(rc);
+			goto fail1;
+		}
+	}
+
+	vboxsf_close(sf_g->root, params.handle);
+
+	return sf_inode_revalidate(dentry);
+
+fail1:
+	vboxsf_close(sf_g->root, params.handle);
+fail2:
+	return err;
+}
+
+static int sf_make_path(const char *caller, struct sf_inode_info *sf_i,
+			const char *d_name, size_t d_len,
+			struct shfl_string **result)
+{
+	size_t path_len, shflstring_len;
+	struct shfl_string *tmp;
+	uint16_t p_len;
+	uint8_t *p_name;
+	int fRoot = 0;
+
+	p_len = sf_i->path->length;
+	p_name = sf_i->path->string.utf8;
+
+	if (p_len == 1 && *p_name == '/') {
+		path_len = d_len + 1;
+		fRoot = 1;
+	} else {
+		/* lengths of constituents plus terminating zero plus slash  */
+		path_len = p_len + d_len + 2;
+		if (path_len > 0xffff)
+			return -ENAMETOOLONG;
+	}
+
+	shflstring_len = offsetof(struct shfl_string, string.utf8) + path_len;
+	tmp = kmalloc(shflstring_len, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	tmp->length = path_len - 1;
+	tmp->size = path_len;
+
+	if (fRoot)
+		memcpy(&tmp->string.utf8[0], d_name, d_len + 1);
+	else {
+		memcpy(&tmp->string.utf8[0], p_name, p_len);
+		tmp->string.utf8[p_len] = '/';
+		memcpy(&tmp->string.utf8[p_len + 1], d_name, d_len);
+		tmp->string.utf8[p_len + 1 + d_len] = '\0';
+	}
+
+	*result = tmp;
+	return 0;
+}
+
+/**
+ * [dentry] contains string encoded in coding system that corresponds
+ * to [sf_g]->nls, we must convert it to UTF8 here and pass down to
+ * [sf_make_path] which will allocate struct shfl_string and fill it in
+ */
+int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
+			struct sf_inode_info *sf_i, struct dentry *dentry,
+			struct shfl_string **result)
+{
+	int err;
+	const char *d_name;
+	size_t d_len;
+	const char *name;
+	size_t len = 0;
+
+	d_name = dentry->d_name.name;
+	d_len = dentry->d_name.len;
+
+	if (sf_g->nls) {
+		size_t in_len, i, out_bound_len;
+		const char *in;
+		char *out;
+
+		in = d_name;
+		in_len = d_len;
+
+		out_bound_len = PATH_MAX;
+		out = kmalloc(out_bound_len, GFP_KERNEL);
+		name = out;
+
+		for (i = 0; i < d_len; ++i) {
+			wchar_t uni;
+			int nb;
+
+			nb = sf_g->nls->char2uni(in, in_len, &uni);
+			if (nb < 0) {
+				err = -EINVAL;
+				goto fail1;
+			}
+			in_len -= nb;
+			in += nb;
+
+			nb = utf32_to_utf8(uni, out, out_bound_len);
+			if (nb < 0) {
+				err = -EINVAL;
+				goto fail1;
+			}
+			out_bound_len -= nb;
+			out += nb;
+			len += nb;
+		}
+		if (len >= PATH_MAX - 1) {
+			err = -ENAMETOOLONG;
+			goto fail1;
+		}
+
+		*out = 0;
+	} else {
+		name = d_name;
+		len = d_len;
+	}
+
+	err = sf_make_path(caller, sf_i, name, len, result);
+	if (name != d_name)
+		kfree(name);
+
+	return err;
+
+fail1:
+	kfree(name);
+	return err;
+}
+
+int sf_nlscpy(struct sf_glob_info *sf_g,
+	      char *name, size_t name_bound_len,
+	      const unsigned char *utf8_name, size_t utf8_len)
+{
+	if (sf_g->nls) {
+		const char *in;
+		char *out;
+		size_t out_len;
+		size_t out_bound_len;
+		size_t in_bound_len;
+
+		in = utf8_name;
+		in_bound_len = utf8_len;
+
+		out = name;
+		out_len = 0;
+		out_bound_len = name_bound_len;
+
+		while (in_bound_len) {
+			int nb;
+			unicode_t uni;
+
+			nb = utf8_to_utf32(in, in_bound_len, &uni);
+			if (nb < 0)
+				return -EINVAL;
+
+			in += nb;
+			in_bound_len -= nb;
+
+			nb = sf_g->nls->uni2char(uni, out, out_bound_len);
+			if (nb < 0)
+				return nb;
+
+			out += nb;
+			out_bound_len -= nb;
+			out_len += nb;
+		}
+
+		*out = 0;
+	} else {
+		if (utf8_len + 1 > name_bound_len)
+			return -ENAMETOOLONG;
+
+		memcpy(name, utf8_name, utf8_len + 1);
+	}
+	return 0;
+}
+
+static struct sf_dir_buf *sf_dir_buf_alloc(void)
+{
+	struct sf_dir_buf *b;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (!b)
+		return NULL;
+
+	b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
+	if (!b->buf) {
+		kfree(b);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&b->head);
+	b->entries = 0;
+	b->used = 0;
+	b->free = DIR_BUFFER_SIZE;
+
+	return b;
+}
+
+static void sf_dir_buf_free(struct sf_dir_buf *b)
+{
+	list_del(&b->head);
+	kfree(b->buf);
+	kfree(b);
+}
+
+/**
+ * Free the directory buffer.
+ */
+void sf_dir_info_free(struct sf_dir_info *p)
+{
+	struct list_head *list, *pos, *tmp;
+
+	list = &p->info_list;
+	list_for_each_safe(pos, tmp, list) {
+		struct sf_dir_buf *b;
+
+		b = list_entry(pos, struct sf_dir_buf, head);
+		sf_dir_buf_free(b);
+	}
+	kfree(p);
+}
+
+/**
+ * Empty (but not free) the directory buffer.
+ */
+void sf_dir_info_empty(struct sf_dir_info *p)
+{
+	struct list_head *list, *pos, *tmp;
+	struct sf_dir_buf *b;
+
+	list = &p->info_list;
+	list_for_each_safe(pos, tmp, list) {
+		b = list_entry(pos, struct sf_dir_buf, head);
+		b->entries = 0;
+		b->used = 0;
+		b->free = DIR_BUFFER_SIZE;
+	}
+}
+
+/**
+ * Create a new directory buffer descriptor.
+ */
+struct sf_dir_info *sf_dir_info_alloc(void)
+{
+	struct sf_dir_info *p;
+
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	INIT_LIST_HEAD(&p->info_list);
+	return p;
+}
+
+/** Search for an empty directory content buffer. */
+static struct sf_dir_buf *sf_get_empty_dir_buf(struct sf_dir_info *sf_d)
+{
+	struct list_head *list, *pos;
+
+	list = &sf_d->info_list;
+	list_for_each(pos, list) {
+		struct sf_dir_buf *b;
+
+		b = list_entry(pos, struct sf_dir_buf, head);
+		if (!b)
+			return NULL;
+
+		if (b->used == 0)
+			return b;
+	}
+
+	return NULL;
+}
+
+int sf_dir_read_all(struct sf_glob_info *sf_g, struct sf_inode_info *sf_i,
+		    struct sf_dir_info *sf_d, SHFLHANDLE handle)
+{
+	int err;
+	struct shfl_string *mask;
+	struct sf_dir_buf *b;
+
+	err = sf_make_path(__func__, sf_i, "*", 1, &mask);
+	if (err)
+		goto fail0;
+
+	for (;;) {
+		int rc;
+		void *buf;
+		u32 entries, size;
+
+		b = sf_get_empty_dir_buf(sf_d);
+		if (!b) {
+			b = sf_dir_buf_alloc();
+			if (!b) {
+				err = -ENOMEM;
+				goto fail1;
+			}
+			list_add(&b->head, &sf_d->info_list);
+		}
+
+		buf = b->buf;
+		size = b->free;
+
+		rc = vboxsf_dirinfo(sf_g->root, handle, mask, 0, 0,
+				    &size, buf, &entries);
+		switch (rc) {
+		case VINF_SUCCESS:
+			/* fallthrough */
+		case VERR_NO_MORE_FILES:
+			break;
+		case VERR_NO_TRANSLATION:
+			/* XXX */
+			break;
+		default:
+			err = vbg_status_code_to_errno(rc);
+			goto fail1;
+		}
+
+		b->entries += entries;
+		b->free -= size;
+		b->used += size;
+
+		if (rc < 0)
+			break;
+	}
+	err = 0;
+
+fail1:
+	kfree(mask);
+
+fail0:
+	return err;
+}
+
+int sf_get_volume_info(struct super_block *sb, struct kstatfs *stat)
+{
+	struct sf_glob_info *sf_g;
+	struct shfl_volinfo SHFLVolumeInfo;
+	u32 buf_len;
+	int rc;
+
+	sf_g = GET_GLOB_INFO(sb);
+	buf_len = sizeof(SHFLVolumeInfo);
+	rc = vboxsf_fsinfo(sf_g->root, 0,
+			   SHFL_INFO_GET | SHFL_INFO_VOLUME, &buf_len,
+			   &SHFLVolumeInfo);
+	if (rc < 0)
+		return vbg_status_code_to_errno(rc);
+
+	stat->f_type = NFS_SUPER_MAGIC;	/* XXX vboxsf type? */
+	stat->f_bsize = SHFLVolumeInfo.bytes_per_allocation_unit;
+
+	do_div(SHFLVolumeInfo.total_allocation_bytes,
+	       SHFLVolumeInfo.bytes_per_allocation_unit);
+	stat->f_blocks = SHFLVolumeInfo.total_allocation_bytes;
+
+	do_div(SHFLVolumeInfo.available_allocation_bytes,
+	       SHFLVolumeInfo.bytes_per_allocation_unit);
+	stat->f_bfree  = SHFLVolumeInfo.available_allocation_bytes;
+	stat->f_bavail = SHFLVolumeInfo.available_allocation_bytes;
+
+	stat->f_files = 1000;
+	/*
+	 * Don't return 0 here since the guest may then think that it is not
+	 * possible to create any more files.
+	 */
+	stat->f_ffree = 1000;
+	stat->f_fsid.val[0] = 0;
+	stat->f_fsid.val[1] = 0;
+	stat->f_namelen = 255;
+	return 0;
+}
+
+const struct dentry_operations sf_dentry_ops = {
+	.d_revalidate = sf_dentry_revalidate
+};
diff --git a/fs/vboxsf/vboxsf_wrappers.c b/fs/vboxsf/vboxsf_wrappers.c
new file mode 100644
index 000000000000..64ee30894ddf
--- /dev/null
+++ b/fs/vboxsf/vboxsf_wrappers.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * Wrapper functions for the shfl host calls.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, in which case the provisions of the CDDL are applicable
+ * instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vbox_err.h>
+#include <linux/vbox_utils.h>
+#include "vboxsf_wrappers.h"
+
+#define VBOX_INIT_CALL(a, b) \
+do { \
+	(a)->result      = VINF_SUCCESS;     \
+	(a)->u32ClientID = vboxsf_client_id; \
+	(a)->u32Function = SHFL_FN_##b;      \
+	(a)->cParms      = SHFL_CPARMS_##b;  \
+} while (0)
+
+/* globals */
+static u32 vboxsf_client_id;
+
+int vboxsf_connect(void)
+{
+	struct vbg_dev *gdev;
+	HGCMServiceLocation loc;
+	int rc;
+
+	loc.type = VMMDevHGCMLoc_LocalHost_Existing;
+	strcpy(loc.u.host.achName, "VBoxSharedFolders");
+
+	gdev = vbg_get_gdev();
+	if (IS_ERR(gdev))
+		return VERR_NOT_SUPPORTED;	/* No guest-device */
+
+	rc = vbg_hgcm_connect(gdev, &loc, &vboxsf_client_id);
+	vbg_put_gdev(gdev);
+
+	return rc;
+}
+
+void vboxsf_disconnect(void)
+{
+	struct vbg_dev *gdev;
+
+	gdev = vbg_get_gdev();
+	if (IS_ERR(gdev))
+		return;   /* guest-device is gone, already disconnected */
+
+	vbg_hgcm_disconnect(gdev, vboxsf_client_id);
+	vbg_put_gdev(gdev);
+}
+
+static int vboxsf_hgcm_call(void *data, u32 len)
+{
+	VBoxGuestHGCMCallInfo *info = data;
+	struct vbg_dev *gdev;
+	int rc;
+
+	gdev = vbg_get_gdev();
+	if (IS_ERR(gdev))
+		return VERR_DEV_IO_ERROR; /* guest-dev removed underneath us */
+
+	rc = vbg_hgcm_call(gdev, info, len, U32_MAX, false);
+	vbg_put_gdev(gdev);
+
+	if (rc >= 0)
+		rc = info->result;
+
+	return rc;
+}
+
+int vboxsf_query_mappings(struct shfl_mapping mappings[], u32 *mappings_len)
+{
+	int rc;
+	struct shfl_query_mappings data;
+
+	VBOX_INIT_CALL(&data.call_info, QUERY_MAPPINGS);
+
+	data.flags.type = VMMDevHGCMParmType_32bit;
+	data.flags.u.value32 = SHFL_MF_UCS2;
+
+	data.number_of_mappings.type = VMMDevHGCMParmType_32bit;
+	data.number_of_mappings.u.value32 = *mappings_len;
+
+	data.mappings.type = VMMDevHGCMParmType_LinAddr;
+	data.mappings.u.Pointer.size = sizeof(struct shfl_mapping) *
+				       *mappings_len;
+	data.mappings.u.Pointer.u.linearAddr = (uintptr_t)&mappings[0];
+
+	rc = vboxsf_hgcm_call(&data, sizeof(data));
+	if (rc >= 0)
+		*mappings_len = data.number_of_mappings.u.value32;
+
+	return rc;
+}
+
+int vboxsf_query_mapname(SHFLROOT root, struct shfl_string *string, u32 size)
+{
+	struct shfl_query_map_name data;
+
+	VBOX_INIT_CALL(&data.call_info, QUERY_MAP_NAME);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.name.type = VMMDevHGCMParmType_LinAddr;
+	data.name.u.Pointer.size = size;
+	data.name.u.Pointer.u.linearAddr = (uintptr_t)string;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_map_folder(struct shfl_string *folder_name, SHFLROOT *root)
+{
+	int rc;
+	struct shfl_map_folder data;
+
+	VBOX_INIT_CALL(&data.call_info, MAP_FOLDER);
+
+	data.path.type = VMMDevHGCMParmType_LinAddr;
+	data.path.u.Pointer.size = shfl_string_buf_size(folder_name);
+	data.path.u.Pointer.u.linearAddr = (uintptr_t)folder_name;
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = 0;
+
+	data.delimiter.type = VMMDevHGCMParmType_32bit;
+	data.delimiter.u.value32 = '/';
+
+	data.case_sensitive.type = VMMDevHGCMParmType_32bit;
+	data.case_sensitive.u.value32 = 1;
+
+	rc = vboxsf_hgcm_call(&data, sizeof(data));
+	if (rc >= 0)
+		*root = data.root.u.value32;
+	else if (rc == VERR_NOT_IMPLEMENTED)
+		vbg_err("%s: Error host is too old\n", __func__);
+
+	return rc;
+}
+
+int vboxsf_unmap_folder(SHFLROOT root)
+{
+	struct shfl_unmap_folder data;
+
+	VBOX_INIT_CALL(&data.call_info, UNMAP_FOLDER);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_create(SHFLROOT root, struct shfl_string *parsed_path,
+		  struct shfl_createparms *create_parms)
+{
+	/** @todo copy buffers to physical or mapped memory. */
+	struct shfl_create data;
+
+	VBOX_INIT_CALL(&data.call_info, CREATE);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.path.type = VMMDevHGCMParmType_LinAddr;
+	data.path.u.Pointer.size = shfl_string_buf_size(parsed_path);
+	data.path.u.Pointer.u.linearAddr = (uintptr_t)parsed_path;
+
+	data.parms.type = VMMDevHGCMParmType_LinAddr;
+	data.parms.u.Pointer.size = sizeof(struct shfl_createparms);
+	data.parms.u.Pointer.u.linearAddr = (uintptr_t)create_parms;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_close(SHFLROOT root, SHFLHANDLE file)
+{
+	struct shfl_close data;
+
+	VBOX_INIT_CALL(&data.call_info, CLOSE);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_remove(SHFLROOT root, struct shfl_string *parsed_path, u32 flags)
+{
+	struct shfl_remove data;
+
+	VBOX_INIT_CALL(&data.call_info, REMOVE);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.path.type = VMMDevHGCMParmType_LinAddr_In;
+	data.path.u.Pointer.size = shfl_string_buf_size(parsed_path);
+	data.path.u.Pointer.u.linearAddr = (uintptr_t)parsed_path;
+
+	data.flags.type = VMMDevHGCMParmType_32bit;
+	data.flags.u.value32 = flags;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_rename(SHFLROOT root, struct shfl_string *src_path,
+		  struct shfl_string *dest_path, u32 flags)
+{
+	struct shfl_rename data;
+
+	VBOX_INIT_CALL(&data.call_info, RENAME);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.src.type = VMMDevHGCMParmType_LinAddr_In;
+	data.src.u.Pointer.size = shfl_string_buf_size(src_path);
+	data.src.u.Pointer.u.linearAddr = (uintptr_t)src_path;
+
+	data.dest.type = VMMDevHGCMParmType_LinAddr_In;
+	data.dest.u.Pointer.size = shfl_string_buf_size(dest_path);
+	data.dest.u.Pointer.u.linearAddr = (uintptr_t)dest_path;
+
+	data.flags.type = VMMDevHGCMParmType_32bit;
+	data.flags.u.value32 = flags;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_read(SHFLROOT root, SHFLHANDLE file, u64 offset,
+		u32 *buf_len, u8 *buf)
+{
+	int rc;
+	struct shfl_read data;
+
+	VBOX_INIT_CALL(&data.call_info, READ);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+	data.offset.type = VMMDevHGCMParmType_64bit;
+	data.offset.u.value64 = offset;
+	data.cb.type = VMMDevHGCMParmType_32bit;
+	data.cb.u.value32 = *buf_len;
+	data.buffer.type = VMMDevHGCMParmType_LinAddr_Out;
+	data.buffer.u.Pointer.size = *buf_len;
+	data.buffer.u.Pointer.u.linearAddr = (uintptr_t)buf;
+
+	rc = vboxsf_hgcm_call(&data, sizeof(data));
+	if (rc >= 0)
+		*buf_len = data.cb.u.value32;
+
+	return rc;
+}
+
+int vboxsf_write(SHFLROOT root, SHFLHANDLE file, u64 offset,
+		 u32 *buf_len, u8 *buf)
+{
+	int rc;
+	struct shfl_write data;
+
+	VBOX_INIT_CALL(&data.call_info, WRITE);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+	data.offset.type = VMMDevHGCMParmType_64bit;
+	data.offset.u.value64 = offset;
+	data.cb.type = VMMDevHGCMParmType_32bit;
+	data.cb.u.value32 = *buf_len;
+	data.buffer.type = VMMDevHGCMParmType_LinAddr_In;
+	data.buffer.u.Pointer.size = *buf_len;
+	data.buffer.u.Pointer.u.linearAddr = (uintptr_t)buf;
+
+	rc = vboxsf_hgcm_call(&data, sizeof(data));
+	if (rc >= 0)
+		*buf_len = data.cb.u.value32;
+
+	return rc;
+}
+
+int vboxsf_write_physcont(SHFLROOT root, SHFLHANDLE file, u64 offset,
+			  u32 *buf_len, u64 phys_buf)
+{
+	HGCMPageListInfo *pg_lst;
+	u32 i, pages, data_len;
+	struct shfl_write *data;
+	int rc;
+
+	pages = PAGE_ALIGN((phys_buf & ~PAGE_MASK) + *buf_len) >> PAGE_SHIFT;
+	data_len = sizeof(struct shfl_write) +
+		   offsetof(HGCMPageListInfo, aPages[pages]);
+
+	data = kmalloc(data_len, GFP_KERNEL);
+	if (!data)
+		return VERR_NO_TMP_MEMORY;
+
+	VBOX_INIT_CALL(&data->call_info, WRITE);
+
+	data->root.type = VMMDevHGCMParmType_32bit;
+	data->root.u.value32 = root;
+
+	data->handle.type = VMMDevHGCMParmType_64bit;
+	data->handle.u.value64 = file;
+	data->offset.type = VMMDevHGCMParmType_64bit;
+	data->offset.u.value64 = offset;
+	data->cb.type = VMMDevHGCMParmType_32bit;
+	data->cb.u.value32 = *buf_len;
+	data->buffer.type = VMMDevHGCMParmType_PageList;
+	data->buffer.u.PageList.size = *buf_len;
+	data->buffer.u.PageList.offset = sizeof(struct shfl_write);
+
+	pg_lst = (HGCMPageListInfo *)(data + 1);
+	pg_lst->flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
+	pg_lst->offFirstPage = (u16)(phys_buf & ~PAGE_MASK);
+	pg_lst->cPages = pages;
+	phys_buf = ALIGN_DOWN(phys_buf, PAGE_SIZE);
+	for (i = 0; i < pages; i++, phys_buf += PAGE_SIZE)
+		pg_lst->aPages[i] = phys_buf;
+
+	rc = vboxsf_hgcm_call(data, data_len);
+	if (rc >= 0)
+		*buf_len = data->cb.u.value32;
+
+	kfree(data);
+	return rc;
+}
+
+int vboxsf_flush(SHFLROOT root, SHFLHANDLE file)
+{
+	struct shfl_flush data;
+
+	VBOX_INIT_CALL(&data.call_info, FLUSH);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_dirinfo(SHFLROOT root, SHFLHANDLE file,
+		   struct shfl_string *parsed_path, u32 flags, u32 index,
+		   u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count)
+{
+	int rc;
+	struct shfl_list data;
+
+	VBOX_INIT_CALL(&data.call_info, LIST);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+	data.flags.type = VMMDevHGCMParmType_32bit;
+	data.flags.u.value32 = flags;
+	data.cb.type = VMMDevHGCMParmType_32bit;
+	data.cb.u.value32 = *buf_len;
+	data.path.type = VMMDevHGCMParmType_LinAddr_In;
+	data.path.u.Pointer.size =
+	    parsed_path ? shfl_string_buf_size(parsed_path) : 0;
+	data.path.u.Pointer.u.linearAddr = (uintptr_t)parsed_path;
+
+	data.buffer.type = VMMDevHGCMParmType_LinAddr_Out;
+	data.buffer.u.Pointer.size = *buf_len;
+	data.buffer.u.Pointer.u.linearAddr = (uintptr_t)buf;
+
+	data.resume_point.type = VMMDevHGCMParmType_32bit;
+	data.resume_point.u.value32 = index;
+	data.file_count.type = VMMDevHGCMParmType_32bit;
+	data.file_count.u.value32 = 0;	/* out parameters only */
+
+	rc = vboxsf_hgcm_call(&data, sizeof(data));
+
+	*buf_len = data.cb.u.value32;
+	*file_count = data.file_count.u.value32;
+
+	return rc;
+}
+
+int vboxsf_fsinfo(SHFLROOT root, SHFLHANDLE file, u32 flags,
+		  u32 *buf_len, void *buf)
+{
+	int rc;
+	struct shfl_information data;
+
+	VBOX_INIT_CALL(&data.call_info, INFORMATION);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+	data.flags.type = VMMDevHGCMParmType_32bit;
+	data.flags.u.value32 = flags;
+	data.cb.type = VMMDevHGCMParmType_32bit;
+	data.cb.u.value32 = *buf_len;
+	data.info.type = VMMDevHGCMParmType_LinAddr;
+	data.info.u.Pointer.size = *buf_len;
+	data.info.u.Pointer.u.linearAddr = (uintptr_t)buf;
+
+	rc = vboxsf_hgcm_call(&data, sizeof(data));
+	if (rc >= 0)
+		*buf_len = data.cb.u.value32;
+
+	return rc;
+}
+
+int vboxsf_lock(SHFLROOT root, SHFLHANDLE file, u64 offset,
+		u64 size, u32 lock)
+{
+	struct shfl_lock data;
+
+	VBOX_INIT_CALL(&data.call_info, LOCK);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.handle.type = VMMDevHGCMParmType_64bit;
+	data.handle.u.value64 = file;
+	data.offset.type = VMMDevHGCMParmType_64bit;
+	data.offset.u.value64 = offset;
+	data.length.type = VMMDevHGCMParmType_64bit;
+	data.length.u.value64 = size;
+
+	data.flags.type = VMMDevHGCMParmType_32bit;
+	data.flags.u.value32 = lock;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_set_utf8(void)
+{
+	VBoxGuestHGCMCallInfo info;
+
+	VBOX_INIT_CALL(&info, SET_UTF8);
+
+	return vboxsf_hgcm_call(&info, sizeof(info));
+}
+
+int vboxsf_readlink(SHFLROOT root, struct shfl_string *parsed_path,
+		    u32 buf_len, u8 *buf)
+{
+	struct shfl_readLink data;
+
+	VBOX_INIT_CALL(&data.call_info, READLINK);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.path.type = VMMDevHGCMParmType_LinAddr_In;
+	data.path.u.Pointer.size = shfl_string_buf_size(parsed_path);
+	data.path.u.Pointer.u.linearAddr = (uintptr_t)parsed_path;
+
+	data.buffer.type = VMMDevHGCMParmType_LinAddr_Out;
+	data.buffer.u.Pointer.size = buf_len;
+	data.buffer.u.Pointer.u.linearAddr = (uintptr_t)buf;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_symlink(SHFLROOT root, struct shfl_string *new_path,
+		   struct shfl_string *old_path, struct shfl_fsobjinfo *buf)
+{
+	struct shfl_symlink data;
+
+	VBOX_INIT_CALL(&data.call_info, SYMLINK);
+
+	data.root.type = VMMDevHGCMParmType_32bit;
+	data.root.u.value32 = root;
+
+	data.new_path.type = VMMDevHGCMParmType_LinAddr_In;
+	data.new_path.u.Pointer.size = shfl_string_buf_size(new_path);
+	data.new_path.u.Pointer.u.linearAddr = (uintptr_t)new_path;
+
+	data.old_path.type = VMMDevHGCMParmType_LinAddr_In;
+	data.old_path.u.Pointer.size = shfl_string_buf_size(old_path);
+	data.old_path.u.Pointer.u.linearAddr = (uintptr_t)old_path;
+
+	data.info.type = VMMDevHGCMParmType_LinAddr_Out;
+	data.info.u.Pointer.size = sizeof(struct shfl_fsobjinfo);
+	data.info.u.Pointer.u.linearAddr = (uintptr_t)buf;
+
+	return vboxsf_hgcm_call(&data, sizeof(data));
+}
+
+int vboxsf_set_symlinks(void)
+{
+	VBoxGuestHGCMCallInfo info;
+
+	VBOX_INIT_CALL(&info, SET_SYMLINKS);
+
+	return vboxsf_hgcm_call(&info, sizeof(info));
+}
diff --git a/fs/vboxsf/vboxsf_wrappers.h b/fs/vboxsf/vboxsf_wrappers.h
new file mode 100644
index 000000000000..97e17a6997c6
--- /dev/null
+++ b/fs/vboxsf/vboxsf_wrappers.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * Protype declarations for the wrapper functions for the shfl host calls.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, in which case the provisions of the CDDL are applicable
+ * instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef VBOXSF_WRAPPERS_H
+#define VBOXSF_WRAPPERS_H
+
+#include <linux/vboxguest.h>	/* For VBoxGuestHGCMCallInfo */
+#include "shfl_hostintf.h"
+
+/**
+ * @addtogroup grp_vboxguest_lib_r0
+ *
+ * Note all these functions (all functions prefixed with vboxsf_)
+ * return a vbox status code rather then a negative errno on error.
+ * @{
+ */
+
+int vboxsf_connect(void);
+void vboxsf_disconnect(void);
+
+int vboxsf_query_mappings(struct shfl_mapping mappings[], u32 *mappings_len);
+int vboxsf_query_mapname(SHFLROOT root, struct shfl_string *string, u32 size);
+
+/**
+ * Create a new file or folder or open an existing one in a shared folder.
+ * Proxies to vbsfCreate in the host shared folder service.
+ *
+ * @returns VBox status code, but see note below
+ * @param   root         Root of the shared folder in which to create the file
+ * @param   parsed_path  The path of the file or folder relative to the shared
+ *                       folder
+ * @param   create_parms Parameters for file/folder creation.  See the
+ *                       structure description in shflsvc.h
+ * @retval  create_parms See the structure description in shflsvc.h
+ *
+ * @note This function reports errors as follows.  The return value is always
+ *       VINF_SUCCESS unless an exceptional condition occurs - out of
+ *       memory, invalid arguments, etc.  If the file or folder could not be
+ *       opened or created, create_parms->handle will be set to
+ *       SHFL_HANDLE_NIL on return.  In this case the value in
+ *       create_parms->result provides information as to why (e.g.
+ *       SHFL_FILE_EXISTS).  create_parms->result is also set on success
+ *       as additional information.
+ */
+int vboxsf_create(SHFLROOT root, struct shfl_string *parsed_path,
+		  struct shfl_createparms *create_parms);
+
+int vboxsf_close(SHFLROOT root, SHFLHANDLE file);
+int vboxsf_remove(SHFLROOT root, struct shfl_string *parsed_path, u32 flags);
+int vboxsf_rename(SHFLROOT root, struct shfl_string *src_path,
+		  struct shfl_string *dest_path, u32 flags);
+int vboxsf_flush(SHFLROOT root, SHFLHANDLE file);
+
+int vboxsf_read(SHFLROOT root, SHFLHANDLE file, u64 offset,
+		u32 *buf_len, u8 *buf);
+int vboxsf_write(SHFLROOT root, SHFLHANDLE file, u64 offset,
+		 u32 *buf_len, u8 *buf);
+int vboxsf_write_physcont(SHFLROOT root, SHFLHANDLE file, u64 offset,
+			  u32 *buf_len, u64 phys_buf);
+
+int vboxsf_lock(SHFLROOT root, SHFLHANDLE file, u64 offset,
+		u64 size, u32 lock);
+
+int vboxsf_dirinfo(SHFLROOT root, SHFLHANDLE file,
+		   struct shfl_string *parsed_path, u32 flags, u32 index,
+		   u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count);
+int vboxsf_fsinfo(SHFLROOT root, SHFLHANDLE file, u32 flags,
+		  u32 *buf_len, void *buf);
+
+int vboxsf_map_folder(struct shfl_string *folder_name, SHFLROOT *root);
+int vboxsf_unmap_folder(SHFLROOT root);
+
+int vboxsf_readlink(SHFLROOT root, struct shfl_string *parsed_path,
+		    u32 buf_len, u8 *buf);
+int vboxsf_symlink(SHFLROOT root, struct shfl_string *new_path,
+		   struct shfl_string *old_path, struct shfl_fsobjinfo *buf);
+
+int vboxsf_set_utf8(void);
+int vboxsf_set_symlinks(void);
+
+/** @} */
+
+#endif
diff --git a/fs/vboxsf/vfsmod.c b/fs/vboxsf/vfsmod.c
new file mode 100644
index 000000000000..ee861e4c0375
--- /dev/null
+++ b/fs/vboxsf/vfsmod.c
@@ -0,0 +1,386 @@
+/*
+ * VirtualBox Guest Shared Folders support: Virtual File System.
+ *
+ * Module initialization/finalization
+ * File system registration/deregistration
+ * Superblock reading
+ * Few utility functions
+ *
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/**
+ * @note Anyone wishing to make changes here might wish to take a look at
+ *  http://www.atnf.csiro.au/people/rgooch/linux/vfs.txt
+ * which seems to be the closest there is to official documentation on
+ * writing filesystem drivers for Linux.
+ */
+
+#include <linux/module.h>
+#include <linux/nls.h>
+#include <linux/vbox_utils.h>
+#include <linux/vbsfmount.h>
+#include "vfsmod.h"
+
+MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access");
+MODULE_AUTHOR("Oracle Corporation");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_FS("vboxsf");
+
+/* forward declarations */
+static struct super_operations sf_super_ops;
+
+/* allocate global info, try to map host share */
+static int sf_glob_alloc(struct vbsf_mount_info_new *info,
+			 struct sf_glob_info **sf_gp)
+{
+	int err, rc;
+	size_t name_len, str_len;
+	struct sf_glob_info *sf_g;
+	struct shfl_string *str_name = NULL;
+#ifdef CONFIG_NLS_DEFAULT
+	const char *nls_name = CONFIG_NLS_DEFAULT;
+#else
+	const char *nls_name = "";
+#endif
+
+	if (info->nullchar != '\0' ||
+	    info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0 ||
+	    info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1 ||
+	    info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2)
+		return -EINVAL;
+
+	sf_g = kzalloc(sizeof(*sf_g), GFP_KERNEL);
+	if (!sf_g)
+		return -ENOMEM;
+
+	info->name[sizeof(info->name) - 1] = 0;
+	info->nls_name[sizeof(info->nls_name) - 1] = 0;
+
+	name_len = strlen(info->name);
+	str_len = offsetof(struct shfl_string, string.utf8) + name_len + 1;
+
+	str_name = kmalloc(str_len, GFP_KERNEL);
+	if (!str_name) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	str_name->length = name_len;
+	str_name->size = name_len + 1;
+	memcpy(str_name->string.utf8, info->name, name_len + 1);
+
+	if (info->nls_name[0])
+		nls_name = info->nls_name;
+
+	/* Load nls if not utf8 */
+	if (nls_name[0] && strcmp(nls_name, "utf8") != 0) {
+		sf_g->nls = load_nls(info->nls_name);
+		if (!sf_g->nls) {
+			err = -EINVAL;
+			goto fail;
+		}
+	} else {
+		sf_g->nls = NULL;
+	}
+
+	rc = vboxsf_map_folder(str_name, &sf_g->root);
+	if (rc < 0) {
+		err = -EPROTO;
+		goto fail;
+	}
+
+	kfree(str_name);
+
+	sf_g->ttl = info->ttl;
+	sf_g->uid = info->uid;
+	sf_g->gid = info->gid;
+
+	if ((size_t)info->length >= sizeof(struct vbsf_mount_info_new)) {
+		/* new fields */
+		sf_g->dmode = info->dmode;
+		sf_g->fmode = info->fmode;
+		sf_g->dmask = info->dmask;
+		sf_g->fmask = info->fmask;
+	} else {
+		sf_g->dmode = ~0;
+		sf_g->fmode = ~0;
+	}
+
+	*sf_gp = sf_g;
+	return 0;
+
+fail:
+	if (sf_g->nls)
+		unload_nls(sf_g->nls);
+
+	kfree(str_name);
+	kfree(sf_g);
+
+	return err;
+}
+
+/* unmap the share and free global info [sf_g] */
+static void sf_glob_free(struct sf_glob_info *sf_g)
+{
+	vboxsf_unmap_folder(sf_g->root);
+
+	if (sf_g->nls)
+		unload_nls(sf_g->nls);
+
+	kfree(sf_g);
+}
+
+/**
+ * This is called when vfs mounts the fs and wants to read the super_block.
+ *
+ * calls [sf_glob_alloc] to map the folder and allocate global
+ * information structure.
+ *
+ * initializes [sb], initializes root inode and dentry.
+ *
+ * should respect [flags]
+ */
+static int sf_read_super(struct super_block *sb, void *data, int flags)
+{
+	int err;
+	struct dentry *droot;
+	struct inode *iroot;
+	struct sf_inode_info *sf_i;
+	struct sf_glob_info *sf_g;
+	struct shfl_fsobjinfo fsinfo;
+	struct vbsf_mount_info_new *info;
+
+	if (!data)
+		return -EINVAL;
+
+	info = data;
+
+	if (flags & MS_REMOUNT)
+		return -EINVAL;
+
+	err = sf_glob_alloc(info, &sf_g);
+	if (err)
+		goto fail0;
+
+	sf_i = kmalloc(sizeof(*sf_i), GFP_KERNEL);
+	if (!sf_i) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	sf_i->handle = SHFL_HANDLE_NIL;
+	sf_i->path = kmalloc(sizeof(struct shfl_string) + 1, GFP_KERNEL);
+	if (!sf_i->path) {
+		err = -ENOMEM;
+		goto fail2;
+	}
+
+	sf_i->path->length = 1;
+	sf_i->path->size = 2;
+	sf_i->path->string.utf8[0] = '/';
+	sf_i->path->string.utf8[1] = 0;
+	sf_i->force_reread = 0;
+
+	err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
+	if (err)
+		goto fail3;
+
+	sb->s_magic = 0xface;
+	sb->s_blocksize = 1024;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
+	sb->s_op = &sf_super_ops;
+
+	iroot = iget_locked(sb, 0);
+	if (!iroot) {
+		err = -ENOMEM;	/* XXX */
+		goto fail3;
+	}
+
+	sf_init_inode(sf_g, iroot, &fsinfo);
+	SET_INODE_INFO(iroot, sf_i);
+
+	unlock_new_inode(iroot);
+
+	droot = d_make_root(iroot);
+	if (!droot) {
+		err = -ENOMEM;
+		goto fail3;
+	}
+
+	sb->s_root = droot;
+	SET_GLOB_INFO(sb, sf_g);
+	return 0;
+
+fail3:
+	kfree(sf_i->path);
+
+fail2:
+	kfree(sf_i);
+
+fail1:
+	sf_glob_free(sf_g);
+
+fail0:
+	return err;
+}
+
+/*
+ * This is called when vfs is about to destroy the [inode]. all
+ * resources associated with this [inode] must be cleared here.
+ */
+static void sf_evict_inode(struct inode *inode)
+{
+	struct sf_inode_info *sf_i;
+
+	truncate_inode_pages(&inode->i_data, 0);
+	clear_inode(inode);
+
+	sf_i = GET_INODE_INFO(inode);
+	if (!sf_i)
+		return;
+
+	kfree(sf_i->path);
+	kfree(sf_i);
+	SET_INODE_INFO(inode, NULL);
+}
+
+/*
+ * vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
+ * the folder and free [sf_g]
+ */
+static void sf_put_super(struct super_block *sb)
+{
+	struct sf_glob_info *sf_g;
+
+	sf_g = GET_GLOB_INFO(sb);
+	sf_glob_free(sf_g);
+}
+
+static int sf_statfs(struct dentry *dentry, struct kstatfs *stat)
+{
+	struct super_block *sb = dentry->d_inode->i_sb;
+
+	return sf_get_volume_info(sb, stat);
+}
+
+static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	struct sf_glob_info *sf_g;
+	struct sf_inode_info *sf_i;
+	struct inode *iroot;
+	struct shfl_fsobjinfo fsinfo;
+	int err;
+
+	sf_g = GET_GLOB_INFO(sb);
+	if (data && data[0] != 0) {
+		struct vbsf_mount_info_new *info =
+		    (struct vbsf_mount_info_new *)data;
+		if (info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0
+		    && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1
+		    && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2) {
+			sf_g->uid = info->uid;
+			sf_g->gid = info->gid;
+			sf_g->ttl = info->ttl;
+			sf_g->dmode = info->dmode;
+			sf_g->fmode = info->fmode;
+			sf_g->dmask = info->dmask;
+			sf_g->fmask = info->fmask;
+		}
+	}
+
+	iroot = ilookup(sb, 0);
+	if (!iroot)
+		return -ENOENT;
+
+	sf_i = GET_INODE_INFO(iroot);
+	err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
+	sf_init_inode(sf_g, iroot, &fsinfo);
+
+	return 0;
+}
+
+static struct super_operations sf_super_ops = {
+	.evict_inode = sf_evict_inode,
+	.put_super = sf_put_super,
+	.statfs = sf_statfs,
+	.remount_fs = sf_remount_fs
+};
+
+static struct dentry *sf_mount(struct file_system_type *fs_type, int flags,
+			       const char *dev_name, void *data)
+{
+	return mount_nodev(fs_type, flags, data, sf_read_super);
+}
+
+static struct file_system_type vboxsf_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "vboxsf",
+	.mount = sf_mount,
+	.kill_sb = kill_anon_super
+};
+
+static int follow_symlinks;
+module_param(follow_symlinks, int, 0444);
+MODULE_PARM_DESC(follow_symlinks,
+		 "Let host resolve symlinks rather than showing them");
+
+/* Module initialization/finalization handlers */
+static int __init init(void)
+{
+	int rc, err;
+
+	if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE) {
+		vbg_err("vboxsf: Mount information structure is too large %zd; Must be less than or equal to %ld\n",
+			sizeof(struct vbsf_mount_info_new), PAGE_SIZE);
+		return -EINVAL;
+	}
+
+	err = register_filesystem(&vboxsf_fs_type);
+	if (err)
+		return err;
+
+	rc = vboxsf_connect();
+	if (rc < 0) {
+		vbg_err("vboxsf_Connect failed, rc=%d\n", rc);
+		err = -EPROTO;
+		goto fail1;
+	}
+
+	rc = vboxsf_set_utf8();
+	if (rc < 0) {
+		vbg_err("vboxsf_setutf8 failed, rc=%d\n", rc);
+		err = -EPROTO;
+		goto fail2;
+	}
+
+	if (!follow_symlinks) {
+		rc = vboxsf_set_symlinks();
+		if (rc < 0) {
+			vbg_warn("vboxsf: Host unable to show symlinks, rc=%d\n",
+				 rc);
+		}
+	}
+
+	return 0;
+
+fail2:
+	vboxsf_disconnect();
+
+fail1:
+	unregister_filesystem(&vboxsf_fs_type);
+	return err;
+}
+
+static void __exit fini(void)
+{
+	vboxsf_disconnect();
+	unregister_filesystem(&vboxsf_fs_type);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/fs/vboxsf/vfsmod.h b/fs/vboxsf/vfsmod.h
new file mode 100644
index 000000000000..93e8791eea9a
--- /dev/null
+++ b/fs/vboxsf/vfsmod.h
@@ -0,0 +1,113 @@
+/*
+ * VirtualBox Guest Shared Folders support: module header.
+ *
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef VFSMOD_H
+#define VFSMOD_H
+
+#include <linux/backing-dev.h>
+#include <linux/version.h>
+#include "vboxsf_wrappers.h"
+
+#define DIR_BUFFER_SIZE SZ_16K
+
+/* per-shared folder information */
+struct sf_glob_info {
+	SHFLROOT root;
+	struct nls_table *nls;
+	int ttl;
+	int uid;
+	int gid;
+	int dmode;
+	int fmode;
+	int dmask;
+	int fmask;
+};
+
+/* per-inode information */
+struct sf_inode_info {
+	/* which file */
+	struct shfl_string *path;
+	/* some information was changed, update data on next revalidate */
+	int force_restat;
+	/*
+	 * directory content changed, update the whole directory on next
+	 * sf_getdent
+	 */
+	int force_reread;
+	/* file structure, only valid between open() and release() */
+	struct file *file;
+	/*
+	 * handle valid if a file was created with sf_create_aux until it
+	 * will be opened with sf_reg_open()
+	 */
+	SHFLHANDLE handle;
+};
+
+struct sf_dir_info {
+	struct list_head info_list;
+};
+
+struct sf_dir_buf {
+	size_t entries;
+	size_t free;
+	size_t used;
+	void *buf;
+	struct list_head head;
+};
+
+struct sf_reg_info {
+	SHFLHANDLE handle;
+};
+
+/* globals */
+extern const struct inode_operations sf_dir_iops;
+extern const struct inode_operations sf_lnk_iops;
+extern const struct inode_operations sf_reg_iops;
+extern const struct file_operations sf_dir_fops;
+extern const struct file_operations sf_reg_fops;
+extern const struct dentry_operations sf_dentry_ops;
+extern const struct address_space_operations sf_reg_aops;
+
+void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode,
+		   const struct shfl_fsobjinfo *info);
+int sf_stat(const char *caller, struct sf_glob_info *sf_g,
+	    struct shfl_string *path, struct shfl_fsobjinfo *result,
+	    int ok_to_fail);
+int sf_inode_revalidate(struct dentry *dentry);
+int sf_getattr(const struct path *path, struct kstat *kstat,
+	       u32 request_mask, unsigned int query_flags);
+int sf_setattr(struct dentry *dentry, struct iattr *iattr);
+int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
+			struct sf_inode_info *sf_i,
+			struct dentry *dentry, struct shfl_string **result);
+int sf_nlscpy(struct sf_glob_info *sf_g, char *name,
+	      size_t name_bound_len, const unsigned char *utf8_name,
+	      size_t utf8_len);
+void sf_dir_info_free(struct sf_dir_info *p);
+void sf_dir_info_empty(struct sf_dir_info *p);
+struct sf_dir_info *sf_dir_info_alloc(void);
+int sf_dir_read_all(struct sf_glob_info *sf_g,
+		    struct sf_inode_info *sf_i, struct sf_dir_info *sf_d,
+		    SHFLHANDLE handle);
+int sf_get_volume_info(struct super_block *sb, struct kstatfs *stat);
+
+/*
+ * Following casts are here to prevent assignment of void * to
+ * pointers of arbitrary type.
+ */
+#define GET_GLOB_INFO(sb)       ((struct sf_glob_info *)(sb)->s_fs_info)
+#define SET_GLOB_INFO(sb, sf_g) ((sb)->s_fs_info = (sf_g))
+
+#define GET_INODE_INFO(i)       ((struct sf_inode_info *)(i)->i_private)
+#define SET_INODE_INFO(i, sf_i) ((i)->i_private = (sf_i))
+
+#define GET_F_DENTRY(f)         (f->f_path.dentry)
+
+#endif
diff --git a/include/uapi/linux/vbsfmount.h b/include/uapi/linux/vbsfmount.h
new file mode 100644
index 000000000000..21aa546a2a64
--- /dev/null
+++ b/include/uapi/linux/vbsfmount.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2006-2016 Oracle Corporation
+ *
+ * VirtualBox Guest Shared Folders: mount(2) parameter structure.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef VBFS_MOUNT_H
+#define VBFS_MOUNT_H
+
+/* Linux constraints the size of data mount argument to PAGE_SIZE - 1. */
+#define MAX_HOST_NAME  256
+#define MAX_NLS_NAME    32
+
+#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\377')
+#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\376')
+#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\375')
+
+struct vbsf_mount_info_new {
+	/*
+	 * The old version of the mount_info struct started with a
+	 * char name[MAX_HOST_NAME] field, where name cannot be '\0'.
+	 * So the new version of the mount_info struct starts with a
+	 * nullchar field which is always 0 so that we can detect and
+	 * reject the old structure being passed.
+	 */
+	char nullchar;
+	char signature[3];	/* signature */
+	int length;		/* length of the whole structure */
+	char name[MAX_HOST_NAME];	/* share name */
+	char nls_name[MAX_NLS_NAME];	/* name of an I/O charset */
+	int uid;		/* user ID for all entries, default 0=root */
+	int gid;		/* group ID for all entries, default 0=root */
+	int ttl;		/* time to live */
+	int dmode;		/* mode for directories if != 0xffffffff */
+	int fmode;		/* mode for regular files if != 0xffffffff */
+	int dmask;		/* umask applied to directories */
+	int fmask;		/* umask applied to regular files */
+};
+
+struct vbsf_mount_opts {
+	int uid;
+	int gid;
+	int ttl;
+	int dmode;
+	int fmode;
+	int dmask;
+	int fmask;
+	int ronly;
+	int sloppy;
+	int noexec;
+	int nodev;
+	int nosuid;
+	int remount;
+	char nls_name[MAX_NLS_NAME];
+	char *convertcp;
+};
+
+#endif /* vbsfmount.h */
-- 
2.13.4

  parent reply	other threads:[~2017-08-25 14:38 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-25 14:37 [RFC v2 0/2] Add Virtual Box vboxguest and vboxsf guest drivers to the mainline kernel Hans de Goede
2017-08-25 14:37 ` [RFC v2 1/2] virt: Add vboxguest driver for Virtual Box Guest integration Hans de Goede
2017-08-25 14:58   ` Christoph Hellwig
2017-08-25 15:00     ` Hans de Goede
2017-08-25 15:03       ` Christoph Hellwig
2017-08-25 15:06         ` Hans de Goede
2017-08-25 15:09           ` Christoph Hellwig
2017-08-25 15:13             ` Hans de Goede
2017-08-25 15:19               ` Christoph Hellwig
2017-08-25 14:37 ` Hans de Goede [this message]
2017-08-25 15:02   ` [RFC v2 2/2] fs: Add VirtualBox guest shared folder (vboxsf) support Christoph Hellwig

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170825143732.10836-3-hdegoede@redhat.com \
    --to=hdegoede@redhat.com \
    --cc=Larry.Finger@lwfinger.net \
    --cc=arnd@arndb.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=knut.osmundsen@oracle.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.thayer@oracle.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.