VirtualBox

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

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

VBoxSharedFolders,VBoxService,VBoxTray: New go at auto mounting shared folders, now also at runtime. bugref:3544

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