VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c@ 76787

Last change on this file since 76787 was 76744, checked in by vboxsync, 6 years ago

vboxsf/linux: Indent #ifdefs and comment the according to our guidelines, no need to make this harder to untangle than it already is.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/* $Id: vfsmod.c 76744 2019-01-09 16:29:03Z vboxsync $ */
2/** @file
3 * vboxsf - VBox Linux Shared Folders VFS, module init/term, super block management.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/**
32 * @note Anyone wishing to make changes here might wish to take a look at
33 * https://github.com/torvalds/linux/blob/master/Documentation/filesystems/vfs.txt
34 * which seems to be the closest there is to official documentation on
35 * writing filesystem drivers for Linux.
36 */
37
38#include "vfsmod.h"
39#include "version-generated.h"
40#include "revision-generated.h"
41#include "product-generated.h"
42#include "VBoxGuestR0LibInternal.h"
43#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
44# include <linux/mount.h>
45#endif
46#include <linux/seq_file.h>
47
48MODULE_DESCRIPTION(VBOX_PRODUCT " VFS Module for Host File System Access");
49MODULE_AUTHOR(VBOX_VENDOR);
50MODULE_LICENSE("GPL and additional rights");
51#ifdef MODULE_ALIAS_FS
52MODULE_ALIAS_FS("vboxsf");
53#endif
54#ifdef MODULE_VERSION
55MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
56#endif
57
58/* globals */
59VBGLSFCLIENT client_handle;
60
61/* forward declarations */
62static struct super_operations sf_super_ops;
63
64/* allocate global info, try to map host share */
65static int sf_glob_alloc(struct vbsf_mount_info_new *info,
66 struct sf_glob_info **sf_gp)
67{
68 int err, rc;
69 SHFLSTRING *str_name;
70 size_t name_len, str_len;
71 struct sf_glob_info *sf_g;
72
73 TRACE();
74 sf_g = kmalloc(sizeof(*sf_g), GFP_KERNEL);
75 if (!sf_g) {
76 err = -ENOMEM;
77 LogRelFunc(("could not allocate memory for global info\n"));
78 goto fail0;
79 }
80
81 RT_ZERO(*sf_g);
82
83 if (info->nullchar != '\0'
84 || info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
85 || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
86 || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2) {
87 err = -EINVAL;
88 goto fail1;
89 }
90
91 info->name[sizeof(info->name) - 1] = 0;
92 info->nls_name[sizeof(info->nls_name) - 1] = 0;
93
94 name_len = strlen(info->name);
95 str_len = offsetof(SHFLSTRING, String.utf8) + name_len + 1;
96 str_name = kmalloc(str_len, GFP_KERNEL);
97 if (!str_name) {
98 err = -ENOMEM;
99 LogRelFunc(("could not allocate memory for host name\n"));
100 goto fail1;
101 }
102
103 str_name->u16Length = name_len;
104 str_name->u16Size = name_len + 1;
105 memcpy(str_name->String.utf8, info->name, name_len + 1);
106
107#define _IS_UTF8(_str) \
108 (strcmp(_str, "utf8") == 0)
109#define _IS_EMPTY(_str) \
110 (strcmp(_str, "") == 0)
111
112 /* Check if NLS charset is valid and not points to UTF8 table */
113 if (info->nls_name[0]) {
114 if (_IS_UTF8(info->nls_name))
115 sf_g->nls = NULL;
116 else {
117 sf_g->nls = load_nls(info->nls_name);
118 if (!sf_g->nls) {
119 err = -EINVAL;
120 LogFunc(("failed to load nls %s\n",
121 info->nls_name));
122 kfree(str_name);
123 goto fail1;
124 }
125 }
126 } else {
127#ifdef CONFIG_NLS_DEFAULT
128 /* If no NLS charset specified, try to load the default
129 * one if it's not points to UTF8. */
130 if (!_IS_UTF8(CONFIG_NLS_DEFAULT)
131 && !_IS_EMPTY(CONFIG_NLS_DEFAULT))
132 sf_g->nls = load_nls_default();
133 else
134 sf_g->nls = NULL;
135#else
136 sf_g->nls = NULL;
137#endif
138
139#undef _IS_UTF8
140#undef _IS_EMPTY
141 }
142
143 rc = VbglR0SfMapFolder(&client_handle, str_name, &sf_g->map);
144 kfree(str_name);
145
146 if (RT_FAILURE(rc)) {
147 err = -EPROTO;
148 LogFunc(("VbglR0SfMapFolder failed rc=%d\n", rc));
149 goto fail2;
150 }
151
152 sf_g->ttl = info->ttl;
153 sf_g->uid = info->uid;
154 sf_g->gid = info->gid;
155
156 if ((unsigned)info->length >= RT_UOFFSETOF(struct vbsf_mount_info_new, tag)) {
157 /* new fields */
158 sf_g->dmode = info->dmode;
159 sf_g->fmode = info->fmode;
160 sf_g->dmask = info->dmask;
161 sf_g->fmask = info->fmask;
162 } else {
163 sf_g->dmode = ~0;
164 sf_g->fmode = ~0;
165 }
166
167 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new)) {
168 AssertCompile(sizeof(sf_g->tag) >= sizeof(info->tag));
169 memcpy(sf_g->tag, info->tag, sizeof(info->tag));
170 sf_g->tag[sizeof(sf_g->tag) - 1] = '\0';
171 } else {
172 sf_g->tag[0] = '\0';
173 }
174
175 *sf_gp = sf_g;
176 return 0;
177
178 fail2:
179 if (sf_g->nls)
180 unload_nls(sf_g->nls);
181
182 fail1:
183 kfree(sf_g);
184
185 fail0:
186 return err;
187}
188
189/* unmap the share and free global info [sf_g] */
190static void sf_glob_free(struct sf_glob_info *sf_g)
191{
192 int rc;
193
194 TRACE();
195 rc = VbglR0SfUnmapFolder(&client_handle, &sf_g->map);
196 if (RT_FAILURE(rc))
197 LogFunc(("VbglR0SfUnmapFolder failed rc=%d\n", rc));
198
199 if (sf_g->nls)
200 unload_nls(sf_g->nls);
201
202 kfree(sf_g);
203}
204
205/**
206 * This is called (by sf_read_super_[24|26] when vfs mounts the fs and
207 * wants to read super_block.
208 *
209 * calls [sf_glob_alloc] to map the folder and allocate global
210 * information structure.
211 *
212 * initializes [sb], initializes root inode and dentry.
213 *
214 * should respect [flags]
215 */
216static int sf_read_super_aux(struct super_block *sb, void *data, int flags)
217{
218 int err;
219 struct dentry *droot;
220 struct inode *iroot;
221 struct sf_inode_info *sf_i;
222 struct sf_glob_info *sf_g;
223 SHFLFSOBJINFO fsinfo;
224 struct vbsf_mount_info_new *info;
225 bool fInodePut = true;
226
227 TRACE();
228 if (!data) {
229 LogFunc(("no mount info specified\n"));
230 return -EINVAL;
231 }
232
233 info = data;
234
235 if (flags & MS_REMOUNT) {
236 LogFunc(("remounting is not supported\n"));
237 return -ENOSYS;
238 }
239
240 err = sf_glob_alloc(info, &sf_g);
241 if (err)
242 goto fail0;
243
244 sf_i = kmalloc(sizeof(*sf_i), GFP_KERNEL);
245 if (!sf_i) {
246 err = -ENOMEM;
247 LogRelFunc(("could not allocate memory for root inode info\n"));
248 goto fail1;
249 }
250
251 sf_i->handle = SHFL_HANDLE_NIL;
252 sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL);
253 if (!sf_i->path) {
254 err = -ENOMEM;
255 LogRelFunc(("could not allocate memory for root inode path\n"));
256 goto fail2;
257 }
258
259 sf_i->path->u16Length = 1;
260 sf_i->path->u16Size = 2;
261 sf_i->path->String.utf8[0] = '/';
262 sf_i->path->String.utf8[1] = 0;
263 sf_i->force_reread = 0;
264
265 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
266 if (err) {
267 LogFunc(("could not stat root of share\n"));
268 goto fail3;
269 }
270
271 sb->s_magic = 0xface;
272 sb->s_blocksize = 1024;
273#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 3)
274 /* Required for seek/sendfile.
275 *
276 * Must by less than or equal to INT64_MAX despite the fact that the
277 * declaration of this variable is unsigned long long. See determination
278 * of 'loff_t max' in fs/read_write.c / do_sendfile(). I don't know the
279 * correct limit but MAX_LFS_FILESIZE (8TB-1 on 32-bit boxes) takes the
280 * page cache into account and is the suggested limit. */
281# if defined MAX_LFS_FILESIZE
282 sb->s_maxbytes = MAX_LFS_FILESIZE;
283# else
284 sb->s_maxbytes = 0x7fffffffffffffffULL;
285# endif
286#endif
287 sb->s_op = &sf_super_ops;
288
289#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
290 iroot = iget_locked(sb, 0);
291#else
292 iroot = iget(sb, 0);
293#endif
294 if (!iroot) {
295 err = -ENOMEM; /* XXX */
296 LogFunc(("could not get root inode\n"));
297 goto fail3;
298 }
299
300 if (sf_init_backing_dev(sf_g)) {
301 err = -EINVAL;
302 LogFunc(("could not init bdi\n"));
303#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
304 unlock_new_inode(iroot);
305#endif
306 goto fail4;
307 }
308
309 sf_init_inode(sf_g, iroot, &fsinfo);
310 SET_INODE_INFO(iroot, sf_i);
311
312#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
313 unlock_new_inode(iroot);
314#endif
315
316#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
317 droot = d_make_root(iroot);
318#else
319 droot = d_alloc_root(iroot);
320#endif
321 if (!droot) {
322 err = -ENOMEM; /* XXX */
323 LogFunc(("d_alloc_root failed\n"));
324#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
325 fInodePut = false;
326#endif
327 goto fail5;
328 }
329
330 sb->s_root = droot;
331 SET_GLOB_INFO(sb, sf_g);
332 return 0;
333
334 fail5:
335 sf_done_backing_dev(sf_g);
336
337 fail4:
338 if (fInodePut)
339 iput(iroot);
340
341 fail3:
342 kfree(sf_i->path);
343
344 fail2:
345 kfree(sf_i);
346
347 fail1:
348 sf_glob_free(sf_g);
349
350 fail0:
351 return err;
352}
353
354#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
355static struct super_block *sf_read_super_24(struct super_block *sb, void *data,
356 int flags)
357{
358 int err;
359
360 TRACE();
361 err = sf_read_super_aux(sb, data, flags);
362 if (err)
363 return NULL;
364
365 return sb;
366}
367#endif
368
369/* this is called when vfs is about to destroy the [inode]. all
370 resources associated with this [inode] must be cleared here */
371#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
372static void sf_clear_inode(struct inode *inode)
373{
374 struct sf_inode_info *sf_i;
375
376 TRACE();
377 sf_i = GET_INODE_INFO(inode);
378 if (!sf_i)
379 return;
380
381 BUG_ON(!sf_i->path);
382 kfree(sf_i->path);
383 kfree(sf_i);
384 SET_INODE_INFO(inode, NULL);
385}
386#else /* LINUX_VERSION_CODE >= 2.6.36 */
387static void sf_evict_inode(struct inode *inode)
388{
389 struct sf_inode_info *sf_i;
390
391 TRACE();
392 truncate_inode_pages(&inode->i_data, 0);
393# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
394 clear_inode(inode);
395# else
396 end_writeback(inode);
397# endif
398
399 sf_i = GET_INODE_INFO(inode);
400 if (!sf_i)
401 return;
402
403 BUG_ON(!sf_i->path);
404 kfree(sf_i->path);
405 kfree(sf_i);
406 SET_INODE_INFO(inode, NULL);
407}
408#endif /* LINUX_VERSION_CODE >= 2.6.36 */
409
410/* this is called by vfs when it wants to populate [inode] with data.
411 the only thing that is known about inode at this point is its index
412 hence we can't do anything here, and let lookup/whatever with the
413 job to properly fill then [inode] */
414#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
415static void sf_read_inode(struct inode *inode)
416{
417}
418#endif
419
420/* vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
421 the folder and free [sf_g] */
422static void sf_put_super(struct super_block *sb)
423{
424 struct sf_glob_info *sf_g;
425
426 sf_g = GET_GLOB_INFO(sb);
427 BUG_ON(!sf_g);
428 sf_done_backing_dev(sf_g);
429 sf_glob_free(sf_g);
430}
431
432#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
433static int sf_statfs(struct super_block *sb, STRUCT_STATFS * stat)
434{
435 return sf_get_volume_info(sb, stat);
436}
437#else
438static int sf_statfs(struct dentry *dentry, STRUCT_STATFS * stat)
439{
440 struct super_block *sb = dentry->d_inode->i_sb;
441 return sf_get_volume_info(sb, stat);
442}
443#endif
444
445static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
446{
447#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
448 struct sf_glob_info *sf_g;
449 struct sf_inode_info *sf_i;
450 struct inode *iroot;
451 SHFLFSOBJINFO fsinfo;
452 int err;
453
454 sf_g = GET_GLOB_INFO(sb);
455 BUG_ON(!sf_g);
456 if (data && data[0] != 0) {
457 struct vbsf_mount_info_new *info =
458 (struct vbsf_mount_info_new *)data;
459 if (info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0
460 && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1
461 && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2) {
462 sf_g->uid = info->uid;
463 sf_g->gid = info->gid;
464 sf_g->ttl = info->ttl;
465 if ((unsigned)info->length >= RT_UOFFSETOF(struct vbsf_mount_info_new, tag)) {
466 sf_g->dmode = info->dmode;
467 sf_g->fmode = info->fmode;
468 sf_g->dmask = info->dmask;
469 sf_g->fmask = info->fmask;
470 } else {
471 sf_g->dmode = ~0;
472 sf_g->fmode = ~0;
473 }
474 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new)) {
475 AssertCompile(sizeof(sf_g->tag) >= sizeof(info->tag));
476 memcpy(sf_g->tag, info->tag, sizeof(info->tag));
477 sf_g->tag[sizeof(sf_g->tag) - 1] = '\0';
478 } else {
479 sf_g->tag[0] = '\0';
480 }
481 }
482 }
483
484 iroot = ilookup(sb, 0);
485 if (!iroot)
486 return -ENOSYS;
487
488 sf_i = GET_INODE_INFO(iroot);
489 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
490 BUG_ON(err != 0);
491 sf_init_inode(sf_g, iroot, &fsinfo);
492 /*unlock_new_inode(iroot); */
493 return 0;
494#else /* LINUX_VERSION_CODE < 2.4.23 */
495 return -ENOSYS;
496#endif /* LINUX_VERSION_CODE < 2.4.23 */
497}
498
499/** Show mount options. */
500#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
501static int sf_show_options(struct seq_file *m, struct vfsmount *mnt)
502#else
503static int sf_show_options(struct seq_file *m, struct dentry *root)
504#endif
505{
506#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
507 struct super_block *sb = mnt->mnt_sb;
508#else
509 struct super_block *sb = root->d_sb;
510#endif
511 struct sf_glob_info *sf_g = GET_GLOB_INFO(sb);
512 if (sf_g) {
513 seq_printf(m, ",uid=%u,gid=%u,ttl=%u,dmode=0%o,fmode=0%o,dmask=0%o,fmask=0%o",
514 sf_g->uid, sf_g->gid, sf_g->ttl, sf_g->dmode, sf_g->fmode, sf_g->dmask, sf_g->fmask);
515 if (sf_g->tag[0] != '\0') {
516 seq_puts(m, ",tag=");
517 seq_escape(m, sf_g->tag, " \t\n\\");
518 }
519 }
520
521 return 0;
522}
523
524static struct super_operations sf_super_ops = {
525#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
526 .clear_inode = sf_clear_inode,
527#else
528 .evict_inode = sf_evict_inode,
529#endif
530#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
531 .read_inode = sf_read_inode,
532#endif
533 .put_super = sf_put_super,
534 .statfs = sf_statfs,
535 .remount_fs = sf_remount_fs,
536 .show_options = sf_show_options
537};
538
539#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
540static DECLARE_FSTYPE(vboxsf_fs_type, "vboxsf", sf_read_super_24, 0);
541#else
542static int sf_read_super_26(struct super_block *sb, void *data, int flags)
543{
544 int err;
545
546 TRACE();
547 err = sf_read_super_aux(sb, data, flags);
548 if (err)
549 printk(KERN_DEBUG "sf_read_super_aux err=%d\n", err);
550
551 return err;
552}
553
554# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
555static struct super_block *sf_get_sb(struct file_system_type *fs_type,
556 int flags, const char *dev_name,
557 void *data)
558{
559 TRACE();
560 return get_sb_nodev(fs_type, flags, data, sf_read_super_26);
561}
562# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
563static int sf_get_sb(struct file_system_type *fs_type, int flags,
564 const char *dev_name, void *data, struct vfsmount *mnt)
565{
566 TRACE();
567 return get_sb_nodev(fs_type, flags, data, sf_read_super_26, mnt);
568}
569# else /* LINUX_VERSION_CODE >= 2.6.39 */
570static struct dentry *sf_mount(struct file_system_type *fs_type, int flags,
571 const char *dev_name, void *data)
572{
573 TRACE();
574 return mount_nodev(fs_type, flags, data, sf_read_super_26);
575}
576# endif /* LINUX_VERSION_CODE >= 2.6.39 */
577
578static struct file_system_type vboxsf_fs_type = {
579 .owner = THIS_MODULE,
580 .name = "vboxsf",
581# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
582 .get_sb = sf_get_sb,
583# else
584 .mount = sf_mount,
585# endif
586 .kill_sb = kill_anon_super
587};
588
589#endif /* LINUX_VERSION_CODE >= 2.6.0 */
590
591#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
592static int follow_symlinks = 0;
593module_param(follow_symlinks, int, 0);
594MODULE_PARM_DESC(follow_symlinks,
595 "Let host resolve symlinks rather than showing them");
596#endif
597
598/* Module initialization/finalization handlers */
599static int __init init(void)
600{
601 int rcVBox;
602 int rcRet = 0;
603 int err;
604
605 TRACE();
606
607 if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE) {
608 printk(KERN_ERR
609 "Mount information structure is too large %lu\n"
610 "Must be less than or equal to %lu\n",
611 (unsigned long)sizeof(struct vbsf_mount_info_new),
612 (unsigned long)PAGE_SIZE);
613 return -EINVAL;
614 }
615
616 err = register_filesystem(&vboxsf_fs_type);
617 if (err) {
618 LogFunc(("register_filesystem err=%d\n", err));
619 return err;
620 }
621
622 rcVBox = VbglR0HGCMInit();
623 if (RT_FAILURE(rcVBox)) {
624 LogRelFunc(("VbglR0HGCMInit failed, rc=%d\n", rcVBox));
625 rcRet = -EPROTO;
626 goto fail0;
627 }
628
629 rcVBox = VbglR0SfConnect(&client_handle);
630 if (RT_FAILURE(rcVBox)) {
631 LogRelFunc(("VbglR0SfConnect failed, rc=%d\n", rcVBox));
632 rcRet = -EPROTO;
633 goto fail1;
634 }
635
636 rcVBox = VbglR0SfSetUtf8(&client_handle);
637 if (RT_FAILURE(rcVBox)) {
638 LogRelFunc(("VbglR0SfSetUtf8 failed, rc=%d\n", rcVBox));
639 rcRet = -EPROTO;
640 goto fail2;
641 }
642#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
643 if (!follow_symlinks) {
644 rcVBox = VbglR0SfSetSymlinks(&client_handle);
645 if (RT_FAILURE(rcVBox)) {
646 printk(KERN_WARNING
647 "vboxsf: Host unable to show symlinks, rc=%d\n",
648 rcVBox);
649 }
650 }
651#endif
652
653 printk(KERN_DEBUG
654 "vboxsf: Successfully loaded version " VBOX_VERSION_STRING
655 " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
656
657 return 0;
658
659 fail2:
660 VbglR0SfDisconnect(&client_handle);
661
662 fail1:
663 VbglR0HGCMTerminate();
664
665 fail0:
666 unregister_filesystem(&vboxsf_fs_type);
667 return rcRet;
668}
669
670static void __exit fini(void)
671{
672 TRACE();
673
674 VbglR0SfDisconnect(&client_handle);
675 VbglR0HGCMTerminate();
676 unregister_filesystem(&vboxsf_fs_type);
677}
678
679module_init(init);
680module_exit(fini);
681
682/* C++ hack */
683int __gxx_personality_v0 = 0xdeadbeef;
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette