VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c@ 93449

Last change on this file since 93449 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.5 KB
Line 
1/* $Id: vboxfs_vfs.c 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox File System for Solaris Guests, VFS implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27#include <VBox/log.h>
28#include <VBox/version.h>
29#include <iprt/dbg.h>
30
31#include <sys/types.h>
32#include <sys/mntent.h>
33#include <sys/param.h>
34#include <sys/modctl.h>
35#include <sys/mount.h>
36#include <sys/policy.h>
37#include <sys/atomic.h>
38#include <sys/sysmacros.h>
39#include <sys/ddi.h>
40#include <sys/sunddi.h>
41#include <sys/vfs.h>
42#if !defined(VBOX_VFS_SOLARIS_10U6)
43# include <sys/vfs_opreg.h>
44#endif
45#include <sys/pathname.h>
46#include <sys/cmn_err.h>
47#include <sys/vmsystm.h>
48#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
49
50#include "vboxfs_prov.h"
51#include "vboxfs_vnode.h"
52#include "vboxfs_vfs.h"
53#include "vboxfs.h"
54
55
56#define VBOXSOLQUOTE2(x) #x
57#define VBOXSOLQUOTE(x) VBOXSOLQUOTE2(x)
58/** The module name. */
59#define DEVICE_NAME "vboxfs"
60/** The module description as seen in 'modinfo'. */
61#define DEVICE_DESC "VirtualBox ShrdFS"
62
63
64/*
65 * Shared Folders filesystem implementation of the Solaris VFS interfaces.
66 * Much of this is cookie cutter code for Solaris filesystem implementation.
67 */
68
69/* forward declarations */
70static int sffs_init(int fstype, char *name);
71static int sffs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
72static int sffs_unmount(vfs_t *vfsp, int flag, cred_t *cr);
73static int sffs_root(vfs_t *vfsp, vnode_t **vpp);
74static int sffs_statvfs(vfs_t *vfsp, statvfs64_t *sbp);
75
76static mntopt_t sffs_options[] = {
77 /* Option Cancels Opt Arg Flags Data */
78 {"uid", NULL, NULL, MO_HASVALUE, NULL},
79 {"gid", NULL, NULL, MO_HASVALUE, NULL},
80 {"dmode", NULL, NULL, MO_HASVALUE, NULL},
81 {"fmode", NULL, NULL, MO_HASVALUE, NULL},
82 {"dmask", NULL, NULL, MO_HASVALUE, NULL},
83 {"fmask", NULL, NULL, MO_HASVALUE, NULL},
84 {"stat_ttl", NULL, NULL, MO_HASVALUE, NULL},
85 {"fsync", NULL, NULL, 0, NULL},
86 {"tag", NULL, NULL, MO_HASVALUE, NULL}
87};
88
89static mntopts_t sffs_options_table = {
90 sizeof (sffs_options) / sizeof (mntopt_t),
91 sffs_options
92};
93
94static vfsdef_t sffs_vfsdef = {
95 VFSDEF_VERSION,
96 DEVICE_NAME,
97 sffs_init,
98 VSW_HASPROTO,
99 &sffs_options_table
100};
101
102static int sffs_fstype;
103static int sffs_major; /* major number for device */
104
105kmutex_t sffs_minor_lock;
106int sffs_minor; /* minor number for device */
107
108/** Whether to use the old-style map_addr()/choose_addr() routines. */
109bool g_fVBoxVFS_SolOldAddrMap;
110/** The map_addr()/choose_addr() hooks callout table structure. */
111VBoxVFS_SolAddrMap g_VBoxVFS_SolAddrMap;
112
113/*
114 * Module linkage information
115 */
116static struct modlfs modlfs = {
117 &mod_fsops,
118 DEVICE_DESC " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
119 &sffs_vfsdef
120};
121
122static struct modlinkage modlinkage = {
123 MODREV_1, &modlfs, NULL
124};
125
126static sfp_connection_t *sfprov = NULL;
127
128int
129_init()
130{
131 RTDBGKRNLINFO hKrnlDbgInfo;
132 int rc = RTR0DbgKrnlInfoOpen(&hKrnlDbgInfo, 0 /* fFlags */);
133 if (RT_SUCCESS(rc))
134 {
135 rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlDbgInfo, NULL /* pszModule */, "plat_map_align_amount", NULL /* ppvSymbol */);
136 if (RT_SUCCESS(rc))
137 {
138#if defined(VBOX_VFS_SOLARIS_10U6)
139 g_VBoxVFS_SolAddrMap.MapAddr.pfnSol_map_addr = (void *)map_addr;
140#else
141 g_VBoxVFS_SolAddrMap.ChooseAddr.pfnSol_choose_addr = (void *)choose_addr;
142#endif
143 }
144 else
145 {
146 g_fVBoxVFS_SolOldAddrMap = true;
147#if defined(VBOX_VFS_SOLARIS_10U6)
148 g_VBoxVFS_SolAddrMap.MapAddr.pfnSol_map_addr_old = (void *)map_addr;
149#else
150 g_VBoxVFS_SolAddrMap.ChooseAddr.pfnSol_choose_addr_old = (void *)choose_addr;
151#endif
152 }
153
154 RTR0DbgKrnlInfoRelease(hKrnlDbgInfo);
155 }
156 else
157 {
158 cmn_err(CE_NOTE, "RTR0DbgKrnlInfoOpen failed. rc=%d\n", rc);
159 return rc;
160 }
161
162 return (mod_install(&modlinkage));
163}
164
165int
166_info(struct modinfo *modinfop)
167{
168 return (mod_info(&modlinkage, modinfop));
169}
170
171
172int
173_fini()
174{
175 int error;
176
177 error = mod_remove(&modlinkage);
178 if (error)
179 return (error);
180
181 /*
182 * Tear down the operations vectors
183 */
184 sffs_vnode_fini();
185 (void) vfs_freevfsops_by_type(sffs_fstype);
186
187 /*
188 * close connection to the provider
189 */
190 sfprov_disconnect(sfprov);
191 return (0);
192}
193
194
195static int
196sffs_init(int fstype, char *name)
197{
198#if defined(VBOX_VFS_SOLARIS_10U6)
199 static const fs_operation_def_t sffs_vfsops_template[] = {
200 VFSNAME_MOUNT, sffs_mount,
201 VFSNAME_UNMOUNT, sffs_unmount,
202 VFSNAME_ROOT, sffs_root,
203 VFSNAME_STATVFS, sffs_statvfs,
204 NULL, NULL
205 };
206#else
207 static const fs_operation_def_t sffs_vfsops_template[] = {
208 VFSNAME_MOUNT, { .vfs_mount = sffs_mount },
209 VFSNAME_UNMOUNT, { .vfs_unmount = sffs_unmount },
210 VFSNAME_ROOT, { .vfs_root = sffs_root },
211 VFSNAME_STATVFS, { .vfs_statvfs = sffs_statvfs },
212 NULL, NULL
213 };
214#endif
215 int error;
216
217 ASSERT(fstype != 0);
218 sffs_fstype = fstype;
219 LogFlowFunc(("sffs_init() name=%s\n", name));
220
221 /*
222 * This may seem a silly way to do things for now. But the code
223 * is structured to easily allow it to be used on other hypervisors
224 * which would have a different implementation of the provider.
225 * Hopefully that'll never happen. :)
226 */
227 sfprov = sfprov_connect(SFPROV_VERSION);
228 if (sfprov == NULL) {
229 cmn_err(CE_WARN, "sffs_init: couldn't init sffs provider");
230 return (ENODEV);
231 }
232
233 error = sfprov_set_show_symlinks();
234 if (error != 0) {
235 cmn_err(CE_WARN, "sffs_init: host unable to show symlinks, "
236 "rc=%d\n", error);
237 }
238
239 error = vfs_setfsops(fstype, sffs_vfsops_template, NULL);
240 if (error != 0) {
241 cmn_err(CE_WARN, "sffs_init: bad vfs ops template");
242 return (error);
243 }
244
245 error = sffs_vnode_init();
246 if (error != 0) {
247 (void) vfs_freevfsops_by_type(fstype);
248 cmn_err(CE_WARN, "sffs_init: bad vnode ops template");
249 return (error);
250 }
251
252 if ((sffs_major = getudev()) == (major_t)-1) {
253 cmn_err(CE_WARN, "sffs_init: Can't get unique device number.");
254 sffs_major = 0;
255 }
256 mutex_init(&sffs_minor_lock, NULL, MUTEX_DEFAULT, NULL);
257 return (0);
258}
259
260/*
261 * wrapper for pn_get
262 */
263static int
264sf_pn_get(char *rawpath, struct mounta *uap, char **outpath)
265{
266 pathname_t path;
267 int error;
268
269 error = pn_get(rawpath, (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE :
270 UIO_USERSPACE, &path);
271 if (error) {
272 LogFlowFunc(("pn_get(%s) failed\n", rawpath));
273 return (error);
274 }
275 *outpath = kmem_alloc(path.pn_pathlen + 1, KM_SLEEP);
276 strcpy(*outpath, path.pn_path);
277 pn_free(&path);
278 return (0);
279}
280
281#ifdef DEBUG_ramshankar
282static void
283sffs_print(sffs_data_t *sffs)
284{
285 cmn_err(CE_NOTE, "sffs_data_t at 0x%p\n", sffs);
286 cmn_err(CE_NOTE, " vfs_t *sf_vfsp = 0x%p\n", sffs->sf_vfsp);
287 cmn_err(CE_NOTE, " vnode_t *sf_rootnode = 0x%p\n", sffs->sf_rootnode);
288 cmn_err(CE_NOTE, " uid_t sf_uid = 0x%lu\n", (ulong_t)sffs->sf_handle->sf_uid);
289 cmn_err(CE_NOTE, " gid_t sf_gid = 0x%lu\n", (ulong_t)sffs->sf_handle->sf_gid);
290 cmn_err(CE_NOTE, " mode_t sf_dmode = 0x%lu\n", (ulong_t)sffs->sf_handle->sf_dmode);
291 cmn_err(CE_NOTE, " mode_t sf_fmode = 0x%lu\n", (ulong_t)sffs->sf_handle->sf_fmode);
292 cmn_err(CE_NOTE, " mode_t sf_dmask = 0x%lu\n", (ulong_t)sffs->sf_handle->sf_dmask);
293 cmn_err(CE_NOTE, " mode_t sf_fmask = 0x%lu\n", (ulong_t)sffs->sf_handle->sf_fmask);
294 cmn_err(CE_NOTE, " char *sf_share_name = %s\n", sffs->sf_share_name);
295 cmn_err(CE_NOTE, " char *sf_mntpath = %s\n", sffs->sf_mntpath);
296 cmn_err(CE_NOTE, " sfp_mount_t *sf_handle = 0x%p\n", sffs->sf_handle);
297}
298#endif
299
300static int
301sffs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
302{
303 sffs_data_t *sffs;
304 char *mount_point = NULL;
305 char *share_name = NULL;
306 int error;
307 dev_t dev;
308 uid_t uid = 0;
309 gid_t gid = 0;
310 mode_t dmode = ~0U;
311 mode_t fmode = ~0U;
312 mode_t dmask = 0;
313 mode_t fmask = 0;
314 int stat_ttl = DEF_STAT_TTL_MS;
315 int fsync = 0;
316 char *optval;
317 long val;
318 char *path;
319 sfp_mount_t *handle;
320 sfnode_t *sfnode;
321
322 /*
323 * check we have permission to do the mount
324 */
325 LogFlowFunc(("sffs_mount() started\n"));
326 error = secpolicy_fs_mount(cr, mvp, vfsp);
327 if (error != 0)
328 return (error);
329
330 /*
331 * Mount point must be a directory
332 */
333 if (mvp->v_type != VDIR)
334 return (ENOTDIR);
335
336 /*
337 * no support for remount (what is it?)
338 */
339 if (uap->flags & MS_REMOUNT)
340 return (ENOTSUP);
341
342 /*
343 * Ensure that nothing else is actively in/under the mount point
344 */
345 mutex_enter(&mvp->v_lock);
346 if ((uap->flags & MS_OVERLAY) == 0 &&
347 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
348 mutex_exit(&mvp->v_lock);
349 return (EBUSY);
350 }
351 mutex_exit(&mvp->v_lock);
352
353 /*
354 * check for read only has to be done early
355 */
356 if (uap->flags & MS_RDONLY) {
357 vfsp->vfs_flag |= VFS_RDONLY;
358 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
359 }
360
361 /*
362 * UID to use for all files
363 */
364 if (vfs_optionisset(vfsp, "uid", &optval) &&
365 ddi_strtol(optval, NULL, 10, &val) == 0 &&
366 (uid_t)val == val)
367 uid = val;
368
369 /*
370 * GID to use for all files
371 */
372 if (vfs_optionisset(vfsp, "gid", &optval) &&
373 ddi_strtol(optval, NULL, 10, &val) == 0 &&
374 (gid_t)val == val)
375 gid = val;
376
377 /*
378 * dmode to use for all directories
379 */
380 if (vfs_optionisset(vfsp, "dmode", &optval) &&
381 ddi_strtol(optval, NULL, 8, &val) == 0 &&
382 (mode_t)val == val)
383 dmode = val;
384
385 /*
386 * fmode to use for all files
387 */
388 if (vfs_optionisset(vfsp, "fmode", &optval) &&
389 ddi_strtol(optval, NULL, 8, &val) == 0 &&
390 (mode_t)val == val)
391 fmode = val;
392
393 /*
394 * dmask to use for all directories
395 */
396 if (vfs_optionisset(vfsp, "dmask", &optval) &&
397 ddi_strtol(optval, NULL, 8, &val) == 0 &&
398 (mode_t)val == val)
399 dmask = val;
400
401 /*
402 * fmask to use for all files
403 */
404 if (vfs_optionisset(vfsp, "fmask", &optval) &&
405 ddi_strtol(optval, NULL, 8, &val) == 0 &&
406 (mode_t)val == val)
407 fmask = val;
408
409 /*
410 * umask to use for all directories & files
411 */
412 if (vfs_optionisset(vfsp, "umask", &optval) &&
413 ddi_strtol(optval, NULL, 8, &val) == 0 &&
414 (mode_t)val == val)
415 dmask = fmask = val;
416
417 /*
418 * ttl to use for stat caches
419 */
420 if (vfs_optionisset(vfsp, "stat_ttl", &optval) &&
421 ddi_strtol(optval, NULL, 10, &val) == 0 &&
422 (int)val == val)
423 {
424 stat_ttl = val;
425 }
426 else
427 vfs_setmntopt(vfsp, "stat_ttl", VBOXSOLQUOTE(DEF_STAT_TTL_MS), 0);
428
429 /*
430 * whether to honor fsync
431 */
432 if (vfs_optionisset(vfsp, "fsync", &optval))
433 fsync = 1;
434
435 /*
436 * Any unknown options are an error
437 */
438 if ((uap->flags & MS_DATA) && uap->datalen > 0) {
439 cmn_err(CE_WARN, "sffs: unknown mount options specified");
440 return (EINVAL);
441 }
442
443 /*
444 * get the mount point pathname
445 */
446 error = sf_pn_get(uap->dir, uap, &mount_point);
447 if (error)
448 return (error);
449
450 /*
451 * find what we are mounting
452 */
453 error = sf_pn_get(uap->spec, uap, &share_name);
454 if (error) {
455 kmem_free(mount_point, strlen(mount_point) + 1);
456 return (error);
457 }
458
459 /*
460 * Invoke Hypervisor mount interface before proceeding
461 */
462 error = sfprov_mount(sfprov, share_name, &handle);
463 if (error) {
464 kmem_free(share_name, strlen(share_name) + 1);
465 kmem_free(mount_point, strlen(mount_point) + 1);
466 return (error);
467 }
468
469 /*
470 * find an available minor device number for this mount
471 */
472 mutex_enter(&sffs_minor_lock);
473 do {
474 sffs_minor = (sffs_minor + 1) & L_MAXMIN32;
475 dev = makedevice(sffs_major, sffs_minor);
476 } while (vfs_devismounted(dev));
477 mutex_exit(&sffs_minor_lock);
478
479 /*
480 * allocate and fill in the sffs structure
481 */
482 sffs = kmem_alloc(sizeof (*sffs), KM_SLEEP);
483 sffs->sf_vfsp = vfsp;
484 sffs->sf_handle = handle;
485 sffs->sf_handle->sf_uid = uid;
486 sffs->sf_handle->sf_gid = gid;
487 sffs->sf_handle->sf_dmode = dmode;
488 sffs->sf_handle->sf_fmode = fmode;
489 sffs->sf_handle->sf_dmask = dmask;
490 sffs->sf_handle->sf_fmask = fmask;
491 sffs->sf_stat_ttl = stat_ttl;
492 sffs->sf_fsync = fsync;
493 sffs->sf_share_name = share_name;
494 sffs->sf_mntpath = mount_point;
495 sffs->sf_ino = 3; /* root mount point is always '3' */
496
497 /*
498 * fill in the vfs structure
499 */
500 vfsp->vfs_data = (caddr_t)sffs;
501 vfsp->vfs_fstype = sffs_fstype;
502 vfsp->vfs_dev = dev;
503 vfsp->vfs_bsize = PAGESIZE; /* HERE JOE ??? */
504 vfsp->vfs_flag |= VFS_NOTRUNC; /* HERE JOE ???? */
505 vfs_make_fsid(&vfsp->vfs_fsid, dev, sffs_fstype);
506
507 /*
508 * create the root vnode.
509 * XXX JOE What should the path be here? is "/" really right?
510 * other options?
511 */
512 path = kmem_alloc(2, KM_SLEEP);
513 strcpy(path, ".");
514 mutex_enter(&sffs_lock);
515 sfnode = sfnode_make(sffs, path, VDIR, NULL, NULL, NULL, 0);
516 sffs->sf_rootnode = sfnode_get_vnode(sfnode);
517 sffs->sf_rootnode->v_flag |= VROOT;
518 sffs->sf_rootnode->v_vfsp = vfsp;
519 mutex_exit(&sffs_lock);
520
521 LogFlowFunc(("sffs_mount() success sffs=0x%p\n", sffs));
522#ifdef DEBUG_ramshankar
523 sffs_print(sffs);
524#endif
525 return (error);
526}
527
528static int
529sffs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
530{
531 sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
532 int error;
533
534 /*
535 * generic security check
536 */
537 LogFlowFunc(("sffs_unmount() of sffs=0x%p\n", sffs));
538 if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
539 return (error);
540
541 /*
542 * forced unmount is not supported by this file system
543 * and thus, ENOTSUP, is being returned.
544 */
545 if (flag & MS_FORCE) {
546 LogFlowFunc(("sffs_unmount(MS_FORCE) returns ENOSUP\n"));
547 return (ENOTSUP);
548 }
549
550 /*
551 * Mark the file system unmounted.
552 */
553 vfsp->vfs_flag |= VFS_UNMOUNTED;
554
555 /*
556 * Make sure nothing is still in use.
557 */
558 if (sffs_purge(sffs) != 0) {
559 vfsp->vfs_flag &= ~VFS_UNMOUNTED;
560 LogFlowFunc(("sffs_unmount() returns EBUSY\n"));
561 return (EBUSY);
562 }
563
564 /*
565 * Invoke Hypervisor unmount interface before proceeding
566 */
567 error = sfprov_unmount(sffs->sf_handle);
568 if (error != 0) {
569 /* TBD anything here? */
570 }
571
572 kmem_free(sffs->sf_share_name, strlen(sffs->sf_share_name) + 1);
573 kmem_free(sffs->sf_mntpath, strlen(sffs->sf_mntpath) + 1);
574 kmem_free(sffs, sizeof(*sffs));
575 LogFlowFunc(("sffs_unmount() done\n"));
576 return (0);
577}
578
579/*
580 * return the vnode for the root of the mounted file system
581 */
582static int
583sffs_root(vfs_t *vfsp, vnode_t **vpp)
584{
585 sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
586 vnode_t *vp = sffs->sf_rootnode;
587
588 VN_HOLD(vp);
589 *vpp = vp;
590 return (0);
591}
592
593/*
594 * get some stats.. fake up the rest
595 */
596static int
597sffs_statvfs(vfs_t *vfsp, statvfs64_t *sbp)
598{
599 sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
600 sffs_fsinfo_t fsinfo;
601 dev32_t d32;
602 int error;
603
604 bzero(sbp, sizeof(*sbp));
605 error = sfprov_get_fsinfo(sffs->sf_handle, &fsinfo);
606 if (error != 0)
607 return (error);
608
609 sbp->f_bsize = fsinfo.blksize;
610 sbp->f_frsize = fsinfo.blksize;
611
612 sbp->f_bfree = fsinfo.blksavail;
613 sbp->f_bavail = fsinfo.blksavail;
614 sbp->f_files = fsinfo.blksavail / 4; /* some kind of reasonable value */
615 sbp->f_ffree = fsinfo.blksavail / 4;
616 sbp->f_favail = fsinfo.blksavail / 4;
617
618 sbp->f_blocks = fsinfo.blksused + sbp->f_bavail;
619
620 (void) cmpldev(&d32, vfsp->vfs_dev);
621 sbp->f_fsid = d32;
622 strcpy(&sbp->f_basetype[0], "sffs");
623 sbp->f_flag |= ST_NOSUID;
624
625 if (fsinfo.readonly)
626 sbp->f_flag |= ST_RDONLY;
627
628 sbp->f_namemax = fsinfo.maxnamesize;
629 return (0);
630}
631
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