VirtualBox

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

Last change on this file since 42880 was 41577, checked in by vboxsync, 13 years ago

Additions/linux/sharedfolders: Linux 3.5 compile fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 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-2010 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 */
23
24/**
25 * @note Anyone wishing to make changes here might wish to take a look at
26 * http://www.atnf.csiro.au/people/rgooch/linux/vfs.txt
27 * which seems to be the closest there is to official documentation on
28 * writing filesystem drivers for Linux.
29 */
30
31#include "vfsmod.h"
32
33MODULE_DESCRIPTION(VBOX_PRODUCT " VFS Module for Host File System Access");
34MODULE_AUTHOR(VBOX_VENDOR);
35MODULE_LICENSE("GPL");
36#ifdef MODULE_VERSION
37MODULE_VERSION(VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")");
38#endif
39
40/* globals */
41VBSFCLIENT client_handle;
42
43/* forward declarations */
44static struct super_operations sf_super_ops;
45
46/* allocate global info, try to map host share */
47static int sf_glob_alloc(struct vbsf_mount_info_new *info, struct sf_glob_info **sf_gp)
48{
49 int err, rc;
50 SHFLSTRING *str_name;
51 size_t name_len, str_len;
52 struct sf_glob_info *sf_g;
53
54 TRACE();
55 sf_g = kmalloc(sizeof(*sf_g), GFP_KERNEL);
56 if (!sf_g)
57 {
58 err = -ENOMEM;
59 LogRelFunc(("could not allocate memory for global info\n"));
60 goto fail0;
61 }
62
63 RT_ZERO(*sf_g);
64
65 if ( info->nullchar != '\0'
66 || info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
67 || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
68 || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2)
69 {
70 /* An old version of mount.vboxsf made the syscall. Translate the
71 * old parameters to the new structure. */
72 struct vbsf_mount_info_old *info_old = (struct vbsf_mount_info_old *)info;
73 static struct vbsf_mount_info_new info_compat;
74
75 info = &info_compat;
76 memset(info, 0, sizeof(*info));
77 memcpy(&info->name, &info_old->name, MAX_HOST_NAME);
78 memcpy(&info->nls_name, &info_old->nls_name, MAX_NLS_NAME);
79 info->length = offsetof(struct vbsf_mount_info_new, dmode);
80 info->uid = info_old->uid;
81 info->gid = info_old->gid;
82 info->ttl = info_old->ttl;
83 }
84
85 info->name[sizeof(info->name) - 1] = 0;
86 info->nls_name[sizeof(info->nls_name) - 1] = 0;
87
88 name_len = strlen(info->name);
89 if (name_len > 0xfffe)
90 {
91 err = -ENAMETOOLONG;
92 LogFunc(("map name too big\n"));
93 goto fail1;
94 }
95
96 str_len = offsetof(SHFLSTRING, String.utf8) + name_len + 1;
97 str_name = kmalloc(str_len, GFP_KERNEL);
98 if (!str_name)
99 {
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 if (info->nls_name[0] && strcmp(info->nls_name, "utf8"))
110 {
111 sf_g->nls = load_nls(info->nls_name);
112 if (!sf_g->nls)
113 {
114 err = -EINVAL;
115 LogFunc(("failed to load nls %s\n", info->nls_name));
116 goto fail1;
117 }
118 }
119 else
120 sf_g->nls = NULL;
121
122 rc = vboxCallMapFolder(&client_handle, str_name, &sf_g->map);
123 kfree(str_name);
124
125 if (RT_FAILURE(rc))
126 {
127 err = -EPROTO;
128 LogFunc(("vboxCallMapFolder failed rc=%d\n", rc));
129 goto fail2;
130 }
131
132 sf_g->ttl = info->ttl;
133 sf_g->uid = info->uid;
134 sf_g->gid = info->gid;
135
136 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new))
137 {
138 /* new fields */
139 sf_g->dmode = info->dmode;
140 sf_g->fmode = info->fmode;
141 sf_g->dmask = info->dmask;
142 sf_g->fmask = info->fmask;
143 }
144 else
145 {
146 sf_g->dmode = ~0;
147 sf_g->fmode = ~0;
148 }
149
150 *sf_gp = sf_g;
151 return 0;
152
153fail2:
154 if (sf_g->nls)
155 unload_nls(sf_g->nls);
156
157fail1:
158 kfree(sf_g);
159
160fail0:
161 return err;
162}
163
164/* unmap the share and free global info [sf_g] */
165static void
166sf_glob_free(struct sf_glob_info *sf_g)
167{
168 int rc;
169
170 TRACE();
171 rc = vboxCallUnmapFolder(&client_handle, &sf_g->map);
172 if (RT_FAILURE(rc))
173 LogFunc(("vboxCallUnmapFolder failed rc=%d\n", rc));
174
175 if (sf_g->nls)
176 unload_nls(sf_g->nls);
177
178 kfree(sf_g);
179}
180
181/**
182 * This is called (by sf_read_super_[24|26] when vfs mounts the fs and
183 * wants to read super_block.
184 *
185 * calls [sf_glob_alloc] to map the folder and allocate global
186 * information structure.
187 *
188 * initializes [sb], initializes root inode and dentry.
189 *
190 * should respect [flags]
191 */
192static int sf_read_super_aux(struct super_block *sb, void *data, int flags)
193{
194 int err;
195 struct dentry *droot;
196 struct inode *iroot;
197 struct sf_inode_info *sf_i;
198 struct sf_glob_info *sf_g;
199 SHFLFSOBJINFO fsinfo;
200 struct vbsf_mount_info_new *info;
201 bool fInodePut = true;
202
203 TRACE();
204 if (!data)
205 {
206 LogFunc(("no mount info specified\n"));
207 return -EINVAL;
208 }
209
210 info = data;
211
212 if (flags & MS_REMOUNT)
213 {
214 LogFunc(("remounting is not supported\n"));
215 return -ENOSYS;
216 }
217
218 err = sf_glob_alloc(info, &sf_g);
219 if (err)
220 goto fail0;
221
222 sf_i = kmalloc(sizeof (*sf_i), GFP_KERNEL);
223 if (!sf_i)
224 {
225 err = -ENOMEM;
226 LogRelFunc(("could not allocate memory for root inode info\n"));
227 goto fail1;
228 }
229
230 sf_i->handle = SHFL_HANDLE_NIL;
231 sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL);
232 if (!sf_i->path)
233 {
234 err = -ENOMEM;
235 LogRelFunc(("could not allocate memory for root inode path\n"));
236 goto fail2;
237 }
238
239 sf_i->path->u16Length = 1;
240 sf_i->path->u16Size = 2;
241 sf_i->path->String.utf8[0] = '/';
242 sf_i->path->String.utf8[1] = 0;
243 sf_i->force_reread = 0;
244
245 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
246 if (err)
247 {
248 LogFunc(("could not stat root of share\n"));
249 goto fail3;
250 }
251
252 sb->s_magic = 0xface;
253 sb->s_blocksize = 1024;
254#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 3)
255 /* Required for seek/sendfile.
256 *
257 * Must by less than or equal to INT64_MAX despite the fact that the
258 * declaration of this variable is unsigned long long. See determination
259 * of 'loff_t max' in fs/read_write.c / do_sendfile(). I don't know the
260 * correct limit but MAX_LFS_FILESIZE (8TB-1 on 32-bit boxes) takes the
261 * page cache into account and is the suggested limit. */
262# if defined MAX_LFS_FILESIZE
263 sb->s_maxbytes = MAX_LFS_FILESIZE;
264# else
265 sb->s_maxbytes = 0x7fffffffffffffffULL;
266# endif
267#endif
268 sb->s_op = &sf_super_ops;
269
270#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
271 iroot = iget_locked(sb, 0);
272#else
273 iroot = iget(sb, 0);
274#endif
275 if (!iroot)
276 {
277 err = -ENOMEM; /* XXX */
278 LogFunc(("could not get root inode\n"));
279 goto fail3;
280 }
281
282 if (sf_init_backing_dev(sf_g))
283 {
284 err = -EINVAL;
285 LogFunc(("could not init bdi\n"));
286#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
287 unlock_new_inode(iroot);
288#endif
289 goto fail4;
290 }
291
292 sf_init_inode(sf_g, iroot, &fsinfo);
293 SET_INODE_INFO(iroot, sf_i);
294
295#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
296 unlock_new_inode(iroot);
297#endif
298
299#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
300 droot = d_make_root(iroot);
301#else
302 droot = d_alloc_root(iroot);
303#endif
304 if (!droot)
305 {
306 err = -ENOMEM; /* XXX */
307 LogFunc(("d_alloc_root failed\n"));
308#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
309 fInodePut = false;
310#endif
311 goto fail5;
312 }
313
314 sb->s_root = droot;
315 SET_GLOB_INFO(sb, sf_g);
316 return 0;
317
318fail5:
319 sf_done_backing_dev(sf_g);
320
321fail4:
322 if (fInodePut)
323 iput(iroot);
324
325fail3:
326 kfree(sf_i->path);
327
328fail2:
329 kfree(sf_i);
330
331fail1:
332 sf_glob_free(sf_g);
333
334fail0:
335 return err;
336}
337
338#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
339static struct super_block *
340sf_read_super_24(struct super_block *sb, void *data, int flags)
341{
342 int err;
343
344 TRACE();
345 err = sf_read_super_aux(sb, data, flags);
346 if (err)
347 return NULL;
348
349 return sb;
350}
351#endif
352
353/* this is called when vfs is about to destroy the [inode]. all
354 resources associated with this [inode] must be cleared here */
355#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
356static void sf_clear_inode(struct inode *inode)
357{
358 struct sf_inode_info *sf_i;
359
360 TRACE();
361 sf_i = GET_INODE_INFO(inode);
362 if (!sf_i)
363 return;
364
365 BUG_ON(!sf_i->path);
366 kfree(sf_i->path);
367 kfree(sf_i);
368 SET_INODE_INFO(inode, NULL);
369}
370#else
371static void sf_evict_inode(struct inode *inode)
372{
373 struct sf_inode_info *sf_i;
374
375 TRACE();
376 truncate_inode_pages(&inode->i_data, 0);
377# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
378 clear_inode(inode);
379# else
380 end_writeback(inode);
381# endif
382
383 sf_i = GET_INODE_INFO(inode);
384 if (!sf_i)
385 return;
386
387 BUG_ON(!sf_i->path);
388 kfree(sf_i->path);
389 kfree(sf_i);
390 SET_INODE_INFO(inode, NULL);
391}
392#endif
393
394/* this is called by vfs when it wants to populate [inode] with data.
395 the only thing that is known about inode at this point is its index
396 hence we can't do anything here, and let lookup/whatever with the
397 job to properly fill then [inode] */
398#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
399static void sf_read_inode(struct inode *inode)
400{
401}
402#endif
403
404/* vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
405 the folder and free [sf_g] */
406static void sf_put_super(struct super_block *sb)
407{
408 struct sf_glob_info *sf_g;
409
410 sf_g = GET_GLOB_INFO(sb);
411 BUG_ON(!sf_g);
412 sf_done_backing_dev(sf_g);
413 sf_glob_free(sf_g);
414}
415
416#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
417static int sf_statfs(struct super_block *sb, STRUCT_STATFS *stat)
418{
419 return sf_get_volume_info(sb, stat);
420}
421#else
422static int sf_statfs(struct dentry *dentry, STRUCT_STATFS *stat)
423{
424 struct super_block *sb = dentry->d_inode->i_sb;
425 return sf_get_volume_info(sb, stat);
426}
427#endif
428
429static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
430{
431#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
432 struct sf_glob_info *sf_g;
433 struct vbsf_mount_info_new *info;
434 struct sf_inode_info *sf_i;
435 struct inode *iroot;
436 SHFLFSOBJINFO fsinfo;
437 int err;
438
439 printk(KERN_DEBUG "ENTER: sf_remount_fs\n");
440 sf_g = GET_GLOB_INFO(sb);
441 BUG_ON(!sf_g);
442 BUG_ON(data[0] != 0);
443 info = (struct vbsf_mount_info_new *)data;
444 BUG_ON( info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
445 || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
446 || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2);
447
448 sf_g->uid = info->uid;
449 sf_g->gid = info->gid;
450 sf_g->ttl = info->ttl;
451 sf_g->dmode = info->dmode;
452 sf_g->fmode = info->fmode;
453 sf_g->dmask = info->dmask;
454 sf_g->fmask = info->fmask;
455
456 iroot = ilookup(sb, 0);
457 if (!iroot)
458 {
459 printk(KERN_DEBUG "can't find root inode\n");
460 return -ENOSYS;
461 }
462 sf_i = GET_INODE_INFO(iroot);
463 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
464 BUG_ON(err != 0);
465 sf_init_inode(sf_g, iroot, &fsinfo);
466 /*unlock_new_inode(iroot);*/
467 printk(KERN_DEBUG "LEAVE: sf_remount_fs\n");
468 return 0;
469#else
470 return -ENOSYS;
471#endif
472}
473
474static struct super_operations sf_super_ops =
475{
476#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
477 .clear_inode = sf_clear_inode,
478#else
479 .evict_inode = sf_evict_inode,
480#endif
481#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
482 .read_inode = sf_read_inode,
483#endif
484 .put_super = sf_put_super,
485 .statfs = sf_statfs,
486 .remount_fs = sf_remount_fs
487};
488
489#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
490static DECLARE_FSTYPE(vboxsf_fs_type, "vboxsf", sf_read_super_24, 0);
491#else
492static int
493sf_read_super_26(struct super_block *sb, void *data, int flags)
494{
495 int err;
496
497 TRACE();
498 err = sf_read_super_aux(sb, data, flags);
499 if (err)
500 printk(KERN_DEBUG "sf_read_super_aux err=%d\n", err);
501
502 return err;
503}
504
505# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
506static struct super_block *sf_get_sb(struct file_system_type *fs_type, int flags,
507 const char *dev_name, void *data)
508{
509 TRACE();
510 return get_sb_nodev(fs_type, flags, data, sf_read_super_26);
511}
512# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
513static int sf_get_sb(struct file_system_type *fs_type, int flags,
514 const char *dev_name, void *data, struct vfsmount *mnt)
515{
516 TRACE();
517 return get_sb_nodev(fs_type, flags, data, sf_read_super_26, mnt);
518}
519# else
520static struct dentry *sf_mount(struct file_system_type *fs_type, int flags,
521 const char *dev_name, void *data)
522{
523 TRACE();
524 return mount_nodev(fs_type, flags, data, sf_read_super_26);
525}
526# endif
527
528static struct file_system_type vboxsf_fs_type =
529{
530 .owner = THIS_MODULE,
531 .name = "vboxsf",
532# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
533 .get_sb = sf_get_sb,
534# else
535 .mount = sf_mount,
536# endif
537 .kill_sb = kill_anon_super
538};
539#endif
540
541#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
542static int follow_symlinks = 0;
543module_param(follow_symlinks, int, 0);
544MODULE_PARM_DESC(follow_symlinks, "Let host resolve symlinks rather than showing them");
545#endif
546
547/* Module initialization/finalization handlers */
548static int __init init(void)
549{
550 int rcVBox;
551 int rcRet = 0;
552 int err;
553
554 TRACE();
555
556 if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE)
557 {
558 printk(KERN_ERR
559 "Mount information structure is too large %lu\n"
560 "Must be less than or equal to %lu\n",
561 (unsigned long)sizeof (struct vbsf_mount_info_new),
562 (unsigned long)PAGE_SIZE);
563 return -EINVAL;
564 }
565
566 err = register_filesystem(&vboxsf_fs_type);
567 if (err)
568 {
569 LogFunc(("register_filesystem err=%d\n", err));
570 return err;
571 }
572
573 rcVBox = vboxInit();
574 if (RT_FAILURE(rcVBox))
575 {
576 LogRelFunc(("vboxInit failed, rc=%d\n", rcVBox));
577 rcRet = -EPROTO;
578 goto fail0;
579 }
580
581 rcVBox = vboxConnect(&client_handle);
582 if (RT_FAILURE(rcVBox))
583 {
584 LogRelFunc(("vboxConnect failed, rc=%d\n", rcVBox));
585 rcRet = -EPROTO;
586 goto fail1;
587 }
588
589 rcVBox = vboxCallSetUtf8(&client_handle);
590 if (RT_FAILURE(rcVBox))
591 {
592 LogRelFunc(("vboxCallSetUtf8 failed, rc=%d\n", rcVBox));
593 rcRet = -EPROTO;
594 goto fail2;
595 }
596
597#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
598 if (!follow_symlinks)
599 {
600 rcVBox = vboxCallSetSymlinks(&client_handle);
601 if (RT_FAILURE(rcVBox))
602 {
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
616fail2:
617 vboxDisconnect(&client_handle);
618
619fail1:
620 vboxUninit();
621
622fail0:
623 unregister_filesystem(&vboxsf_fs_type);
624 return rcRet;
625}
626
627static void __exit fini(void)
628{
629 TRACE();
630
631 vboxDisconnect(&client_handle);
632 vboxUninit();
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