VirtualBox

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

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

linux/vboxsf: Started converting the code to use the more efficient interfaces in VBoxGuestLibSharedFoldersInline.h. Some minor fixes and cleanups. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.2 KB
Line 
1/* $Id: vfsmod.c 77054 2019-01-30 17:40:43Z 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#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
43# include <linux/mount.h>
44#endif
45#include <linux/seq_file.h>
46#include <iprt/path.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;
60VBGLSFCLIENT g_SfClient; /* temporary? */
61uint32_t g_fHostFeatures = 0; /* temporary? */
62
63/* forward declarations */
64static struct super_operations sf_super_ops;
65
66/* allocate global info, try to map host share */
67static int sf_glob_alloc(struct vbsf_mount_info_new *info,
68 struct sf_glob_info **sf_gp)
69{
70 int err, rc;
71 SHFLSTRING *str_name;
72 size_t name_len, str_len;
73 struct sf_glob_info *sf_g;
74
75 TRACE();
76 sf_g = kmalloc(sizeof(*sf_g), GFP_KERNEL);
77 if (!sf_g) {
78 err = -ENOMEM;
79 LogRelFunc(("could not allocate memory for global info\n"));
80 goto fail0;
81 }
82
83 RT_ZERO(*sf_g);
84
85 if (info->nullchar != '\0'
86 || info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
87 || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
88 || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2) {
89 err = -EINVAL;
90 goto fail1;
91 }
92
93 info->name[sizeof(info->name) - 1] = 0;
94 info->nls_name[sizeof(info->nls_name) - 1] = 0;
95
96 name_len = strlen(info->name);
97 str_len = offsetof(SHFLSTRING, String.utf8) + name_len + 1;
98 str_name = kmalloc(str_len, GFP_KERNEL);
99 if (!str_name) {
100 err = -ENOMEM;
101 LogRelFunc(("could not allocate memory for host name\n"));
102 goto fail1;
103 }
104
105 str_name->u16Length = name_len;
106 str_name->u16Size = name_len + 1;
107 memcpy(str_name->String.utf8, info->name, name_len + 1);
108
109#define _IS_UTF8(_str) (strcmp(_str, "utf8") == 0)
110#define _IS_EMPTY(_str) (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
140#undef _IS_UTF8
141#undef _IS_EMPTY
142
143#ifdef VBOXSF_USE_DEPRECATED_VBGL_INTERFACE
144 rc = VbglR0SfMapFolder(&client_handle, str_name, &sf_g->map);
145#else
146 rc = VbglR0SfHostReqMapFolderWithContigSimple(str_name, virt_to_phys(str_name), RTPATH_DELIMITER,
147 true /*fCaseSensitive*/, &sf_g->map.root);
148#endif
149 kfree(str_name);
150
151 if (RT_FAILURE(rc)) {
152 err = -EPROTO;
153 LogFunc(("SHFL_FN_MAP_FOLDER failed rc=%Rrc\n", rc));
154 goto fail2;
155 }
156
157 sf_g->ttl = info->ttl;
158 sf_g->uid = info->uid;
159 sf_g->gid = info->gid;
160
161 if ((unsigned)info->length >= RT_UOFFSETOF(struct vbsf_mount_info_new, tag)) {
162 /* new fields */
163 sf_g->dmode = info->dmode;
164 sf_g->fmode = info->fmode;
165 sf_g->dmask = info->dmask;
166 sf_g->fmask = info->fmask;
167 } else {
168 sf_g->dmode = ~0;
169 sf_g->fmode = ~0;
170 }
171
172 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new)) {
173 AssertCompile(sizeof(sf_g->tag) >= sizeof(info->tag));
174 memcpy(sf_g->tag, info->tag, sizeof(info->tag));
175 sf_g->tag[sizeof(sf_g->tag) - 1] = '\0';
176 } else {
177 sf_g->tag[0] = '\0';
178 }
179
180 *sf_gp = sf_g;
181 return 0;
182
183 fail2:
184 if (sf_g->nls)
185 unload_nls(sf_g->nls);
186
187 fail1:
188 kfree(sf_g);
189
190 fail0:
191 return err;
192}
193
194/* unmap the share and free global info [sf_g] */
195static void sf_glob_free(struct sf_glob_info *sf_g)
196{
197 int rc;
198
199 TRACE();
200#ifdef VBOXSF_USE_DEPRECATED_VBGL_INTERFACE
201 rc = VbglR0SfUnmapFolder(&client_handle, &sf_g->map);
202 if (RT_FAILURE(rc))
203 LogFunc(("VbglR0SfUnmapFolder failed rc=%d\n", rc));
204#else
205 rc = VbglR0SfHostReqUnmapFolderSimple(sf_g->map.root);
206 if (RT_FAILURE(rc))
207 LogFunc(("VbglR0SfHostReqUnmapFolderSimple failed rc=%Rrc\n", rc));
208#endif
209
210 if (sf_g->nls)
211 unload_nls(sf_g->nls);
212
213 kfree(sf_g);
214}
215
216/**
217 * This is called (by sf_read_super_[24|26] when vfs mounts the fs and
218 * wants to read super_block.
219 *
220 * calls [sf_glob_alloc] to map the folder and allocate global
221 * information structure.
222 *
223 * initializes [sb], initializes root inode and dentry.
224 *
225 * should respect [flags]
226 */
227static int sf_read_super_aux(struct super_block *sb, void *data, int flags)
228{
229 int err;
230 struct dentry *droot;
231 struct inode *iroot;
232 struct sf_inode_info *sf_i;
233 struct sf_glob_info *sf_g;
234 SHFLFSOBJINFO fsinfo;
235 struct vbsf_mount_info_new *info;
236 bool fInodePut = true;
237
238 TRACE();
239 if (!data) {
240 LogFunc(("no mount info specified\n"));
241 return -EINVAL;
242 }
243
244 info = data;
245
246 if (flags & MS_REMOUNT) {
247 LogFunc(("remounting is not supported\n"));
248 return -ENOSYS;
249 }
250
251 err = sf_glob_alloc(info, &sf_g);
252 if (err)
253 goto fail0;
254
255 sf_i = kmalloc(sizeof(*sf_i), GFP_KERNEL);
256 if (!sf_i) {
257 err = -ENOMEM;
258 LogRelFunc(("could not allocate memory for root inode info\n"));
259 goto fail1;
260 }
261
262 sf_i->handle = SHFL_HANDLE_NIL;
263 sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL);
264 if (!sf_i->path) {
265 err = -ENOMEM;
266 LogRelFunc(("could not allocate memory for root inode path\n"));
267 goto fail2;
268 }
269
270 sf_i->path->u16Length = 1;
271 sf_i->path->u16Size = 2;
272 sf_i->path->String.utf8[0] = '/';
273 sf_i->path->String.utf8[1] = 0;
274 sf_i->force_reread = 0;
275
276 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
277 if (err) {
278 LogFunc(("could not stat root of share\n"));
279 goto fail3;
280 }
281
282 sb->s_magic = 0xface;
283 sb->s_blocksize = 1024;
284#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 3)
285 /* Required for seek/sendfile.
286 *
287 * Must by less than or equal to INT64_MAX despite the fact that the
288 * declaration of this variable is unsigned long long. See determination
289 * of 'loff_t max' in fs/read_write.c / do_sendfile(). I don't know the
290 * correct limit but MAX_LFS_FILESIZE (8TB-1 on 32-bit boxes) takes the
291 * page cache into account and is the suggested limit. */
292# if defined MAX_LFS_FILESIZE
293 sb->s_maxbytes = MAX_LFS_FILESIZE;
294# else
295 sb->s_maxbytes = 0x7fffffffffffffffULL;
296# endif
297#endif
298 sb->s_op = &sf_super_ops;
299
300#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
301 iroot = iget_locked(sb, 0);
302#else
303 iroot = iget(sb, 0);
304#endif
305 if (!iroot) {
306 err = -ENOMEM; /* XXX */
307 LogFunc(("could not get root inode\n"));
308 goto fail3;
309 }
310
311 if (sf_init_backing_dev(sf_g)) {
312 err = -EINVAL;
313 LogFunc(("could not init bdi\n"));
314#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
315 unlock_new_inode(iroot);
316#endif
317 goto fail4;
318 }
319
320 sf_init_inode(sf_g, iroot, &fsinfo);
321 SET_INODE_INFO(iroot, sf_i);
322
323#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
324 unlock_new_inode(iroot);
325#endif
326
327#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
328 droot = d_make_root(iroot);
329#else
330 droot = d_alloc_root(iroot);
331#endif
332 if (!droot) {
333 err = -ENOMEM; /* XXX */
334 LogFunc(("d_alloc_root failed\n"));
335#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
336 fInodePut = false;
337#endif
338 goto fail5;
339 }
340
341 sb->s_root = droot;
342 SET_GLOB_INFO(sb, sf_g);
343 return 0;
344
345 fail5:
346 sf_done_backing_dev(sf_g);
347
348 fail4:
349 if (fInodePut)
350 iput(iroot);
351
352 fail3:
353 kfree(sf_i->path);
354
355 fail2:
356 kfree(sf_i);
357
358 fail1:
359 sf_glob_free(sf_g);
360
361 fail0:
362 return err;
363}
364
365#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
366static struct super_block *sf_read_super_24(struct super_block *sb, void *data,
367 int flags)
368{
369 int err;
370
371 TRACE();
372 err = sf_read_super_aux(sb, data, flags);
373 if (err)
374 return NULL;
375
376 return sb;
377}
378#endif
379
380/* this is called when vfs is about to destroy the [inode]. all
381 resources associated with this [inode] must be cleared here */
382#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
383static void sf_clear_inode(struct inode *inode)
384{
385 struct sf_inode_info *sf_i;
386
387 TRACE();
388 sf_i = GET_INODE_INFO(inode);
389 if (!sf_i)
390 return;
391
392 BUG_ON(!sf_i->path);
393 kfree(sf_i->path);
394 kfree(sf_i);
395 SET_INODE_INFO(inode, NULL);
396}
397#else /* LINUX_VERSION_CODE >= 2.6.36 */
398static void sf_evict_inode(struct inode *inode)
399{
400 struct sf_inode_info *sf_i;
401
402 TRACE();
403 truncate_inode_pages(&inode->i_data, 0);
404# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
405 clear_inode(inode);
406# else
407 end_writeback(inode);
408# endif
409
410 sf_i = GET_INODE_INFO(inode);
411 if (!sf_i)
412 return;
413
414 BUG_ON(!sf_i->path);
415 kfree(sf_i->path);
416 kfree(sf_i);
417 SET_INODE_INFO(inode, NULL);
418}
419#endif /* LINUX_VERSION_CODE >= 2.6.36 */
420
421/* this is called by vfs when it wants to populate [inode] with data.
422 the only thing that is known about inode at this point is its index
423 hence we can't do anything here, and let lookup/whatever with the
424 job to properly fill then [inode] */
425#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
426static void sf_read_inode(struct inode *inode)
427{
428}
429#endif
430
431/* vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
432 the folder and free [sf_g] */
433static void sf_put_super(struct super_block *sb)
434{
435 struct sf_glob_info *sf_g;
436
437 sf_g = GET_GLOB_INFO(sb);
438 BUG_ON(!sf_g);
439 sf_done_backing_dev(sf_g);
440 sf_glob_free(sf_g);
441}
442
443#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
444static int sf_statfs(struct super_block *sb, STRUCT_STATFS * stat)
445{
446 return sf_get_volume_info(sb, stat);
447}
448#else
449static int sf_statfs(struct dentry *dentry, STRUCT_STATFS * stat)
450{
451 struct super_block *sb = dentry->d_inode->i_sb;
452 return sf_get_volume_info(sb, stat);
453}
454#endif
455
456static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
457{
458#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
459 struct sf_glob_info *sf_g;
460 struct sf_inode_info *sf_i;
461 struct inode *iroot;
462 SHFLFSOBJINFO fsinfo;
463 int err;
464
465 sf_g = GET_GLOB_INFO(sb);
466 BUG_ON(!sf_g);
467 if (data && data[0] != 0) {
468 struct vbsf_mount_info_new *info = (struct vbsf_mount_info_new *)data;
469 if (info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0
470 && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1
471 && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2) {
472 sf_g->uid = info->uid;
473 sf_g->gid = info->gid;
474 sf_g->ttl = info->ttl;
475 if ((unsigned)info->length >= RT_UOFFSETOF(struct vbsf_mount_info_new, tag)) {
476 sf_g->dmode = info->dmode;
477 sf_g->fmode = info->fmode;
478 sf_g->dmask = info->dmask;
479 sf_g->fmask = info->fmask;
480 } else {
481 sf_g->dmode = ~0;
482 sf_g->fmode = ~0;
483 }
484 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new)) {
485 AssertCompile(sizeof(sf_g->tag) >= sizeof(info->tag));
486 memcpy(sf_g->tag, info->tag, sizeof(info->tag));
487 sf_g->tag[sizeof(sf_g->tag) - 1] = '\0';
488 } else {
489 sf_g->tag[0] = '\0';
490 }
491 }
492 }
493
494 iroot = ilookup(sb, 0);
495 if (!iroot)
496 return -ENOSYS;
497
498 sf_i = GET_INODE_INFO(iroot);
499 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
500 BUG_ON(err != 0);
501 sf_init_inode(sf_g, iroot, &fsinfo);
502 /*unlock_new_inode(iroot); */
503 return 0;
504#else /* LINUX_VERSION_CODE < 2.4.23 */
505 return -ENOSYS;
506#endif /* LINUX_VERSION_CODE < 2.4.23 */
507}
508
509/** Show mount options. */
510#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
511static int sf_show_options(struct seq_file *m, struct vfsmount *mnt)
512#else
513static int sf_show_options(struct seq_file *m, struct dentry *root)
514#endif
515{
516#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
517 struct super_block *sb = mnt->mnt_sb;
518#else
519 struct super_block *sb = root->d_sb;
520#endif
521 struct sf_glob_info *sf_g = GET_GLOB_INFO(sb);
522 if (sf_g) {
523 seq_printf(m, ",uid=%u,gid=%u,ttl=%u,dmode=0%o,fmode=0%o,dmask=0%o,fmask=0%o",
524 sf_g->uid, sf_g->gid, sf_g->ttl, sf_g->dmode, sf_g->fmode, sf_g->dmask, sf_g->fmask);
525 if (sf_g->tag[0] != '\0') {
526 seq_puts(m, ",tag=");
527 seq_escape(m, sf_g->tag, " \t\n\\");
528 }
529 }
530
531 return 0;
532}
533
534static struct super_operations sf_super_ops = {
535#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
536 .clear_inode = sf_clear_inode,
537#else
538 .evict_inode = sf_evict_inode,
539#endif
540#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
541 .read_inode = sf_read_inode,
542#endif
543 .put_super = sf_put_super,
544 .statfs = sf_statfs,
545 .remount_fs = sf_remount_fs,
546 .show_options = sf_show_options
547};
548
549#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
550static DECLARE_FSTYPE(vboxsf_fs_type, "vboxsf", sf_read_super_24, 0);
551#else
552static int sf_read_super_26(struct super_block *sb, void *data, int flags)
553{
554 int err;
555
556 TRACE();
557 err = sf_read_super_aux(sb, data, flags);
558 if (err)
559 printk(KERN_DEBUG "sf_read_super_aux err=%d\n", err);
560
561 return err;
562}
563
564# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
565static struct super_block *sf_get_sb(struct file_system_type *fs_type,
566 int flags, const char *dev_name,
567 void *data)
568{
569 TRACE();
570 return get_sb_nodev(fs_type, flags, data, sf_read_super_26);
571}
572# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
573static int sf_get_sb(struct file_system_type *fs_type, int flags,
574 const char *dev_name, void *data, struct vfsmount *mnt)
575{
576 TRACE();
577 return get_sb_nodev(fs_type, flags, data, sf_read_super_26, mnt);
578}
579# else /* LINUX_VERSION_CODE >= 2.6.39 */
580static struct dentry *sf_mount(struct file_system_type *fs_type, int flags,
581 const char *dev_name, void *data)
582{
583 TRACE();
584 return mount_nodev(fs_type, flags, data, sf_read_super_26);
585}
586# endif /* LINUX_VERSION_CODE >= 2.6.39 */
587
588static struct file_system_type vboxsf_fs_type = {
589 .owner = THIS_MODULE,
590 .name = "vboxsf",
591# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
592 .get_sb = sf_get_sb,
593# else
594 .mount = sf_mount,
595# endif
596 .kill_sb = kill_anon_super
597};
598
599#endif /* LINUX_VERSION_CODE >= 2.6.0 */
600
601#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
602static int follow_symlinks = 0;
603module_param(follow_symlinks, int, 0);
604MODULE_PARM_DESC(follow_symlinks,
605 "Let host resolve symlinks rather than showing them");
606#endif
607
608/* Module initialization/finalization handlers */
609static int __init init(void)
610{
611 int vrc;
612 int rcRet = 0;
613 int err;
614
615 TRACE();
616
617 if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE) {
618 printk(KERN_ERR
619 "Mount information structure is too large %lu\n"
620 "Must be less than or equal to %lu\n",
621 (unsigned long)sizeof(struct vbsf_mount_info_new),
622 (unsigned long)PAGE_SIZE);
623 return -EINVAL;
624 }
625
626 err = register_filesystem(&vboxsf_fs_type);
627 if (err) {
628 LogFunc(("register_filesystem err=%d\n", err));
629 return err;
630 }
631
632 vrc = VbglR0SfInit();
633 if (RT_FAILURE(vrc)) {
634 LogRelFunc(("VbglR0SfInit failed, vrc=%Rrc\n", vrc));
635 rcRet = -EPROTO;
636 goto fail0;
637 }
638
639 vrc = VbglR0SfConnect(&client_handle);
640 g_SfClient = client_handle; /* temporary */
641 if (RT_FAILURE(vrc)) {
642 LogRelFunc(("VbglR0SfConnect failed, vrc=%Rrc\n", vrc));
643 rcRet = -EPROTO;
644 goto fail1;
645 }
646
647 vrc = VbglR0QueryHostFeatures(&g_fHostFeatures);
648 if (RT_FAILURE(vrc))
649 {
650 LogRelFunc(("VbglR0QueryHostFeatures failed: vrc=%Rrc (ignored)\n", vrc));
651 g_fHostFeatures = 0;
652 }
653 LogRelFunc(("g_fHostFeatures=%#x\n", g_fHostFeatures));
654
655 vrc = VbglR0SfSetUtf8(&client_handle);
656 if (RT_FAILURE(vrc)) {
657 LogRelFunc(("VbglR0SfSetUtf8 failed, vrc=%Rrc\n", vrc));
658 rcRet = -EPROTO;
659 goto fail2;
660 }
661#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
662 if (!follow_symlinks) {
663 vrc = VbglR0SfSetSymlinks(&client_handle);
664 if (RT_FAILURE(vrc)) {
665 printk(KERN_WARNING
666 "vboxsf: Host unable to show symlinks, vrc=%d\n",
667 vrc);
668 }
669 }
670#endif
671
672 printk(KERN_DEBUG
673 "vboxsf: Successfully loaded version " VBOX_VERSION_STRING
674 " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
675
676 return 0;
677
678 fail2:
679 VbglR0SfDisconnect(&client_handle);
680 g_SfClient = client_handle; /* temporary */
681
682 fail1:
683 VbglR0SfTerm();
684
685 fail0:
686 unregister_filesystem(&vboxsf_fs_type);
687 return rcRet;
688}
689
690static void __exit fini(void)
691{
692 TRACE();
693
694 VbglR0SfDisconnect(&client_handle);
695 g_SfClient = client_handle; /* temporary */
696 VbglR0SfTerm();
697 unregister_filesystem(&vboxsf_fs_type);
698}
699
700module_init(init);
701module_exit(fini);
702
703/* C++ hack */
704int __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