VirtualBox

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

Last change on this file since 29074 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.2 KB
Line 
1/** @file
2 * VirtualBox File System for Solaris Guests, VFS implementation.
3 */
4
5/*
6 * Copyright (C) 2009 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include <VBox/log.h>
18#include <VBox/version.h>
19
20#include <sys/types.h>
21#include <sys/mntent.h>
22#include <sys/param.h>
23#include <sys/modctl.h>
24#include <sys/mount.h>
25#include <sys/policy.h>
26#include <sys/atomic.h>
27#include <sys/sysmacros.h>
28#include <sys/ddi.h>
29#include <sys/sunddi.h>
30#include <sys/vfs.h>
31#if !defined(VBOX_VFS_SOLARIS_10U6)
32#include <sys/vfs_opreg.h>
33#endif
34#include <sys/pathname.h>
35#include "vboxfs_prov.h"
36#include "vboxfs_vnode.h"
37#include "vboxfs_vfs.h"
38
39#ifdef u
40#undef u
41#endif
42
43#define VBOXSOLQUOTE2(x) #x
44#define VBOXSOLQUOTE(x) VBOXSOLQUOTE2(x)
45/** The module name. */
46#define DEVICE_NAME "vboxfs"
47/** The module description as seen in 'modinfo'. */
48#define DEVICE_DESC "VirtualBox ShrdFS"
49
50
51/*
52 * Shared Folders filesystem implementation of the Solaris VFS interfaces.
53 * Much of this is cookie cutter code for Solaris filesystem implementation.
54 */
55
56/* forward declarations */
57static int sffs_init(int fstype, char *name);
58static int sffs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
59static int sffs_unmount(vfs_t *vfsp, int flag, cred_t *cr);
60static int sffs_root(vfs_t *vfsp, vnode_t **vpp);
61static int sffs_statvfs(vfs_t *vfsp, statvfs64_t *sbp);
62
63static mntopt_t sffs_options[] = {
64 /* Option Cancels Opt Arg Flags Data */
65 {"uid", NULL, NULL, MO_HASVALUE, NULL},
66 {"gid", NULL, NULL, MO_HASVALUE, NULL}
67};
68
69static mntopts_t sffs_options_table = {
70 sizeof (sffs_options) / sizeof (mntopt_t),
71 sffs_options
72};
73
74static vfsdef_t sffs_vfsdef = {
75 VFSDEF_VERSION,
76 DEVICE_NAME,
77 sffs_init,
78 VSW_HASPROTO,
79 &sffs_options_table
80};
81
82static int sffs_fstype;
83static int sffs_major; /* major number for device */
84
85kmutex_t sffs_minor_lock;
86int sffs_minor; /* minor number for device */
87
88/*
89 * Module linkage information
90 */
91static struct modlfs modlfs = {
92 &mod_fsops,
93 DEVICE_DESC " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
94 &sffs_vfsdef
95};
96
97static struct modlinkage modlinkage = {
98 MODREV_1, &modlfs, NULL
99};
100
101static sfp_connection_t *sfprov = NULL;
102
103int
104_init()
105{
106 return (mod_install(&modlinkage));
107}
108
109int
110_info(struct modinfo *modinfop)
111{
112 return (mod_info(&modlinkage, modinfop));
113}
114
115
116int
117_fini()
118{
119 int error;
120
121 error = mod_remove(&modlinkage);
122 if (error)
123 return (error);
124
125 /*
126 * Tear down the operations vectors
127 */
128 sffs_vnode_fini();
129 (void) vfs_freevfsops_by_type(sffs_fstype);
130
131 /*
132 * close connection to the provider
133 */
134 sfprov_disconnect(sfprov);
135 return (0);
136}
137
138
139static int
140sffs_init(int fstype, char *name)
141{
142#if defined(VBOX_VFS_SOLARIS_10U6)
143 static const fs_operation_def_t sffs_vfsops_template[] = {
144 VFSNAME_MOUNT, sffs_mount,
145 VFSNAME_UNMOUNT, sffs_unmount,
146 VFSNAME_ROOT, sffs_root,
147 VFSNAME_STATVFS, sffs_statvfs,
148 NULL, NULL
149 };
150#else
151 static const fs_operation_def_t sffs_vfsops_template[] = {
152 VFSNAME_MOUNT, { .vfs_mount = sffs_mount },
153 VFSNAME_UNMOUNT, { .vfs_unmount = sffs_unmount },
154 VFSNAME_ROOT, { .vfs_root = sffs_root },
155 VFSNAME_STATVFS, { .vfs_statvfs = sffs_statvfs },
156 NULL, NULL
157 };
158#endif
159 int error;
160
161 ASSERT(fstype != 0);
162 sffs_fstype = fstype;
163 LogFlowFunc(("sffs_init() name=%s\n", name));
164
165 /*
166 * This may seem a silly way to do things for now. But the code
167 * is structured to easily allow it to be used on other hypervisors
168 * which would have a different implementation of the provider.
169 * Hopefully that'll never happen. :)
170 */
171 sfprov = sfprov_connect(SFPROV_VERSION);
172 if (sfprov == NULL) {
173 cmn_err(CE_WARN, "sffs_init(): couldn't init sffs provider");
174 return (ENODEV);
175 }
176
177 error = vfs_setfsops(fstype, sffs_vfsops_template, NULL);
178 if (error != 0) {
179 cmn_err(CE_WARN, "sffs_init: bad vfs ops template");
180 return (error);
181 }
182
183 error = sffs_vnode_init();
184 if (error != 0) {
185 (void) vfs_freevfsops_by_type(fstype);
186 cmn_err(CE_WARN, "sffs_init: bad vnode ops template");
187 return (error);
188 }
189
190 if ((sffs_major = getudev()) == (major_t)-1) {
191 cmn_err(CE_WARN, "sffs_init: Can't get unique device number.");
192 sffs_major = 0;
193 }
194 mutex_init(&sffs_minor_lock, NULL, MUTEX_DEFAULT, NULL);
195 return (0);
196}
197
198/*
199 * wrapper for pn_get
200 */
201static int
202sf_pn_get(char *rawpath, struct mounta *uap, char **outpath)
203{
204 pathname_t path;
205 int error;
206
207 error = pn_get(rawpath, (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE :
208 UIO_USERSPACE, &path);
209 if (error) {
210 LogFlowFunc(("pn_get(%s) failed\n", rawpath));
211 return (error);
212 }
213 *outpath = kmem_alloc(path.pn_pathlen + 1, KM_SLEEP);
214 strcpy(*outpath, path.pn_path);
215 pn_free(&path);
216 return (0);
217}
218
219static int
220sffs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
221{
222 sffs_data_t *sffs;
223 char *mount_point = NULL;
224 char *share_name = NULL;
225 int error;
226 dev_t dev;
227 uid_t uid = 0;
228 gid_t gid = 0;
229 char *optval;
230 long val;
231 char *path;
232 sfp_mount_t *handle;
233 sfnode_t *sfnode;
234
235 /*
236 * check we have permission to do the mount
237 */
238 LogFlowFunc(("sffs_mount() started\n"));
239 error = secpolicy_fs_mount(cr, mvp, vfsp);
240 if (error != 0)
241 return (error);
242
243 /*
244 * Mount point must be a directory
245 */
246 if (mvp->v_type != VDIR)
247 return (ENOTDIR);
248
249 /*
250 * no support for remount (what is it?)
251 */
252 if (uap->flags & MS_REMOUNT)
253 return (ENOTSUP);
254
255 /*
256 * Ensure that nothing else is actively in/under the mount point
257 */
258 mutex_enter(&mvp->v_lock);
259 if ((uap->flags & MS_OVERLAY) == 0 &&
260 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
261 mutex_exit(&mvp->v_lock);
262 return (EBUSY);
263 }
264 mutex_exit(&mvp->v_lock);
265
266 /*
267 * check for read only has to be done early
268 */
269 if (uap->flags & MS_RDONLY) {
270 vfsp->vfs_flag |= VFS_RDONLY;
271 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
272 }
273
274 /*
275 * UID to use for all files
276 */
277 if (vfs_optionisset(vfsp, "uid", &optval) &&
278 ddi_strtol(optval, NULL, 10, &val) == 0 &&
279 (uid_t)val == val)
280 uid = val;
281
282 /*
283 * GID to use for all files
284 */
285 if (vfs_optionisset(vfsp, "gid", &optval) &&
286 ddi_strtol(optval, NULL, 10, &val) == 0 &&
287 (gid_t)val == val)
288 gid = val;
289
290 /*
291 * Any unknown options are an error
292 */
293 if ((uap->flags & MS_DATA) && uap->datalen > 0) {
294 cmn_err(CE_WARN, "sffs: unknown mount options specified");
295 return (EINVAL);
296 }
297
298 /*
299 * get the mount point pathname
300 */
301 error = sf_pn_get(uap->dir, uap, &mount_point);
302 if (error)
303 return (error);
304
305 /*
306 * find what we are mounting
307 */
308 error = sf_pn_get(uap->spec, uap, &share_name);
309 if (error) {
310 kmem_free(mount_point, strlen(mount_point) + 1);
311 return (error);
312 }
313
314 /*
315 * Invoke Hypervisor mount interface before proceeding
316 */
317 error = sfprov_mount(sfprov, share_name, &handle);
318 if (error) {
319 kmem_free(share_name, strlen(share_name) + 1);
320 kmem_free(mount_point, strlen(mount_point) + 1);
321 return (error);
322 }
323
324 /*
325 * find an available minor device number for this mount
326 */
327 mutex_enter(&sffs_minor_lock);
328 do {
329 sffs_minor = (sffs_minor + 1) & L_MAXMIN32;
330 dev = makedevice(sffs_major, sffs_minor);
331 } while (vfs_devismounted(dev));
332 mutex_exit(&sffs_minor_lock);
333
334 /*
335 * allocate and fill in the sffs structure
336 */
337 sffs = kmem_alloc(sizeof (*sffs), KM_SLEEP);
338 sffs->sf_vfsp = vfsp;
339 sffs->sf_uid = uid;
340 sffs->sf_gid = gid;
341 sffs->sf_share_name = share_name;
342 sffs->sf_mntpath = mount_point;
343 sffs->sf_handle = handle;
344 sffs->sf_ino = 3; /* root mount point is always '3' */
345
346 /*
347 * fill in the vfs structure
348 */
349 vfsp->vfs_data = (caddr_t)sffs;
350 vfsp->vfs_fstype = sffs_fstype;
351 vfsp->vfs_dev = dev;
352 vfsp->vfs_bsize = PAGESIZE; /* HERE JOE ??? */
353 vfsp->vfs_flag |= VFS_NOTRUNC; /* HERE JOE ???? */
354 vfs_make_fsid(&vfsp->vfs_fsid, dev, sffs_fstype);
355
356 /*
357 * create the root vnode.
358 * XXX JOE What should the path be here? is "/" really right?
359 * other options?
360 */
361 path = kmem_alloc(2, KM_SLEEP);
362 strcpy(path, ".");
363 mutex_enter(&sffs_lock);
364 sfnode = sfnode_make(sffs, path, VDIR, NULL, NULL);
365 sffs->sf_rootnode = sfnode_get_vnode(sfnode);
366 sffs->sf_rootnode->v_flag |= VROOT;
367 sffs->sf_rootnode->v_vfsp = vfsp;
368 mutex_exit(&sffs_lock);
369
370 LogFlowFunc(("sffs_mount() success sffs=0x%p\n", sffs));
371 return (error);
372}
373
374static int
375sffs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
376{
377 sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
378 int error;
379
380 /*
381 * generic securty check
382 */
383 LogFlowFunc(("sffs_unmount() of sffs=0x%p\n", sffs));
384 if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
385 return (error);
386
387 /*
388 * forced unmount is not supported by this file system
389 * and thus, ENOTSUP, is being returned.
390 */
391 if (flag & MS_FORCE)
392 return (ENOTSUP);
393
394 /*
395 * Make sure nothing is still in use.
396 */
397 if (sffs_purge(sffs) != 0)
398 return (EBUSY);
399
400 /*
401 * Invoke Hypervisor unmount interface before proceeding
402 */
403 error = sfprov_unmount(sffs->sf_handle);
404 if (error != 0) {
405 /* TBD anything here? */
406 }
407
408 kmem_free(sffs->sf_share_name, strlen(sffs->sf_share_name) + 1);
409 kmem_free(sffs->sf_mntpath, strlen(sffs->sf_mntpath) + 1);
410 kmem_free(sffs, sizeof(*sffs));
411 LogFlowFunc(("sffs_unmount() done\n"));
412 return (0);
413}
414
415/*
416 * return the vnode for the root of the mounted file system
417 */
418static int
419sffs_root(vfs_t *vfsp, vnode_t **vpp)
420{
421 sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
422 vnode_t *vp = sffs->sf_rootnode;
423
424 VN_HOLD(vp);
425 *vpp = vp;
426 return (0);
427}
428
429/*
430 * get some stats.. fake up the rest
431 */
432static int
433sffs_statvfs(vfs_t *vfsp, statvfs64_t *sbp)
434{
435 sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
436 uint64_t x;
437 uint32_t u;
438 dev32_t d32;
439 int error;
440
441 bzero(sbp, sizeof(*sbp));
442 error = sfprov_get_blksize(sffs->sf_handle, &x);
443 if (error != 0)
444 return (error);
445 sbp->f_bsize = x;
446 sbp->f_frsize = x;
447
448 error = sfprov_get_blksavail(sffs->sf_handle, &x);
449 if (error != 0)
450 return (error);
451 sbp->f_bfree = x;
452 sbp->f_bavail = x;
453 sbp->f_files = x / 4; /* some kind of reasonable value */
454 sbp->f_ffree = x / 4;
455 sbp->f_favail = x / 4;
456
457 error = sfprov_get_blksused(sffs->sf_handle, &x);
458 if (error != 0)
459 return (error);
460 sbp->f_blocks = x + sbp->f_bavail;
461
462 (void) cmpldev(&d32, vfsp->vfs_dev);
463 sbp->f_fsid = d32;
464 strcpy(&sbp->f_basetype[0], "sffs");
465 sbp->f_flag |= ST_NOSUID;
466
467 error = sfprov_get_readonly(sffs->sf_handle, &u);
468 if (error != 0)
469 return (error);
470 if (u)
471 sbp->f_flag |= ST_RDONLY;
472
473 error = sfprov_get_maxnamesize(sffs->sf_handle, &u);
474 if (error != 0)
475 return (error);
476 sbp->f_namemax = u;
477 return (0);
478}
479
480static void sffs_print(sffs_data_t *sffs)
481{
482 Log(("sffs_data_t at 0x%p\n", sffs));
483 Log((" vfs_t *sf_vfsp = 0x%p\n", sffs->sf_vfsp));
484 Log((" vnode_t *sf_rootnode = 0x%p\n", sffs->sf_rootnode));
485 Log((" uid_t sf_uid = 0x%l\n", (ulong_t)sffs->sf_uid));
486 Log((" gid_t sf_gid = 0x%l\n", (ulong_t)sffs->sf_gid));
487 Log((" char *sf_share_name = %s\n", sffs->sf_share_name));
488 Log((" char *sf_mntpath = %s\n", sffs->sf_mntpath));
489 Log((" sfp_mount_t *sf_handle = 0x%p\n", sffs->sf_handle));
490}
491
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