4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/param.h>
26 #include <sys/errno.h>
28 #include <sys/vfs_opreg.h>
29 #include <sys/vnode.h>
31 #include <sys/pathname.h>
34 #include <sys/statvfs.h>
35 #include <sys/fs/lofs_info.h>
36 #include <sys/fs/lofs_node.h>
37 #include <sys/mount.h>
38 #include <sys/mntent.h>
39 #include <sys/mkdev.h>
41 #include <sys/sysmacros.h>
42 #include <sys/systm.h>
43 #include <sys/cmn_err.h>
44 #include <sys/policy.h>
45 #include "sys/fs_subr.h"
48 * This is the loadable module wrapper.
50 #include <sys/modctl.h>
52 static mntopts_t lofs_mntopts
;
54 static int lofsinit(int, char *);
56 static vfsdef_t vfw
= {
60 VSW_HASPROTO
|VSW_STATS
|VSW_ZMOUNT
,
65 * LOFS mount options table
67 static char *xattr_cancel
[] = { MNTOPT_NOXATTR
, NULL
};
68 static char *noxattr_cancel
[] = { MNTOPT_XATTR
, NULL
};
69 static char *sub_cancel
[] = { MNTOPT_LOFS_NOSUB
, NULL
};
70 static char *nosub_cancel
[] = { MNTOPT_LOFS_SUB
, NULL
};
72 static mntopt_t mntopts
[] = {
74 * option name cancel option default arg flags
77 { MNTOPT_XATTR
, xattr_cancel
, NULL
, 0,
79 { MNTOPT_NOXATTR
, noxattr_cancel
, NULL
, 0,
81 { MNTOPT_LOFS_SUB
, sub_cancel
, NULL
, 0,
83 { MNTOPT_LOFS_NOSUB
, nosub_cancel
, NULL
, 0,
87 static mntopts_t lofs_mntopts
= {
88 sizeof (mntopts
) / sizeof (mntopt_t
),
93 * Module linkage information for the kernel.
96 static struct modlfs modlfs
= {
97 &mod_fsops
, "filesystem for lofs", &vfw
100 static struct modlinkage modlinkage
= {
101 MODREV_1
, (void *)&modlfs
, NULL
105 * This is the module initialization routine.
114 status
= mod_install(&modlinkage
);
117 * Cleanup previously initialized work.
126 * Don't allow the lofs module to be unloaded for now.
127 * There is a memory leak if it gets unloaded.
137 _info(struct modinfo
*modinfop
)
139 return (mod_info(&modlinkage
, modinfop
));
143 static int lofsfstype
;
148 * Set up mount info record and attach it to vfs struct.
152 lo_mount(struct vfs
*vfsp
,
158 struct vnode
*srootvp
= NULL
; /* the server's root */
159 struct vnode
*realrootvp
;
163 nodev
= vfs_optionisset(vfsp
, MNTOPT_NODEVICES
, NULL
);
165 if ((error
= secpolicy_fs_mount(cr
, vp
, vfsp
)) != 0)
169 * Loopback devices which get "nodevices" added can be done without
170 * "nodevices" set because we cannot import devices into a zone
171 * with loopback. Note that we have all zone privileges when
172 * this happens; if not, we'd have gotten "nosuid".
174 if (!nodev
&& vfs_optionisset(vfsp
, MNTOPT_NODEVICES
, NULL
))
175 vfs_setmntopt(vfsp
, MNTOPT_DEVICES
, NULL
, VFS_NODISPLAY
);
177 mutex_enter(&vp
->v_lock
);
178 if (!(uap
->flags
& MS_OVERLAY
) &&
179 (vp
->v_count
!= 1 || (vp
->v_flag
& VROOT
))) {
180 mutex_exit(&vp
->v_lock
);
183 mutex_exit(&vp
->v_lock
);
186 * Find real root, and make vfs point to real vfs
189 if (error
= lookupname(uap
->spec
, (uap
->flags
& MS_SYSSPACE
) ?
190 UIO_SYSSPACE
: UIO_USERSPACE
, FOLLOW
, NULLVPP
, &realrootvp
))
194 * realrootvp may be an AUTOFS node, in which case we perform a
195 * VOP_ACCESS() to trigger the mount of the intended filesystem.
196 * This causes a loopback mount of the intended filesystem instead
197 * of the AUTOFS filesystem.
199 * If a lofs mount creates a mount loop (such that a lofs vfs is
200 * mounted on an autofs node and that lofs vfs points back to the
201 * autofs node which it is mounted on) then a VOP_ACCESS call will
202 * create a deadlock. Once this deadlock is released, VOP_ACCESS will
203 * return EINTR. In such a case we don't want the lofs vfs to be
204 * created as the loop could panic the system.
206 if ((error
= VOP_ACCESS(realrootvp
, 0, 0, cr
, NULL
)) != 0) {
212 * We're interested in the top most filesystem.
213 * This is specially important when uap->spec is a trigger
214 * AUTOFS node, since we're really interested in mounting the
215 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
216 * call not the AUTOFS node itself.
218 if (vn_mountedvfs(realrootvp
) != NULL
) {
219 if (error
= traverse(&realrootvp
)) {
226 * Allocate a vfs info struct and attach it
228 li
= kmem_zalloc(sizeof (struct loinfo
), KM_SLEEP
);
229 li
->li_realvfs
= realrootvp
->v_vfsp
;
230 li
->li_mountvfs
= vfsp
;
233 * Set mount flags to be inherited by loopback vfs's
235 if (vfs_optionisset(vfsp
, MNTOPT_RO
, NULL
)) {
236 li
->li_mflag
|= VFS_RDONLY
;
238 if (vfs_optionisset(vfsp
, MNTOPT_NOSUID
, NULL
)) {
239 li
->li_mflag
|= (VFS_NOSETUID
|VFS_NODEVICES
);
241 if (vfs_optionisset(vfsp
, MNTOPT_NODEVICES
, NULL
)) {
242 li
->li_mflag
|= VFS_NODEVICES
;
244 if (vfs_optionisset(vfsp
, MNTOPT_NOSETUID
, NULL
)) {
245 li
->li_mflag
|= VFS_NOSETUID
;
248 * Permissive flags are added to the "deny" bitmap.
250 if (vfs_optionisset(vfsp
, MNTOPT_NOXATTR
, NULL
)) {
251 li
->li_dflag
|= VFS_XATTR
;
253 if (vfs_optionisset(vfsp
, MNTOPT_NONBMAND
, NULL
)) {
254 li
->li_dflag
|= VFS_NBMAND
;
258 * Propagate inheritable mount flags from the real vfs.
260 if ((li
->li_realvfs
->vfs_flag
& VFS_RDONLY
) &&
261 !vfs_optionisset(vfsp
, MNTOPT_RO
, NULL
))
262 vfs_setmntopt(vfsp
, MNTOPT_RO
, NULL
,
264 if ((li
->li_realvfs
->vfs_flag
& VFS_NOSETUID
) &&
265 !vfs_optionisset(vfsp
, MNTOPT_NOSETUID
, NULL
))
266 vfs_setmntopt(vfsp
, MNTOPT_NOSETUID
, NULL
,
268 if ((li
->li_realvfs
->vfs_flag
& VFS_NODEVICES
) &&
269 !vfs_optionisset(vfsp
, MNTOPT_NODEVICES
, NULL
))
270 vfs_setmntopt(vfsp
, MNTOPT_NODEVICES
, NULL
,
273 * Permissive flags such as VFS_XATTR, as opposed to restrictive flags
274 * such as VFS_RDONLY, are handled differently. An explicit
275 * MNTOPT_NOXATTR should override the underlying filesystem's VFS_XATTR.
277 if ((li
->li_realvfs
->vfs_flag
& VFS_XATTR
) &&
278 !vfs_optionisset(vfsp
, MNTOPT_NOXATTR
, NULL
) &&
279 !vfs_optionisset(vfsp
, MNTOPT_XATTR
, NULL
))
280 vfs_setmntopt(vfsp
, MNTOPT_XATTR
, NULL
,
282 if ((li
->li_realvfs
->vfs_flag
& VFS_NBMAND
) &&
283 !vfs_optionisset(vfsp
, MNTOPT_NBMAND
, NULL
) &&
284 !vfs_optionisset(vfsp
, MNTOPT_NONBMAND
, NULL
))
285 vfs_setmntopt(vfsp
, MNTOPT_NBMAND
, NULL
,
289 vfsp
->vfs_data
= (caddr_t
)li
;
290 vfsp
->vfs_bcount
= 0;
291 vfsp
->vfs_fstype
= lofsfstype
;
292 vfsp
->vfs_bsize
= li
->li_realvfs
->vfs_bsize
;
294 vfsp
->vfs_dev
= li
->li_realvfs
->vfs_dev
;
295 vfsp
->vfs_fsid
.val
[0] = li
->li_realvfs
->vfs_fsid
.val
[0];
296 vfsp
->vfs_fsid
.val
[1] = li
->li_realvfs
->vfs_fsid
.val
[1];
298 if (vfs_optionisset(vfsp
, MNTOPT_LOFS_NOSUB
, NULL
)) {
299 li
->li_flag
|= LO_NOSUB
;
303 * Propagate any VFS features
306 vfs_propagate_features(li
->li_realvfs
, vfsp
);
309 * Setup the hashtable. If the root of this mount isn't a directory,
310 * there's no point in allocating a large hashtable. A table with one
311 * bucket is sufficient.
313 if (realrootvp
->v_type
!= VDIR
)
319 * Make the root vnode
321 srootvp
= makelonode(realrootvp
, li
, 0);
322 srootvp
->v_flag
|= VROOT
;
323 li
->li_rootvp
= srootvp
;
326 lo_dprint(4, "lo_mount: vfs %p realvfs %p root %p realroot %p li %p\n",
327 vfsp
, li
->li_realvfs
, srootvp
, realrootvp
, li
);
333 * Undo loopback mount
336 lo_unmount(struct vfs
*vfsp
, int flag
, struct cred
*cr
)
340 if (secpolicy_fs_unmount(cr
, vfsp
) != 0)
344 * Forced unmount is not supported by this file system
345 * and thus, ENOTSUP, is being returned.
352 lo_dprint(4, "lo_unmount(%p) li %p\n", vfsp
, li
);
354 if (li
->li_refct
!= 1 || li
->li_rootvp
->v_count
!= 1) {
356 lo_dprint(4, "refct %d v_ct %d\n", li
->li_refct
,
357 li
->li_rootvp
->v_count
);
361 VN_RELE(li
->li_rootvp
);
366 * Find root of lofs mount.
369 lo_root(struct vfs
*vfsp
, struct vnode
**vpp
)
371 *vpp
= vtoli(vfsp
)->li_rootvp
;
373 lo_dprint(4, "lo_root(0x%p) = %p\n", vfsp
, *vpp
);
376 * If the root of the filesystem is a special file, return the specvp
377 * version of the vnode. We don't save the specvp vnode in our
378 * hashtable since that's exclusively for lnodes.
380 if (IS_DEVVP(*vpp
)) {
383 svp
= specvp(*vpp
, (*vpp
)->v_rdev
, (*vpp
)->v_type
, kcred
);
395 * Get file system statistics.
398 lo_statvfs(register struct vfs
*vfsp
, struct statvfs64
*sbp
)
403 lo_dprint(4, "lostatvfs %p\n", vfsp
);
406 * Using realrootvp->v_vfsp (instead of the realvfsp that was
407 * cached) is necessary to make lofs work woth forced UFS unmounts.
408 * In the case of a forced unmount, UFS stores a set of dummy vfsops
409 * in all the (i)vnodes in the filesystem. The dummy ops simply
412 (void) lo_realvfs(vfsp
, &realrootvp
);
413 if (realrootvp
!= NULL
)
414 return (VFS_STATVFS(realrootvp
->v_vfsp
, sbp
));
420 * LOFS doesn't have any data or metadata to flush, pending I/O on the
421 * underlying filesystem will be flushed when such filesystem is synched.
425 lo_sync(struct vfs
*vfsp
,
430 lo_dprint(4, "lo_sync: %p\n", vfsp
);
436 * Obtain the vnode from the underlying filesystem.
439 lo_vget(struct vfs
*vfsp
, struct vnode
**vpp
, struct fid
*fidp
)
444 lo_dprint(4, "lo_vget: %p\n", vfsp
);
446 (void) lo_realvfs(vfsp
, &realrootvp
);
447 if (realrootvp
!= NULL
)
448 return (VFS_VGET(realrootvp
->v_vfsp
, vpp
, fidp
));
454 * Free mount-specific data.
457 lo_freevfs(struct vfs
*vfsp
)
459 struct loinfo
*li
= vtoli(vfsp
);
462 kmem_free(li
, sizeof (struct loinfo
));
466 lofsinit(int fstyp
, char *name
)
468 static const fs_operation_def_t lo_vfsops_template
[] = {
469 VFSNAME_MOUNT
, { .vfs_mount
= lo_mount
},
470 VFSNAME_UNMOUNT
, { .vfs_unmount
= lo_unmount
},
471 VFSNAME_ROOT
, { .vfs_root
= lo_root
},
472 VFSNAME_STATVFS
, { .vfs_statvfs
= lo_statvfs
},
473 VFSNAME_SYNC
, { .vfs_sync
= lo_sync
},
474 VFSNAME_VGET
, { .vfs_vget
= lo_vget
},
475 VFSNAME_FREEVFS
, { .vfs_freevfs
= lo_freevfs
},
480 error
= vfs_setfsops(fstyp
, lo_vfsops_template
, &lo_vfsops
);
482 cmn_err(CE_WARN
, "lofsinit: bad vfs ops template");
486 error
= vn_make_ops(name
, lo_vnodeops_template
, &lo_vnodeops
);
488 (void) vfs_freevfsops_by_type(fstyp
);
489 cmn_err(CE_WARN
, "lofsinit: bad vnode ops template");