brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · e95b8a4 Raw
478 lines · c
1// SPDX-License-Identifier: MIT2/*3 * VirtualBox Guest Shared Folders support: Virtual File System.4 *5 * Module initialization/finalization6 * File system registration/deregistration7 * Superblock reading8 * Few utility functions9 *10 * Copyright (C) 2006-2018 Oracle Corporation11 */12 13#include <linux/idr.h>14#include <linux/fs_parser.h>15#include <linux/magic.h>16#include <linux/module.h>17#include <linux/nls.h>18#include <linux/statfs.h>19#include <linux/vbox_utils.h>20#include "vfsmod.h"21 22#define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */23 24static const unsigned char VBSF_MOUNT_SIGNATURE[4] = "\000\377\376\375";25 26static int follow_symlinks;27module_param(follow_symlinks, int, 0444);28MODULE_PARM_DESC(follow_symlinks,29		 "Let host resolve symlinks rather than showing them");30 31static DEFINE_IDA(vboxsf_bdi_ida);32static DEFINE_MUTEX(vboxsf_setup_mutex);33static bool vboxsf_setup_done;34static struct super_operations vboxsf_super_ops; /* forward declaration */35static struct kmem_cache *vboxsf_inode_cachep;36 37static char * const vboxsf_default_nls = CONFIG_NLS_DEFAULT;38 39enum  { opt_nls, opt_uid, opt_gid, opt_ttl, opt_dmode, opt_fmode,40	opt_dmask, opt_fmask };41 42static const struct fs_parameter_spec vboxsf_fs_parameters[] = {43	fsparam_string	("nls",		opt_nls),44	fsparam_uid	("uid",		opt_uid),45	fsparam_gid	("gid",		opt_gid),46	fsparam_u32	("ttl",		opt_ttl),47	fsparam_u32oct	("dmode",	opt_dmode),48	fsparam_u32oct	("fmode",	opt_fmode),49	fsparam_u32oct	("dmask",	opt_dmask),50	fsparam_u32oct	("fmask",	opt_fmask),51	{}52};53 54static int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param)55{56	struct vboxsf_fs_context *ctx = fc->fs_private;57	struct fs_parse_result result;58	int opt;59 60	opt = fs_parse(fc, vboxsf_fs_parameters, param, &result);61	if (opt < 0)62		return opt;63 64	switch (opt) {65	case opt_nls:66		if (ctx->nls_name || fc->purpose != FS_CONTEXT_FOR_MOUNT) {67			vbg_err("vboxsf: Cannot reconfigure nls option\n");68			return -EINVAL;69		}70		ctx->nls_name = param->string;71		param->string = NULL;72		break;73	case opt_uid:74		ctx->o.uid = result.uid;75		break;76	case opt_gid:77		ctx->o.gid = result.gid;78		break;79	case opt_ttl:80		ctx->o.ttl = msecs_to_jiffies(result.uint_32);81		break;82	case opt_dmode:83		if (result.uint_32 & ~0777)84			return -EINVAL;85		ctx->o.dmode = result.uint_32;86		ctx->o.dmode_set = true;87		break;88	case opt_fmode:89		if (result.uint_32 & ~0777)90			return -EINVAL;91		ctx->o.fmode = result.uint_32;92		ctx->o.fmode_set = true;93		break;94	case opt_dmask:95		if (result.uint_32 & ~07777)96			return -EINVAL;97		ctx->o.dmask = result.uint_32;98		break;99	case opt_fmask:100		if (result.uint_32 & ~07777)101			return -EINVAL;102		ctx->o.fmask = result.uint_32;103		break;104	default:105		return -EINVAL;106	}107 108	return 0;109}110 111static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)112{113	struct vboxsf_fs_context *ctx = fc->fs_private;114	struct shfl_string *folder_name, root_path;115	struct vboxsf_sbi *sbi;116	struct dentry *droot;117	struct inode *iroot;118	char *nls_name;119	size_t size;120	int err;121 122	if (!fc->source)123		return -EINVAL;124 125	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);126	if (!sbi)127		return -ENOMEM;128 129	sbi->o = ctx->o;130	idr_init(&sbi->ino_idr);131	spin_lock_init(&sbi->ino_idr_lock);132	sbi->next_generation = 1;133	sbi->bdi_id = -1;134 135	/* Load nls if not utf8 */136	nls_name = ctx->nls_name ? ctx->nls_name : vboxsf_default_nls;137	if (strcmp(nls_name, "utf8") != 0) {138		if (nls_name == vboxsf_default_nls)139			sbi->nls = load_nls_default();140		else141			sbi->nls = load_nls(nls_name);142 143		if (!sbi->nls) {144			vbg_err("vboxsf: Count not load '%s' nls\n", nls_name);145			err = -EINVAL;146			goto fail_destroy_idr;147		}148	}149 150	sbi->bdi_id = ida_alloc(&vboxsf_bdi_ida, GFP_KERNEL);151	if (sbi->bdi_id < 0) {152		err = sbi->bdi_id;153		goto fail_free;154	}155 156	err = super_setup_bdi_name(sb, "vboxsf-%d", sbi->bdi_id);157	if (err)158		goto fail_free;159	sb->s_bdi->ra_pages = 0;160	sb->s_bdi->io_pages = 0;161 162	/* Turn source into a shfl_string and map the folder */163	size = strlen(fc->source) + 1;164	folder_name = kmalloc(SHFLSTRING_HEADER_SIZE + size, GFP_KERNEL);165	if (!folder_name) {166		err = -ENOMEM;167		goto fail_free;168	}169	folder_name->size = size;170	folder_name->length = size - 1;171	strscpy(folder_name->string.utf8, fc->source, size);172	err = vboxsf_map_folder(folder_name, &sbi->root);173	kfree(folder_name);174	if (err) {175		vbg_err("vboxsf: Host rejected mount of '%s' with error %d\n",176			fc->source, err);177		goto fail_free;178	}179 180	root_path.length = 1;181	root_path.size = 2;182	root_path.string.utf8[0] = '/';183	root_path.string.utf8[1] = 0;184	err = vboxsf_stat(sbi, &root_path, &sbi->root_info);185	if (err)186		goto fail_unmap;187 188	sb->s_magic = VBOXSF_SUPER_MAGIC;189	sb->s_blocksize = 1024;190	sb->s_maxbytes = MAX_LFS_FILESIZE;191	sb->s_op = &vboxsf_super_ops;192	sb->s_d_op = &vboxsf_dentry_ops;193 194	iroot = iget_locked(sb, 0);195	if (!iroot) {196		err = -ENOMEM;197		goto fail_unmap;198	}199	vboxsf_init_inode(sbi, iroot, &sbi->root_info, false);200	unlock_new_inode(iroot);201 202	droot = d_make_root(iroot);203	if (!droot) {204		err = -ENOMEM;205		goto fail_unmap;206	}207 208	sb->s_root = droot;209	sb->s_fs_info = sbi;210	return 0;211 212fail_unmap:213	vboxsf_unmap_folder(sbi->root);214fail_free:215	if (sbi->bdi_id >= 0)216		ida_free(&vboxsf_bdi_ida, sbi->bdi_id);217	if (sbi->nls)218		unload_nls(sbi->nls);219fail_destroy_idr:220	idr_destroy(&sbi->ino_idr);221	kfree(sbi);222	return err;223}224 225static void vboxsf_inode_init_once(void *data)226{227	struct vboxsf_inode *sf_i = data;228 229	mutex_init(&sf_i->handle_list_mutex);230	inode_init_once(&sf_i->vfs_inode);231}232 233static struct inode *vboxsf_alloc_inode(struct super_block *sb)234{235	struct vboxsf_inode *sf_i;236 237	sf_i = alloc_inode_sb(sb, vboxsf_inode_cachep, GFP_NOFS);238	if (!sf_i)239		return NULL;240 241	sf_i->force_restat = 0;242	INIT_LIST_HEAD(&sf_i->handle_list);243 244	return &sf_i->vfs_inode;245}246 247static void vboxsf_free_inode(struct inode *inode)248{249	struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);250	unsigned long flags;251 252	spin_lock_irqsave(&sbi->ino_idr_lock, flags);253	idr_remove(&sbi->ino_idr, inode->i_ino);254	spin_unlock_irqrestore(&sbi->ino_idr_lock, flags);255	kmem_cache_free(vboxsf_inode_cachep, VBOXSF_I(inode));256}257 258static void vboxsf_put_super(struct super_block *sb)259{260	struct vboxsf_sbi *sbi = VBOXSF_SBI(sb);261 262	vboxsf_unmap_folder(sbi->root);263	if (sbi->bdi_id >= 0)264		ida_free(&vboxsf_bdi_ida, sbi->bdi_id);265	if (sbi->nls)266		unload_nls(sbi->nls);267 268	/*269	 * vboxsf_free_inode uses the idr, make sure all delayed rcu free270	 * inodes are flushed.271	 */272	rcu_barrier();273	idr_destroy(&sbi->ino_idr);274	kfree(sbi);275}276 277static int vboxsf_statfs(struct dentry *dentry, struct kstatfs *stat)278{279	struct super_block *sb = dentry->d_sb;280	struct shfl_volinfo shfl_volinfo;281	struct vboxsf_sbi *sbi;282	u32 buf_len;283	int err;284 285	sbi = VBOXSF_SBI(sb);286	buf_len = sizeof(shfl_volinfo);287	err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,288			    &buf_len, &shfl_volinfo);289	if (err)290		return err;291 292	stat->f_type = VBOXSF_SUPER_MAGIC;293	stat->f_bsize = shfl_volinfo.bytes_per_allocation_unit;294 295	do_div(shfl_volinfo.total_allocation_bytes,296	       shfl_volinfo.bytes_per_allocation_unit);297	stat->f_blocks = shfl_volinfo.total_allocation_bytes;298 299	do_div(shfl_volinfo.available_allocation_bytes,300	       shfl_volinfo.bytes_per_allocation_unit);301	stat->f_bfree  = shfl_volinfo.available_allocation_bytes;302	stat->f_bavail = shfl_volinfo.available_allocation_bytes;303 304	stat->f_files = 1000;305	/*306	 * Don't return 0 here since the guest may then think that it is not307	 * possible to create any more files.308	 */309	stat->f_ffree = 1000000;310	stat->f_fsid.val[0] = 0;311	stat->f_fsid.val[1] = 0;312	stat->f_namelen = 255;313	return 0;314}315 316static struct super_operations vboxsf_super_ops = {317	.alloc_inode	= vboxsf_alloc_inode,318	.free_inode	= vboxsf_free_inode,319	.put_super	= vboxsf_put_super,320	.statfs		= vboxsf_statfs,321};322 323static int vboxsf_setup(void)324{325	int err;326 327	mutex_lock(&vboxsf_setup_mutex);328 329	if (vboxsf_setup_done)330		goto success;331 332	vboxsf_inode_cachep =333		kmem_cache_create("vboxsf_inode_cache",334				  sizeof(struct vboxsf_inode), 0,335				  SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,336				  vboxsf_inode_init_once);337	if (!vboxsf_inode_cachep) {338		err = -ENOMEM;339		goto fail_nomem;340	}341 342	err = vboxsf_connect();343	if (err) {344		vbg_err("vboxsf: err %d connecting to guest PCI-device\n", err);345		vbg_err("vboxsf: make sure you are inside a VirtualBox VM\n");346		vbg_err("vboxsf: and check dmesg for vboxguest errors\n");347		goto fail_free_cache;348	}349 350	err = vboxsf_set_utf8();351	if (err) {352		vbg_err("vboxsf_setutf8 error %d\n", err);353		goto fail_disconnect;354	}355 356	if (!follow_symlinks) {357		err = vboxsf_set_symlinks();358		if (err)359			vbg_warn("vboxsf: Unable to show symlinks: %d\n", err);360	}361 362	vboxsf_setup_done = true;363success:364	mutex_unlock(&vboxsf_setup_mutex);365	return 0;366 367fail_disconnect:368	vboxsf_disconnect();369fail_free_cache:370	kmem_cache_destroy(vboxsf_inode_cachep);371fail_nomem:372	mutex_unlock(&vboxsf_setup_mutex);373	return err;374}375 376static int vboxsf_parse_monolithic(struct fs_context *fc, void *data)377{378	if (data && !memcmp(data, VBSF_MOUNT_SIGNATURE, 4)) {379		vbg_err("vboxsf: Old binary mount data not supported, remove obsolete mount.vboxsf and/or update your VBoxService.\n");380		return -EINVAL;381	}382 383	return generic_parse_monolithic(fc, data);384}385 386static int vboxsf_get_tree(struct fs_context *fc)387{388	int err;389 390	err = vboxsf_setup();391	if (err)392		return err;393 394	return get_tree_nodev(fc, vboxsf_fill_super);395}396 397static int vboxsf_reconfigure(struct fs_context *fc)398{399	struct vboxsf_sbi *sbi = VBOXSF_SBI(fc->root->d_sb);400	struct vboxsf_fs_context *ctx = fc->fs_private;401	struct inode *iroot = fc->root->d_sb->s_root->d_inode;402 403	/* Apply changed options to the root inode */404	sbi->o = ctx->o;405	vboxsf_init_inode(sbi, iroot, &sbi->root_info, true);406 407	return 0;408}409 410static void vboxsf_free_fc(struct fs_context *fc)411{412	struct vboxsf_fs_context *ctx = fc->fs_private;413 414	kfree(ctx->nls_name);415	kfree(ctx);416}417 418static const struct fs_context_operations vboxsf_context_ops = {419	.free			= vboxsf_free_fc,420	.parse_param		= vboxsf_parse_param,421	.parse_monolithic	= vboxsf_parse_monolithic,422	.get_tree		= vboxsf_get_tree,423	.reconfigure		= vboxsf_reconfigure,424};425 426static int vboxsf_init_fs_context(struct fs_context *fc)427{428	struct vboxsf_fs_context *ctx;429 430	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);431	if (!ctx)432		return -ENOMEM;433 434	current_uid_gid(&ctx->o.uid, &ctx->o.gid);435 436	fc->fs_private = ctx;437	fc->ops = &vboxsf_context_ops;438	return 0;439}440 441static struct file_system_type vboxsf_fs_type = {442	.owner			= THIS_MODULE,443	.name			= "vboxsf",444	.init_fs_context	= vboxsf_init_fs_context,445	.kill_sb		= kill_anon_super446};447 448/* Module initialization/finalization handlers */449static int __init vboxsf_init(void)450{451	return register_filesystem(&vboxsf_fs_type);452}453 454static void __exit vboxsf_fini(void)455{456	unregister_filesystem(&vboxsf_fs_type);457 458	mutex_lock(&vboxsf_setup_mutex);459	if (vboxsf_setup_done) {460		vboxsf_disconnect();461		/*462		 * Make sure all delayed rcu free inodes are flushed463		 * before we destroy the cache.464		 */465		rcu_barrier();466		kmem_cache_destroy(vboxsf_inode_cachep);467	}468	mutex_unlock(&vboxsf_setup_mutex);469}470 471module_init(vboxsf_init);472module_exit(vboxsf_fini);473 474MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access");475MODULE_AUTHOR("Oracle Corporation");476MODULE_LICENSE("GPL v2");477MODULE_ALIAS_FS("vboxsf");478