vfsmod.c revision c161379f4055372228230517aa1700c47e3b9b7f
6a67d144095c31bbafed93cec1619590157335eajvergara/** @file
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * vboxsf -- VirtualBox Guest Additions for Linux:
6a67d144095c31bbafed93cec1619590157335eajvergara * Virtual File System for VirtualBox Shared Folders
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * Module initialization/finalization
6a67d144095c31bbafed93cec1619590157335eajvergara * File system registration/deregistration
6a67d144095c31bbafed93cec1619590157335eajvergara * Superblock reading
6a67d144095c31bbafed93cec1619590157335eajvergara * Few utility functions
6a67d144095c31bbafed93cec1619590157335eajvergara */
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/*
6a67d144095c31bbafed93cec1619590157335eajvergara * Copyright (C) 2006-2010 Oracle Corporation
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * This file is part of VirtualBox Open Source Edition (OSE), as
6a67d144095c31bbafed93cec1619590157335eajvergara * available from http://www.virtualbox.org. This file is free software;
6a67d144095c31bbafed93cec1619590157335eajvergara * you can redistribute it and/or modify it under the terms of the GNU
6a67d144095c31bbafed93cec1619590157335eajvergara * General Public License (GPL) as published by the Free Software
6a67d144095c31bbafed93cec1619590157335eajvergara * Foundation, in version 2 as it comes in the "COPYING" file of the
6a67d144095c31bbafed93cec1619590157335eajvergara * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6a67d144095c31bbafed93cec1619590157335eajvergara * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
6a67d144095c31bbafed93cec1619590157335eajvergara */
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/**
6a67d144095c31bbafed93cec1619590157335eajvergara * @note Anyone wishing to make changes here might wish to take a look at
6a67d144095c31bbafed93cec1619590157335eajvergara * http://www.atnf.csiro.au/people/rgooch/linux/vfs.txt
6a67d144095c31bbafed93cec1619590157335eajvergara * which seems to be the closest there is to official documentation on
6a67d144095c31bbafed93cec1619590157335eajvergara * writing filesystem drivers for Linux.
6a67d144095c31bbafed93cec1619590157335eajvergara */
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#include "vfsmod.h"
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergaraMODULE_DESCRIPTION(VBOX_PRODUCT " VFS Module for Host File System Access");
6a67d144095c31bbafed93cec1619590157335eajvergaraMODULE_AUTHOR(VBOX_VENDOR);
6a67d144095c31bbafed93cec1619590157335eajvergaraMODULE_LICENSE("GPL");
6a67d144095c31bbafed93cec1619590157335eajvergara#ifdef MODULE_VERSION
6a67d144095c31bbafed93cec1619590157335eajvergaraMODULE_VERSION(VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")");
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* globals */
6a67d144095c31bbafed93cec1619590157335eajvergaraVBSFCLIENT client_handle;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* forward declarations */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic struct super_operations sf_super_ops;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* allocate global info, try to map host share */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int sf_glob_alloc(struct vbsf_mount_info_new *info, struct sf_glob_info **sf_gp)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara int err, rc;
6a67d144095c31bbafed93cec1619590157335eajvergara SHFLSTRING *str_name;
6a67d144095c31bbafed93cec1619590157335eajvergara size_t name_len, str_len;
6a67d144095c31bbafed93cec1619590157335eajvergara struct sf_glob_info *sf_g;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g = kmalloc(sizeof(*sf_g), GFP_KERNEL);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!sf_g)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENOMEM;
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("could not allocate memory for global info\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail0;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara RT_ZERO(*sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if ( info->nullchar != '\0'
6a67d144095c31bbafed93cec1619590157335eajvergara || info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
6a67d144095c31bbafed93cec1619590157335eajvergara || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
6a67d144095c31bbafed93cec1619590157335eajvergara || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara /* An old version of mount.vboxsf made the syscall. Translate the
6a67d144095c31bbafed93cec1619590157335eajvergara * old parameters to the new structure. */
6a67d144095c31bbafed93cec1619590157335eajvergara struct vbsf_mount_info_old *info_old = (struct vbsf_mount_info_old *)info;
6a67d144095c31bbafed93cec1619590157335eajvergara static struct vbsf_mount_info_new info_compat;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara info = &info_compat;
6a67d144095c31bbafed93cec1619590157335eajvergara memset(info, 0, sizeof(*info));
6a67d144095c31bbafed93cec1619590157335eajvergara memcpy(&info->name, &info_old->name, MAX_HOST_NAME);
6a67d144095c31bbafed93cec1619590157335eajvergara memcpy(&info->nls_name, &info_old->nls_name, MAX_NLS_NAME);
6a67d144095c31bbafed93cec1619590157335eajvergara info->length = offsetof(struct vbsf_mount_info_new, dmode);
6a67d144095c31bbafed93cec1619590157335eajvergara info->uid = info_old->uid;
6a67d144095c31bbafed93cec1619590157335eajvergara info->gid = info_old->gid;
6a67d144095c31bbafed93cec1619590157335eajvergara info->ttl = info_old->ttl;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara info->name[sizeof(info->name) - 1] = 0;
6a67d144095c31bbafed93cec1619590157335eajvergara info->nls_name[sizeof(info->nls_name) - 1] = 0;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara name_len = strlen(info->name);
6a67d144095c31bbafed93cec1619590157335eajvergara if (name_len > 0xfffe)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENAMETOOLONG;
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("map name too big\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail1;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara str_len = offsetof(SHFLSTRING, String.utf8) + name_len + 1;
6a67d144095c31bbafed93cec1619590157335eajvergara str_name = kmalloc(str_len, GFP_KERNEL);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!str_name)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENOMEM;
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("could not allocate memory for host name\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail1;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara str_name->u16Length = name_len;
6a67d144095c31bbafed93cec1619590157335eajvergara str_name->u16Size = name_len + 1;
6a67d144095c31bbafed93cec1619590157335eajvergara memcpy(str_name->String.utf8, info->name, name_len + 1);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if (info->nls_name[0] && strcmp(info->nls_name, "utf8"))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->nls = load_nls(info->nls_name);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!sf_g->nls)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -EINVAL;
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("failed to load nls %s\n", info->nls_name));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail1;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara else
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->nls = NULL;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara rc = vboxCallMapFolder(&client_handle, str_name, &sf_g->map);
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(str_name);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if (RT_FAILURE(rc))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -EPROTO;
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("vboxCallMapFolder failed rc=%d\n", rc));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail2;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->ttl = info->ttl;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->uid = info->uid;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->gid = info->gid;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara /* new fields */
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->dmode = info->dmode;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->fmode = info->fmode;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->dmask = info->dmask;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->fmask = info->fmask;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara else
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->dmode = ~0;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g->fmode = ~0;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara *sf_gp = sf_g;
6a67d144095c31bbafed93cec1619590157335eajvergara return 0;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail2:
6a67d144095c31bbafed93cec1619590157335eajvergara if (sf_g->nls)
6a67d144095c31bbafed93cec1619590157335eajvergara unload_nls(sf_g->nls);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail1:
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail0:
6a67d144095c31bbafed93cec1619590157335eajvergara return err;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* unmap the share and free global info [sf_g] */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void
6a67d144095c31bbafed93cec1619590157335eajvergarasf_glob_free(struct sf_glob_info *sf_g)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara int rc;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara rc = vboxCallUnmapFolder(&client_handle, &sf_g->map);
6a67d144095c31bbafed93cec1619590157335eajvergara if (RT_FAILURE(rc))
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("vboxCallUnmapFolder failed rc=%d\n", rc));
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if (sf_g->nls)
6a67d144095c31bbafed93cec1619590157335eajvergara unload_nls(sf_g->nls);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/**
6a67d144095c31bbafed93cec1619590157335eajvergara * This is called (by sf_read_super_[24|26] when vfs mounts the fs and
6a67d144095c31bbafed93cec1619590157335eajvergara * wants to read super_block.
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * calls [sf_glob_alloc] to map the folder and allocate global
6a67d144095c31bbafed93cec1619590157335eajvergara * information structure.
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * initializes [sb], initializes root inode and dentry.
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * should respect [flags]
6a67d144095c31bbafed93cec1619590157335eajvergara */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int sf_read_super_aux(struct super_block *sb, void *data, int flags)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara int err;
6a67d144095c31bbafed93cec1619590157335eajvergara struct dentry *droot;
6a67d144095c31bbafed93cec1619590157335eajvergara struct inode *iroot;
6a67d144095c31bbafed93cec1619590157335eajvergara struct sf_inode_info *sf_i;
6a67d144095c31bbafed93cec1619590157335eajvergara struct sf_glob_info *sf_g;
6a67d144095c31bbafed93cec1619590157335eajvergara SHFLFSOBJINFO fsinfo;
6a67d144095c31bbafed93cec1619590157335eajvergara struct vbsf_mount_info_new *info;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara if (!data)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("no mount info specified\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara return -EINVAL;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara info = data;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if (flags & MS_REMOUNT)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("remounting is not supported\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara return -ENOSYS;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara err = sf_glob_alloc(info, &sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara if (err)
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail0;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i = kmalloc(sizeof (*sf_i), GFP_KERNEL);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!sf_i)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENOMEM;
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("could not allocate memory for root inode info\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail1;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i->handle = SHFL_HANDLE_NIL;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!sf_i->path)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENOMEM;
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("could not allocate memory for root inode path\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail2;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i->path->u16Length = 1;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i->path->u16Size = 2;
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i->path->String.utf8[0] = '/';
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i->path->String.utf8[1] = 0;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
6a67d144095c31bbafed93cec1619590157335eajvergara if (err)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("could not stat root of share\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail3;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sb->s_magic = 0xface;
6a67d144095c31bbafed93cec1619590157335eajvergara sb->s_blocksize = 1024;
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 3)
6a67d144095c31bbafed93cec1619590157335eajvergara /* Required for seek/sendfile.
6a67d144095c31bbafed93cec1619590157335eajvergara *
6a67d144095c31bbafed93cec1619590157335eajvergara * Must by less than or equal to INT64_MAX despite the fact that the
6a67d144095c31bbafed93cec1619590157335eajvergara * declaration of this variable is unsigned long long. See determination
6a67d144095c31bbafed93cec1619590157335eajvergara * of 'loff_t max' in fs/read_write.c / do_sendfile(). I don't know the
6a67d144095c31bbafed93cec1619590157335eajvergara * correct limit but MAX_LFS_FILESIZE (8TB-1 on 32-bit boxes) takes the
6a67d144095c31bbafed93cec1619590157335eajvergara * page cache into account and is the suggested limit. */
6a67d144095c31bbafed93cec1619590157335eajvergara# if defined MAX_LFS_FILESIZE
6a67d144095c31bbafed93cec1619590157335eajvergara sb->s_maxbytes = MAX_LFS_FILESIZE;
6a67d144095c31bbafed93cec1619590157335eajvergara# else
6a67d144095c31bbafed93cec1619590157335eajvergara sb->s_maxbytes = 0x7fffffffffffffffULL;
6a67d144095c31bbafed93cec1619590157335eajvergara# endif
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara sb->s_op = &sf_super_ops;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
6a67d144095c31bbafed93cec1619590157335eajvergara iroot = iget_locked(sb, 0);
6a67d144095c31bbafed93cec1619590157335eajvergara#else
6a67d144095c31bbafed93cec1619590157335eajvergara iroot = iget(sb, 0);
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara if (!iroot)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENOMEM; /* XXX */
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("could not get root inode\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail3;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if (sf_init_backing_dev(sf_g, info->name))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -EINVAL;
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("could not init bdi\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail4;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_init_inode(sf_g, iroot, &fsinfo);
6a67d144095c31bbafed93cec1619590157335eajvergara SET_INODE_INFO(iroot, sf_i);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
6a67d144095c31bbafed93cec1619590157335eajvergara unlock_new_inode(iroot);
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara droot = d_alloc_root(iroot);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!droot)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara err = -ENOMEM; /* XXX */
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("d_alloc_root failed\n"));
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail5;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sb->s_root = droot;
6a67d144095c31bbafed93cec1619590157335eajvergara SET_GLOB_INFO(sb, sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara return 0;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail5:
6a67d144095c31bbafed93cec1619590157335eajvergara sf_done_backing_dev(sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail4:
6a67d144095c31bbafed93cec1619590157335eajvergara iput(iroot);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail3:
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_i->path);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail2:
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_i);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail1:
6a67d144095c31bbafed93cec1619590157335eajvergara sf_glob_free(sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail0:
6a67d144095c31bbafed93cec1619590157335eajvergara return err;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic struct super_block *
6a67d144095c31bbafed93cec1619590157335eajvergarasf_read_super_24(struct super_block *sb, void *data, int flags)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara int err;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara err = sf_read_super_aux(sb, data, flags);
6a67d144095c31bbafed93cec1619590157335eajvergara if (err)
6a67d144095c31bbafed93cec1619590157335eajvergara return NULL;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara return sb;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* this is called when vfs is about to destroy the [inode]. all
6a67d144095c31bbafed93cec1619590157335eajvergara resources associated with this [inode] must be cleared here */
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void sf_clear_inode(struct inode *inode)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara struct sf_inode_info *sf_i;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i = GET_INODE_INFO(inode);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!sf_i)
6a67d144095c31bbafed93cec1619590157335eajvergara return;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara BUG_ON(!sf_i->path);
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_i->path);
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_i);
6a67d144095c31bbafed93cec1619590157335eajvergara SET_INODE_INFO(inode, NULL);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#else
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void sf_evict_inode(struct inode *inode)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara struct sf_inode_info *sf_i;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara truncate_inode_pages(&inode->i_data, 0);
6a67d144095c31bbafed93cec1619590157335eajvergara end_writeback(inode);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_i = GET_INODE_INFO(inode);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!sf_i)
6a67d144095c31bbafed93cec1619590157335eajvergara return;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara BUG_ON(!sf_i->path);
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_i->path);
6a67d144095c31bbafed93cec1619590157335eajvergara kfree(sf_i);
6a67d144095c31bbafed93cec1619590157335eajvergara SET_INODE_INFO(inode, NULL);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* this is called by vfs when it wants to populate [inode] with data.
6a67d144095c31bbafed93cec1619590157335eajvergara the only thing that is known about inode at this point is its index
6a67d144095c31bbafed93cec1619590157335eajvergara hence we can't do anything here, and let lookup/whatever with the
6a67d144095c31bbafed93cec1619590157335eajvergara job to properly fill then [inode] */
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void sf_read_inode(struct inode *inode)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
6a67d144095c31bbafed93cec1619590157335eajvergara the folder and free [sf_g] */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void sf_put_super(struct super_block *sb)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara struct sf_glob_info *sf_g;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara sf_g = GET_GLOB_INFO(sb);
6a67d144095c31bbafed93cec1619590157335eajvergara BUG_ON(!sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara sf_done_backing_dev(sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara sf_glob_free(sf_g);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int sf_statfs(struct super_block *sb, STRUCT_STATFS *stat)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara return sf_get_volume_info(sb, stat);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#else
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int sf_statfs(struct dentry *dentry, STRUCT_STATFS *stat)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara struct super_block *sb = dentry->d_inode->i_sb;
6a67d144095c31bbafed93cec1619590157335eajvergara return sf_get_volume_info(sb, stat);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int sf_remount_fs(struct super_block *sb, int *flags, char *data)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara return -ENOSYS;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarastatic struct super_operations sf_super_ops =
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
6a67d144095c31bbafed93cec1619590157335eajvergara .clear_inode = sf_clear_inode,
6a67d144095c31bbafed93cec1619590157335eajvergara#else
6a67d144095c31bbafed93cec1619590157335eajvergara .evict_inode = sf_evict_inode,
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
6a67d144095c31bbafed93cec1619590157335eajvergara .read_inode = sf_read_inode,
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara .put_super = sf_put_super,
6a67d144095c31bbafed93cec1619590157335eajvergara .statfs = sf_statfs,
6a67d144095c31bbafed93cec1619590157335eajvergara .remount_fs = sf_remount_fs
6a67d144095c31bbafed93cec1619590157335eajvergara};
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic DECLARE_FSTYPE(vboxsf_fs_type, "vboxsf", sf_read_super_24, 0);
6a67d144095c31bbafed93cec1619590157335eajvergara#else
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int
6a67d144095c31bbafed93cec1619590157335eajvergarasf_read_super_26(struct super_block *sb, void *data, int flags)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara int err;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara err = sf_read_super_aux(sb, data, flags);
6a67d144095c31bbafed93cec1619590157335eajvergara if (err)
6a67d144095c31bbafed93cec1619590157335eajvergara printk(KERN_DEBUG "sf_read_super_aux err=%d\n", err);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara return err;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic struct super_block *sf_get_sb(struct file_system_type *fs_type, int flags,
6a67d144095c31bbafed93cec1619590157335eajvergara const char *dev_name, void *data)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara return get_sb_nodev(fs_type, flags, data, sf_read_super_26);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#else
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int sf_get_sb(struct file_system_type *fs_type, int flags,
6a67d144095c31bbafed93cec1619590157335eajvergara const char *dev_name, void *data, struct vfsmount *mnt)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara return get_sb_nodev(fs_type, flags, data, sf_read_super_26, mnt);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarastatic struct file_system_type vboxsf_fs_type =
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara .owner = THIS_MODULE,
6a67d144095c31bbafed93cec1619590157335eajvergara .name = "vboxsf",
6a67d144095c31bbafed93cec1619590157335eajvergara .get_sb = sf_get_sb,
6a67d144095c31bbafed93cec1619590157335eajvergara .kill_sb = kill_anon_super
6a67d144095c31bbafed93cec1619590157335eajvergara};
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int follow_symlinks = 0;
6a67d144095c31bbafed93cec1619590157335eajvergaramodule_param(follow_symlinks, bool, 0);
6a67d144095c31bbafed93cec1619590157335eajvergaraMODULE_PARM_DESC(follow_symlinks, "Let host resolve symlinks rather than showing them");
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* Module initialization/finalization handlers */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic int __init init(void)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara int rcVBox;
6a67d144095c31bbafed93cec1619590157335eajvergara int rcRet = 0;
6a67d144095c31bbafed93cec1619590157335eajvergara int err;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara printk(KERN_ERR
6a67d144095c31bbafed93cec1619590157335eajvergara "Mount information structure is too large %lu\n"
6a67d144095c31bbafed93cec1619590157335eajvergara "Must be less than or equal to %lu\n",
6a67d144095c31bbafed93cec1619590157335eajvergara (unsigned long)sizeof (struct vbsf_mount_info_new),
6a67d144095c31bbafed93cec1619590157335eajvergara (unsigned long)PAGE_SIZE);
6a67d144095c31bbafed93cec1619590157335eajvergara return -EINVAL;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara err = register_filesystem(&vboxsf_fs_type);
6a67d144095c31bbafed93cec1619590157335eajvergara if (err)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogFunc(("register_filesystem err=%d\n", err));
6a67d144095c31bbafed93cec1619590157335eajvergara return err;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara rcVBox = vboxInit();
6a67d144095c31bbafed93cec1619590157335eajvergara if (RT_FAILURE(rcVBox))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("vboxInit failed, rc=%d\n", rcVBox));
6a67d144095c31bbafed93cec1619590157335eajvergara rcRet = -EPROTO;
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail0;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara rcVBox = vboxConnect(&client_handle);
6a67d144095c31bbafed93cec1619590157335eajvergara if (RT_FAILURE(rcVBox))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("vboxConnect failed, rc=%d\n", rcVBox));
6a67d144095c31bbafed93cec1619590157335eajvergara rcRet = -EPROTO;
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail1;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara rcVBox = vboxCallSetUtf8(&client_handle);
6a67d144095c31bbafed93cec1619590157335eajvergara if (RT_FAILURE(rcVBox))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara LogRelFunc(("vboxCallSetUtf8 failed, rc=%d\n", rcVBox));
6a67d144095c31bbafed93cec1619590157335eajvergara rcRet = -EPROTO;
6a67d144095c31bbafed93cec1619590157335eajvergara goto fail2;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
6a67d144095c31bbafed93cec1619590157335eajvergara if (!follow_symlinks)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara rcVBox = vboxCallSetSymlinks(&client_handle);
6a67d144095c31bbafed93cec1619590157335eajvergara if (RT_FAILURE(rcVBox))
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara printk(KERN_WARNING
6a67d144095c31bbafed93cec1619590157335eajvergara "vboxsf: Host unable to show symlinks, rc=%d\n",
6a67d144095c31bbafed93cec1619590157335eajvergara rcVBox);
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara printk(KERN_DEBUG
6a67d144095c31bbafed93cec1619590157335eajvergara "vboxsf: Successfully loaded version " VBOX_VERSION_STRING
6a67d144095c31bbafed93cec1619590157335eajvergara " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara return 0;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail2:
6a67d144095c31bbafed93cec1619590157335eajvergara vboxDisconnect(&client_handle);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail1:
6a67d144095c31bbafed93cec1619590157335eajvergara vboxUninit();
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarafail0:
6a67d144095c31bbafed93cec1619590157335eajvergara unregister_filesystem(&vboxsf_fs_type);
6a67d144095c31bbafed93cec1619590157335eajvergara return rcRet;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void __exit fini(void)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara TRACE();
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara vboxDisconnect(&client_handle);
6a67d144095c31bbafed93cec1619590157335eajvergara vboxUninit();
6a67d144095c31bbafed93cec1619590157335eajvergara unregister_filesystem(&vboxsf_fs_type);
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergaramodule_init(init);
6a67d144095c31bbafed93cec1619590157335eajvergaramodule_exit(fini);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/* C++ hack */
6a67d144095c31bbafed93cec1619590157335eajvergaraint __gxx_personality_v0 = 0xdeadbeef;
6a67d144095c31bbafed93cec1619590157335eajvergara