xref: /kernel/linux/linux-5.10/fs/vboxsf/super.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * VirtualBox Guest Shared Folders support: Virtual File System.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Module initialization/finalization
68c2ecf20Sopenharmony_ci * File system registration/deregistration
78c2ecf20Sopenharmony_ci * Superblock reading
88c2ecf20Sopenharmony_ci * Few utility functions
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2006-2018 Oracle Corporation
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/idr.h>
148c2ecf20Sopenharmony_ci#include <linux/fs_parser.h>
158c2ecf20Sopenharmony_ci#include <linux/magic.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/nls.h>
188c2ecf20Sopenharmony_ci#include <linux/statfs.h>
198c2ecf20Sopenharmony_ci#include <linux/vbox_utils.h>
208c2ecf20Sopenharmony_ci#include "vfsmod.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic const unsigned char VBSF_MOUNT_SIGNATURE[4] = "\000\377\376\375";
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int follow_symlinks;
278c2ecf20Sopenharmony_cimodule_param(follow_symlinks, int, 0444);
288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(follow_symlinks,
298c2ecf20Sopenharmony_ci		 "Let host resolve symlinks rather than showing them");
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic DEFINE_IDA(vboxsf_bdi_ida);
328c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(vboxsf_setup_mutex);
338c2ecf20Sopenharmony_cistatic bool vboxsf_setup_done;
348c2ecf20Sopenharmony_cistatic struct super_operations vboxsf_super_ops; /* forward declaration */
358c2ecf20Sopenharmony_cistatic struct kmem_cache *vboxsf_inode_cachep;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic char * const vboxsf_default_nls = CONFIG_NLS_DEFAULT;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cienum  { opt_nls, opt_uid, opt_gid, opt_ttl, opt_dmode, opt_fmode,
408c2ecf20Sopenharmony_ci	opt_dmask, opt_fmask };
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec vboxsf_fs_parameters[] = {
438c2ecf20Sopenharmony_ci	fsparam_string	("nls",		opt_nls),
448c2ecf20Sopenharmony_ci	fsparam_u32	("uid",		opt_uid),
458c2ecf20Sopenharmony_ci	fsparam_u32	("gid",		opt_gid),
468c2ecf20Sopenharmony_ci	fsparam_u32	("ttl",		opt_ttl),
478c2ecf20Sopenharmony_ci	fsparam_u32oct	("dmode",	opt_dmode),
488c2ecf20Sopenharmony_ci	fsparam_u32oct	("fmode",	opt_fmode),
498c2ecf20Sopenharmony_ci	fsparam_u32oct	("dmask",	opt_dmask),
508c2ecf20Sopenharmony_ci	fsparam_u32oct	("fmask",	opt_fmask),
518c2ecf20Sopenharmony_ci	{}
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct vboxsf_fs_context *ctx = fc->fs_private;
578c2ecf20Sopenharmony_ci	struct fs_parse_result result;
588c2ecf20Sopenharmony_ci	kuid_t uid;
598c2ecf20Sopenharmony_ci	kgid_t gid;
608c2ecf20Sopenharmony_ci	int opt;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	opt = fs_parse(fc, vboxsf_fs_parameters, param, &result);
638c2ecf20Sopenharmony_ci	if (opt < 0)
648c2ecf20Sopenharmony_ci		return opt;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	switch (opt) {
678c2ecf20Sopenharmony_ci	case opt_nls:
688c2ecf20Sopenharmony_ci		if (ctx->nls_name || fc->purpose != FS_CONTEXT_FOR_MOUNT) {
698c2ecf20Sopenharmony_ci			vbg_err("vboxsf: Cannot reconfigure nls option\n");
708c2ecf20Sopenharmony_ci			return -EINVAL;
718c2ecf20Sopenharmony_ci		}
728c2ecf20Sopenharmony_ci		ctx->nls_name = param->string;
738c2ecf20Sopenharmony_ci		param->string = NULL;
748c2ecf20Sopenharmony_ci		break;
758c2ecf20Sopenharmony_ci	case opt_uid:
768c2ecf20Sopenharmony_ci		uid = make_kuid(current_user_ns(), result.uint_32);
778c2ecf20Sopenharmony_ci		if (!uid_valid(uid))
788c2ecf20Sopenharmony_ci			return -EINVAL;
798c2ecf20Sopenharmony_ci		ctx->o.uid = uid;
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci	case opt_gid:
828c2ecf20Sopenharmony_ci		gid = make_kgid(current_user_ns(), result.uint_32);
838c2ecf20Sopenharmony_ci		if (!gid_valid(gid))
848c2ecf20Sopenharmony_ci			return -EINVAL;
858c2ecf20Sopenharmony_ci		ctx->o.gid = gid;
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci	case opt_ttl:
888c2ecf20Sopenharmony_ci		ctx->o.ttl = msecs_to_jiffies(result.uint_32);
898c2ecf20Sopenharmony_ci		break;
908c2ecf20Sopenharmony_ci	case opt_dmode:
918c2ecf20Sopenharmony_ci		if (result.uint_32 & ~0777)
928c2ecf20Sopenharmony_ci			return -EINVAL;
938c2ecf20Sopenharmony_ci		ctx->o.dmode = result.uint_32;
948c2ecf20Sopenharmony_ci		ctx->o.dmode_set = true;
958c2ecf20Sopenharmony_ci		break;
968c2ecf20Sopenharmony_ci	case opt_fmode:
978c2ecf20Sopenharmony_ci		if (result.uint_32 & ~0777)
988c2ecf20Sopenharmony_ci			return -EINVAL;
998c2ecf20Sopenharmony_ci		ctx->o.fmode = result.uint_32;
1008c2ecf20Sopenharmony_ci		ctx->o.fmode_set = true;
1018c2ecf20Sopenharmony_ci		break;
1028c2ecf20Sopenharmony_ci	case opt_dmask:
1038c2ecf20Sopenharmony_ci		if (result.uint_32 & ~07777)
1048c2ecf20Sopenharmony_ci			return -EINVAL;
1058c2ecf20Sopenharmony_ci		ctx->o.dmask = result.uint_32;
1068c2ecf20Sopenharmony_ci		break;
1078c2ecf20Sopenharmony_ci	case opt_fmask:
1088c2ecf20Sopenharmony_ci		if (result.uint_32 & ~07777)
1098c2ecf20Sopenharmony_ci			return -EINVAL;
1108c2ecf20Sopenharmony_ci		ctx->o.fmask = result.uint_32;
1118c2ecf20Sopenharmony_ci		break;
1128c2ecf20Sopenharmony_ci	default:
1138c2ecf20Sopenharmony_ci		return -EINVAL;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct vboxsf_fs_context *ctx = fc->fs_private;
1228c2ecf20Sopenharmony_ci	struct shfl_string *folder_name, root_path;
1238c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi;
1248c2ecf20Sopenharmony_ci	struct dentry *droot;
1258c2ecf20Sopenharmony_ci	struct inode *iroot;
1268c2ecf20Sopenharmony_ci	char *nls_name;
1278c2ecf20Sopenharmony_ci	size_t size;
1288c2ecf20Sopenharmony_ci	int err;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!fc->source)
1318c2ecf20Sopenharmony_ci		return -EINVAL;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
1348c2ecf20Sopenharmony_ci	if (!sbi)
1358c2ecf20Sopenharmony_ci		return -ENOMEM;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	sbi->o = ctx->o;
1388c2ecf20Sopenharmony_ci	idr_init(&sbi->ino_idr);
1398c2ecf20Sopenharmony_ci	spin_lock_init(&sbi->ino_idr_lock);
1408c2ecf20Sopenharmony_ci	sbi->next_generation = 1;
1418c2ecf20Sopenharmony_ci	sbi->bdi_id = -1;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* Load nls if not utf8 */
1448c2ecf20Sopenharmony_ci	nls_name = ctx->nls_name ? ctx->nls_name : vboxsf_default_nls;
1458c2ecf20Sopenharmony_ci	if (strcmp(nls_name, "utf8") != 0) {
1468c2ecf20Sopenharmony_ci		if (nls_name == vboxsf_default_nls)
1478c2ecf20Sopenharmony_ci			sbi->nls = load_nls_default();
1488c2ecf20Sopenharmony_ci		else
1498c2ecf20Sopenharmony_ci			sbi->nls = load_nls(nls_name);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		if (!sbi->nls) {
1528c2ecf20Sopenharmony_ci			vbg_err("vboxsf: Count not load '%s' nls\n", nls_name);
1538c2ecf20Sopenharmony_ci			err = -EINVAL;
1548c2ecf20Sopenharmony_ci			goto fail_free;
1558c2ecf20Sopenharmony_ci		}
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	sbi->bdi_id = ida_simple_get(&vboxsf_bdi_ida, 0, 0, GFP_KERNEL);
1598c2ecf20Sopenharmony_ci	if (sbi->bdi_id < 0) {
1608c2ecf20Sopenharmony_ci		err = sbi->bdi_id;
1618c2ecf20Sopenharmony_ci		goto fail_free;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	err = super_setup_bdi_name(sb, "vboxsf-%d", sbi->bdi_id);
1658c2ecf20Sopenharmony_ci	if (err)
1668c2ecf20Sopenharmony_ci		goto fail_free;
1678c2ecf20Sopenharmony_ci	sb->s_bdi->ra_pages = 0;
1688c2ecf20Sopenharmony_ci	sb->s_bdi->io_pages = 0;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	/* Turn source into a shfl_string and map the folder */
1718c2ecf20Sopenharmony_ci	size = strlen(fc->source) + 1;
1728c2ecf20Sopenharmony_ci	folder_name = kmalloc(SHFLSTRING_HEADER_SIZE + size, GFP_KERNEL);
1738c2ecf20Sopenharmony_ci	if (!folder_name) {
1748c2ecf20Sopenharmony_ci		err = -ENOMEM;
1758c2ecf20Sopenharmony_ci		goto fail_free;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci	folder_name->size = size;
1788c2ecf20Sopenharmony_ci	folder_name->length = size - 1;
1798c2ecf20Sopenharmony_ci	strlcpy(folder_name->string.utf8, fc->source, size);
1808c2ecf20Sopenharmony_ci	err = vboxsf_map_folder(folder_name, &sbi->root);
1818c2ecf20Sopenharmony_ci	kfree(folder_name);
1828c2ecf20Sopenharmony_ci	if (err) {
1838c2ecf20Sopenharmony_ci		vbg_err("vboxsf: Host rejected mount of '%s' with error %d\n",
1848c2ecf20Sopenharmony_ci			fc->source, err);
1858c2ecf20Sopenharmony_ci		goto fail_free;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	root_path.length = 1;
1898c2ecf20Sopenharmony_ci	root_path.size = 2;
1908c2ecf20Sopenharmony_ci	root_path.string.utf8[0] = '/';
1918c2ecf20Sopenharmony_ci	root_path.string.utf8[1] = 0;
1928c2ecf20Sopenharmony_ci	err = vboxsf_stat(sbi, &root_path, &sbi->root_info);
1938c2ecf20Sopenharmony_ci	if (err)
1948c2ecf20Sopenharmony_ci		goto fail_unmap;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	sb->s_magic = VBOXSF_SUPER_MAGIC;
1978c2ecf20Sopenharmony_ci	sb->s_blocksize = 1024;
1988c2ecf20Sopenharmony_ci	sb->s_maxbytes = MAX_LFS_FILESIZE;
1998c2ecf20Sopenharmony_ci	sb->s_op = &vboxsf_super_ops;
2008c2ecf20Sopenharmony_ci	sb->s_d_op = &vboxsf_dentry_ops;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	iroot = iget_locked(sb, 0);
2038c2ecf20Sopenharmony_ci	if (!iroot) {
2048c2ecf20Sopenharmony_ci		err = -ENOMEM;
2058c2ecf20Sopenharmony_ci		goto fail_unmap;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci	vboxsf_init_inode(sbi, iroot, &sbi->root_info);
2088c2ecf20Sopenharmony_ci	unlock_new_inode(iroot);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	droot = d_make_root(iroot);
2118c2ecf20Sopenharmony_ci	if (!droot) {
2128c2ecf20Sopenharmony_ci		err = -ENOMEM;
2138c2ecf20Sopenharmony_ci		goto fail_unmap;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	sb->s_root = droot;
2178c2ecf20Sopenharmony_ci	sb->s_fs_info = sbi;
2188c2ecf20Sopenharmony_ci	return 0;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cifail_unmap:
2218c2ecf20Sopenharmony_ci	vboxsf_unmap_folder(sbi->root);
2228c2ecf20Sopenharmony_cifail_free:
2238c2ecf20Sopenharmony_ci	if (sbi->bdi_id >= 0)
2248c2ecf20Sopenharmony_ci		ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id);
2258c2ecf20Sopenharmony_ci	if (sbi->nls)
2268c2ecf20Sopenharmony_ci		unload_nls(sbi->nls);
2278c2ecf20Sopenharmony_ci	idr_destroy(&sbi->ino_idr);
2288c2ecf20Sopenharmony_ci	kfree(sbi);
2298c2ecf20Sopenharmony_ci	return err;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void vboxsf_inode_init_once(void *data)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct vboxsf_inode *sf_i = data;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	mutex_init(&sf_i->handle_list_mutex);
2378c2ecf20Sopenharmony_ci	inode_init_once(&sf_i->vfs_inode);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic struct inode *vboxsf_alloc_inode(struct super_block *sb)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct vboxsf_inode *sf_i;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	sf_i = kmem_cache_alloc(vboxsf_inode_cachep, GFP_NOFS);
2458c2ecf20Sopenharmony_ci	if (!sf_i)
2468c2ecf20Sopenharmony_ci		return NULL;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	sf_i->force_restat = 0;
2498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sf_i->handle_list);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return &sf_i->vfs_inode;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void vboxsf_free_inode(struct inode *inode)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
2578c2ecf20Sopenharmony_ci	unsigned long flags;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sbi->ino_idr_lock, flags);
2608c2ecf20Sopenharmony_ci	idr_remove(&sbi->ino_idr, inode->i_ino);
2618c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sbi->ino_idr_lock, flags);
2628c2ecf20Sopenharmony_ci	kmem_cache_free(vboxsf_inode_cachep, VBOXSF_I(inode));
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic void vboxsf_put_super(struct super_block *sb)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi = VBOXSF_SBI(sb);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	vboxsf_unmap_folder(sbi->root);
2708c2ecf20Sopenharmony_ci	if (sbi->bdi_id >= 0)
2718c2ecf20Sopenharmony_ci		ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id);
2728c2ecf20Sopenharmony_ci	if (sbi->nls)
2738c2ecf20Sopenharmony_ci		unload_nls(sbi->nls);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * vboxsf_free_inode uses the idr, make sure all delayed rcu free
2778c2ecf20Sopenharmony_ci	 * inodes are flushed.
2788c2ecf20Sopenharmony_ci	 */
2798c2ecf20Sopenharmony_ci	rcu_barrier();
2808c2ecf20Sopenharmony_ci	idr_destroy(&sbi->ino_idr);
2818c2ecf20Sopenharmony_ci	kfree(sbi);
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int vboxsf_statfs(struct dentry *dentry, struct kstatfs *stat)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct super_block *sb = dentry->d_sb;
2878c2ecf20Sopenharmony_ci	struct shfl_volinfo shfl_volinfo;
2888c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi;
2898c2ecf20Sopenharmony_ci	u32 buf_len;
2908c2ecf20Sopenharmony_ci	int err;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	sbi = VBOXSF_SBI(sb);
2938c2ecf20Sopenharmony_ci	buf_len = sizeof(shfl_volinfo);
2948c2ecf20Sopenharmony_ci	err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
2958c2ecf20Sopenharmony_ci			    &buf_len, &shfl_volinfo);
2968c2ecf20Sopenharmony_ci	if (err)
2978c2ecf20Sopenharmony_ci		return err;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	stat->f_type = VBOXSF_SUPER_MAGIC;
3008c2ecf20Sopenharmony_ci	stat->f_bsize = shfl_volinfo.bytes_per_allocation_unit;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	do_div(shfl_volinfo.total_allocation_bytes,
3038c2ecf20Sopenharmony_ci	       shfl_volinfo.bytes_per_allocation_unit);
3048c2ecf20Sopenharmony_ci	stat->f_blocks = shfl_volinfo.total_allocation_bytes;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	do_div(shfl_volinfo.available_allocation_bytes,
3078c2ecf20Sopenharmony_ci	       shfl_volinfo.bytes_per_allocation_unit);
3088c2ecf20Sopenharmony_ci	stat->f_bfree  = shfl_volinfo.available_allocation_bytes;
3098c2ecf20Sopenharmony_ci	stat->f_bavail = shfl_volinfo.available_allocation_bytes;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	stat->f_files = 1000;
3128c2ecf20Sopenharmony_ci	/*
3138c2ecf20Sopenharmony_ci	 * Don't return 0 here since the guest may then think that it is not
3148c2ecf20Sopenharmony_ci	 * possible to create any more files.
3158c2ecf20Sopenharmony_ci	 */
3168c2ecf20Sopenharmony_ci	stat->f_ffree = 1000000;
3178c2ecf20Sopenharmony_ci	stat->f_fsid.val[0] = 0;
3188c2ecf20Sopenharmony_ci	stat->f_fsid.val[1] = 0;
3198c2ecf20Sopenharmony_ci	stat->f_namelen = 255;
3208c2ecf20Sopenharmony_ci	return 0;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic struct super_operations vboxsf_super_ops = {
3248c2ecf20Sopenharmony_ci	.alloc_inode	= vboxsf_alloc_inode,
3258c2ecf20Sopenharmony_ci	.free_inode	= vboxsf_free_inode,
3268c2ecf20Sopenharmony_ci	.put_super	= vboxsf_put_super,
3278c2ecf20Sopenharmony_ci	.statfs		= vboxsf_statfs,
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int vboxsf_setup(void)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	int err;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	mutex_lock(&vboxsf_setup_mutex);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (vboxsf_setup_done)
3378c2ecf20Sopenharmony_ci		goto success;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	vboxsf_inode_cachep =
3408c2ecf20Sopenharmony_ci		kmem_cache_create("vboxsf_inode_cache",
3418c2ecf20Sopenharmony_ci				  sizeof(struct vboxsf_inode), 0,
3428c2ecf20Sopenharmony_ci				  (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
3438c2ecf20Sopenharmony_ci				   SLAB_ACCOUNT),
3448c2ecf20Sopenharmony_ci				  vboxsf_inode_init_once);
3458c2ecf20Sopenharmony_ci	if (!vboxsf_inode_cachep) {
3468c2ecf20Sopenharmony_ci		err = -ENOMEM;
3478c2ecf20Sopenharmony_ci		goto fail_nomem;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	err = vboxsf_connect();
3518c2ecf20Sopenharmony_ci	if (err) {
3528c2ecf20Sopenharmony_ci		vbg_err("vboxsf: err %d connecting to guest PCI-device\n", err);
3538c2ecf20Sopenharmony_ci		vbg_err("vboxsf: make sure you are inside a VirtualBox VM\n");
3548c2ecf20Sopenharmony_ci		vbg_err("vboxsf: and check dmesg for vboxguest errors\n");
3558c2ecf20Sopenharmony_ci		goto fail_free_cache;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	err = vboxsf_set_utf8();
3598c2ecf20Sopenharmony_ci	if (err) {
3608c2ecf20Sopenharmony_ci		vbg_err("vboxsf_setutf8 error %d\n", err);
3618c2ecf20Sopenharmony_ci		goto fail_disconnect;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (!follow_symlinks) {
3658c2ecf20Sopenharmony_ci		err = vboxsf_set_symlinks();
3668c2ecf20Sopenharmony_ci		if (err)
3678c2ecf20Sopenharmony_ci			vbg_warn("vboxsf: Unable to show symlinks: %d\n", err);
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	vboxsf_setup_done = true;
3718c2ecf20Sopenharmony_cisuccess:
3728c2ecf20Sopenharmony_ci	mutex_unlock(&vboxsf_setup_mutex);
3738c2ecf20Sopenharmony_ci	return 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cifail_disconnect:
3768c2ecf20Sopenharmony_ci	vboxsf_disconnect();
3778c2ecf20Sopenharmony_cifail_free_cache:
3788c2ecf20Sopenharmony_ci	kmem_cache_destroy(vboxsf_inode_cachep);
3798c2ecf20Sopenharmony_cifail_nomem:
3808c2ecf20Sopenharmony_ci	mutex_unlock(&vboxsf_setup_mutex);
3818c2ecf20Sopenharmony_ci	return err;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int vboxsf_parse_monolithic(struct fs_context *fc, void *data)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	if (data && !memcmp(data, VBSF_MOUNT_SIGNATURE, 4)) {
3878c2ecf20Sopenharmony_ci		vbg_err("vboxsf: Old binary mount data not supported, remove obsolete mount.vboxsf and/or update your VBoxService.\n");
3888c2ecf20Sopenharmony_ci		return -EINVAL;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return generic_parse_monolithic(fc, data);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int vboxsf_get_tree(struct fs_context *fc)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int err;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	err = vboxsf_setup();
3998c2ecf20Sopenharmony_ci	if (err)
4008c2ecf20Sopenharmony_ci		return err;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return get_tree_nodev(fc, vboxsf_fill_super);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int vboxsf_reconfigure(struct fs_context *fc)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi = VBOXSF_SBI(fc->root->d_sb);
4088c2ecf20Sopenharmony_ci	struct vboxsf_fs_context *ctx = fc->fs_private;
4098c2ecf20Sopenharmony_ci	struct inode *iroot = fc->root->d_sb->s_root->d_inode;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* Apply changed options to the root inode */
4128c2ecf20Sopenharmony_ci	sbi->o = ctx->o;
4138c2ecf20Sopenharmony_ci	vboxsf_init_inode(sbi, iroot, &sbi->root_info);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void vboxsf_free_fc(struct fs_context *fc)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct vboxsf_fs_context *ctx = fc->fs_private;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	kfree(ctx->nls_name);
4238c2ecf20Sopenharmony_ci	kfree(ctx);
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic const struct fs_context_operations vboxsf_context_ops = {
4278c2ecf20Sopenharmony_ci	.free			= vboxsf_free_fc,
4288c2ecf20Sopenharmony_ci	.parse_param		= vboxsf_parse_param,
4298c2ecf20Sopenharmony_ci	.parse_monolithic	= vboxsf_parse_monolithic,
4308c2ecf20Sopenharmony_ci	.get_tree		= vboxsf_get_tree,
4318c2ecf20Sopenharmony_ci	.reconfigure		= vboxsf_reconfigure,
4328c2ecf20Sopenharmony_ci};
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic int vboxsf_init_fs_context(struct fs_context *fc)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct vboxsf_fs_context *ctx;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
4398c2ecf20Sopenharmony_ci	if (!ctx)
4408c2ecf20Sopenharmony_ci		return -ENOMEM;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	current_uid_gid(&ctx->o.uid, &ctx->o.gid);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	fc->fs_private = ctx;
4458c2ecf20Sopenharmony_ci	fc->ops = &vboxsf_context_ops;
4468c2ecf20Sopenharmony_ci	return 0;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic struct file_system_type vboxsf_fs_type = {
4508c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
4518c2ecf20Sopenharmony_ci	.name			= "vboxsf",
4528c2ecf20Sopenharmony_ci	.init_fs_context	= vboxsf_init_fs_context,
4538c2ecf20Sopenharmony_ci	.kill_sb		= kill_anon_super
4548c2ecf20Sopenharmony_ci};
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci/* Module initialization/finalization handlers */
4578c2ecf20Sopenharmony_cistatic int __init vboxsf_init(void)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	return register_filesystem(&vboxsf_fs_type);
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic void __exit vboxsf_fini(void)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	unregister_filesystem(&vboxsf_fs_type);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	mutex_lock(&vboxsf_setup_mutex);
4678c2ecf20Sopenharmony_ci	if (vboxsf_setup_done) {
4688c2ecf20Sopenharmony_ci		vboxsf_disconnect();
4698c2ecf20Sopenharmony_ci		/*
4708c2ecf20Sopenharmony_ci		 * Make sure all delayed rcu free inodes are flushed
4718c2ecf20Sopenharmony_ci		 * before we destroy the cache.
4728c2ecf20Sopenharmony_ci		 */
4738c2ecf20Sopenharmony_ci		rcu_barrier();
4748c2ecf20Sopenharmony_ci		kmem_cache_destroy(vboxsf_inode_cachep);
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci	mutex_unlock(&vboxsf_setup_mutex);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cimodule_init(vboxsf_init);
4808c2ecf20Sopenharmony_cimodule_exit(vboxsf_fini);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access");
4838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Oracle Corporation");
4848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
4858c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("vboxsf");
486