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