1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/errno.h> 31*0Sstevel@tonic-gate #include <sys/vfs.h> 32*0Sstevel@tonic-gate #include <sys/vnode.h> 33*0Sstevel@tonic-gate #include <sys/uio.h> 34*0Sstevel@tonic-gate #include <sys/pathname.h> 35*0Sstevel@tonic-gate #include <sys/kmem.h> 36*0Sstevel@tonic-gate #include <sys/cred.h> 37*0Sstevel@tonic-gate #include <sys/statvfs.h> 38*0Sstevel@tonic-gate #include <sys/fs/lofs_info.h> 39*0Sstevel@tonic-gate #include <sys/fs/lofs_node.h> 40*0Sstevel@tonic-gate #include <sys/mount.h> 41*0Sstevel@tonic-gate #include <sys/mntent.h> 42*0Sstevel@tonic-gate #include <sys/mkdev.h> 43*0Sstevel@tonic-gate #include <sys/sysmacros.h> 44*0Sstevel@tonic-gate #include <sys/systm.h> 45*0Sstevel@tonic-gate #include <sys/cmn_err.h> 46*0Sstevel@tonic-gate #include <sys/policy.h> 47*0Sstevel@tonic-gate #include "fs/fs_subr.h" 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * This is the loadable module wrapper. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate #include <sys/modctl.h> 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static mntopts_t lofs_mntopts; 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate static int lofsinit(int, char *); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static vfsdef_t vfw = { 59*0Sstevel@tonic-gate VFSDEF_VERSION, 60*0Sstevel@tonic-gate "lofs", 61*0Sstevel@tonic-gate lofsinit, 62*0Sstevel@tonic-gate VSW_HASPROTO, 63*0Sstevel@tonic-gate &lofs_mntopts 64*0Sstevel@tonic-gate }; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* 67*0Sstevel@tonic-gate * Stuff needed to support "zonedevfs" mode. 68*0Sstevel@tonic-gate */ 69*0Sstevel@tonic-gate static major_t lofs_major; 70*0Sstevel@tonic-gate static minor_t lofs_minor; 71*0Sstevel@tonic-gate static kmutex_t lofs_minor_lock; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* 74*0Sstevel@tonic-gate * LOFS mount options table 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 77*0Sstevel@tonic-gate static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 78*0Sstevel@tonic-gate static char *zonedevfs_cancel[] = { MNTOPT_LOFS_NOZONEDEVFS, NULL }; 79*0Sstevel@tonic-gate static char *nozonedevfs_cancel[] = { MNTOPT_LOFS_ZONEDEVFS, NULL }; 80*0Sstevel@tonic-gate static char *sub_cancel[] = { MNTOPT_LOFS_NOSUB, NULL }; 81*0Sstevel@tonic-gate static char *nosub_cancel[] = { MNTOPT_LOFS_SUB, NULL }; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static mntopt_t mntopts[] = { 84*0Sstevel@tonic-gate /* 85*0Sstevel@tonic-gate * option name cancel option default arg flags 86*0Sstevel@tonic-gate * private data 87*0Sstevel@tonic-gate */ 88*0Sstevel@tonic-gate { MNTOPT_XATTR, xattr_cancel, NULL, 0, 89*0Sstevel@tonic-gate (void *)0 }, 90*0Sstevel@tonic-gate { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 91*0Sstevel@tonic-gate (void *)0 }, 92*0Sstevel@tonic-gate { MNTOPT_LOFS_ZONEDEVFS, zonedevfs_cancel, NULL, 0, 93*0Sstevel@tonic-gate (void *)0 }, 94*0Sstevel@tonic-gate { MNTOPT_LOFS_NOZONEDEVFS, nozonedevfs_cancel, NULL, 0, 95*0Sstevel@tonic-gate (void *)0 }, 96*0Sstevel@tonic-gate { MNTOPT_LOFS_SUB, sub_cancel, NULL, 0, 97*0Sstevel@tonic-gate (void *)0 }, 98*0Sstevel@tonic-gate { MNTOPT_LOFS_NOSUB, nosub_cancel, NULL, 0, 99*0Sstevel@tonic-gate (void *)0 }, 100*0Sstevel@tonic-gate }; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate static mntopts_t lofs_mntopts = { 103*0Sstevel@tonic-gate sizeof (mntopts) / sizeof (mntopt_t), 104*0Sstevel@tonic-gate mntopts 105*0Sstevel@tonic-gate }; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * Module linkage information for the kernel. 109*0Sstevel@tonic-gate */ 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate static struct modlfs modlfs = { 112*0Sstevel@tonic-gate &mod_fsops, "filesystem for lofs", &vfw 113*0Sstevel@tonic-gate }; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 116*0Sstevel@tonic-gate MODREV_1, (void *)&modlfs, NULL 117*0Sstevel@tonic-gate }; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* 120*0Sstevel@tonic-gate * This is the module initialization routine. 121*0Sstevel@tonic-gate */ 122*0Sstevel@tonic-gate int 123*0Sstevel@tonic-gate _init() 124*0Sstevel@tonic-gate { 125*0Sstevel@tonic-gate int status; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate lofs_subrinit(); 128*0Sstevel@tonic-gate status = mod_install(&modlinkage); 129*0Sstevel@tonic-gate if (status != 0) { 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * Cleanup previously initialized work. 132*0Sstevel@tonic-gate */ 133*0Sstevel@tonic-gate lofs_subrfini(); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate return (status); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * Don't allow the lofs module to be unloaded for now. 141*0Sstevel@tonic-gate * There is a memory leak if it gets unloaded. 142*0Sstevel@tonic-gate */ 143*0Sstevel@tonic-gate int 144*0Sstevel@tonic-gate _fini() 145*0Sstevel@tonic-gate { 146*0Sstevel@tonic-gate return (EBUSY); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate int 150*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 151*0Sstevel@tonic-gate { 152*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate static int lofsfstype; 157*0Sstevel@tonic-gate vfsops_t *lo_vfsops; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * lo mount vfsop 161*0Sstevel@tonic-gate * Set up mount info record and attach it to vfs struct. 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate /*ARGSUSED*/ 164*0Sstevel@tonic-gate static int 165*0Sstevel@tonic-gate lo_mount(struct vfs *vfsp, 166*0Sstevel@tonic-gate struct vnode *vp, 167*0Sstevel@tonic-gate struct mounta *uap, 168*0Sstevel@tonic-gate struct cred *cr) 169*0Sstevel@tonic-gate { 170*0Sstevel@tonic-gate int error; 171*0Sstevel@tonic-gate struct vnode *srootvp = NULL; /* the server's root */ 172*0Sstevel@tonic-gate struct vnode *realrootvp; 173*0Sstevel@tonic-gate struct loinfo *li; 174*0Sstevel@tonic-gate int is_zonedevfs = 0; 175*0Sstevel@tonic-gate int nodev; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate nodev = vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL); 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate if ((error = secpolicy_fs_mount(cr, vp, vfsp)) != 0) 180*0Sstevel@tonic-gate return (EPERM); 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /* 183*0Sstevel@tonic-gate * Loopback devices which get "nodevices" added can be done without 184*0Sstevel@tonic-gate * "nodevices" set because we cannot import devices into a zone 185*0Sstevel@tonic-gate * with loopback. Note that we have all zone privileges when 186*0Sstevel@tonic-gate * this happens; if not, we'd have gotten "nosuid". 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate if (!nodev && vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 189*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_DEVICES, NULL, VFS_NODISPLAY); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * We must ensure that only the global zone applies the 'zonedevfs' 193*0Sstevel@tonic-gate * option; we don't want non-global zones to be able to establish 194*0Sstevel@tonic-gate * lofs mounts using the special dev_t we use to ensure that the 195*0Sstevel@tonic-gate * contents of a zone's /dev cannot be victim to link(2) or rename(2). 196*0Sstevel@tonic-gate * See below, where we set all of this up. 197*0Sstevel@tonic-gate * 198*0Sstevel@tonic-gate * Since this is more like a privilege check, we use crgetzoneid(cr) 199*0Sstevel@tonic-gate * instead of getzoneid(). 200*0Sstevel@tonic-gate */ 201*0Sstevel@tonic-gate is_zonedevfs = vfs_optionisset(vfsp, MNTOPT_LOFS_ZONEDEVFS, NULL); 202*0Sstevel@tonic-gate if (crgetzoneid(cr) != GLOBAL_ZONEID && is_zonedevfs) 203*0Sstevel@tonic-gate return (EPERM); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate mutex_enter(&vp->v_lock); 206*0Sstevel@tonic-gate if (!(uap->flags & MS_OVERLAY) && 207*0Sstevel@tonic-gate (vp->v_count != 1 || (vp->v_flag & VROOT))) { 208*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 209*0Sstevel@tonic-gate return (EBUSY); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate /* 214*0Sstevel@tonic-gate * Find real root, and make vfs point to real vfs 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate if (error = lookupname(uap->spec, (uap->flags & MS_SYSSPACE) ? 217*0Sstevel@tonic-gate UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, 218*0Sstevel@tonic-gate &realrootvp)) 219*0Sstevel@tonic-gate return (error); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * realrootvp may be an AUTOFS node, in which case we 223*0Sstevel@tonic-gate * perform a VOP_ACCESS() to trigger the mount of the 224*0Sstevel@tonic-gate * intended filesystem, so we loopback mount the intended 225*0Sstevel@tonic-gate * filesystem instead of the AUTOFS filesystem. 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate (void) VOP_ACCESS(realrootvp, 0, 0, cr); 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate /* 230*0Sstevel@tonic-gate * We're interested in the top most filesystem. 231*0Sstevel@tonic-gate * This is specially important when uap->spec is a trigger 232*0Sstevel@tonic-gate * AUTOFS node, since we're really interested in mounting the 233*0Sstevel@tonic-gate * filesystem AUTOFS mounted as result of the VOP_ACCESS() 234*0Sstevel@tonic-gate * call not the AUTOFS node itself. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate if (vn_mountedvfs(realrootvp) != NULL) { 237*0Sstevel@tonic-gate if (error = traverse(&realrootvp)) { 238*0Sstevel@tonic-gate VN_RELE(realrootvp); 239*0Sstevel@tonic-gate return (error); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate /* 244*0Sstevel@tonic-gate * Allocate a vfs info struct and attach it 245*0Sstevel@tonic-gate */ 246*0Sstevel@tonic-gate li = kmem_zalloc(sizeof (struct loinfo), KM_SLEEP); 247*0Sstevel@tonic-gate li->li_realvfs = realrootvp->v_vfsp; 248*0Sstevel@tonic-gate li->li_mountvfs = vfsp; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * Set mount flags to be inherited by loopback vfs's 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) { 254*0Sstevel@tonic-gate li->li_mflag |= VFS_RDONLY; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { 257*0Sstevel@tonic-gate li->li_mflag |= (VFS_NOSETUID|VFS_NODEVICES); 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) { 260*0Sstevel@tonic-gate li->li_mflag |= VFS_NODEVICES; 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) { 263*0Sstevel@tonic-gate li->li_mflag |= VFS_NOSETUID; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * Permissive flags are added to the "deny" bitmap. 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) { 269*0Sstevel@tonic-gate li->li_dflag |= VFS_XATTR; 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) { 272*0Sstevel@tonic-gate li->li_dflag |= VFS_NBMAND; 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * Propagate inheritable mount flags from the real vfs. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_RDONLY) && 279*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_RO, NULL)) 280*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 281*0Sstevel@tonic-gate VFS_NODISPLAY); 282*0Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_NOSETUID) && 283*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) 284*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 285*0Sstevel@tonic-gate VFS_NODISPLAY); 286*0Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_NODEVICES) && 287*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 288*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 289*0Sstevel@tonic-gate VFS_NODISPLAY); 290*0Sstevel@tonic-gate /* 291*0Sstevel@tonic-gate * Permissive flags such as VFS_XATTR, as opposed to restrictive flags 292*0Sstevel@tonic-gate * such as VFS_RDONLY, are handled differently. An explicit 293*0Sstevel@tonic-gate * MNTOPT_NOXATTR should override the underlying filesystem's VFS_XATTR. 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_XATTR) && 296*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL) && 297*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) 298*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_XATTR, NULL, 299*0Sstevel@tonic-gate VFS_NODISPLAY); 300*0Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_NBMAND) && 301*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL) && 302*0Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) 303*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NBMAND, NULL, 304*0Sstevel@tonic-gate VFS_NODISPLAY); 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate li->li_refct = 0; 307*0Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)li; 308*0Sstevel@tonic-gate vfsp->vfs_bcount = 0; 309*0Sstevel@tonic-gate vfsp->vfs_fstype = lofsfstype; 310*0Sstevel@tonic-gate vfsp->vfs_bsize = li->li_realvfs->vfs_bsize; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * Test to see if we need to be in "zone /dev" mode. In zonedevfs 314*0Sstevel@tonic-gate * mode, we pull a nasty trick; we make sure that the lofs dev_t does 315*0Sstevel@tonic-gate * *not* reflect the underlying device, so that no renames or links 316*0Sstevel@tonic-gate * can occur to or from the /dev hierarchy. 317*0Sstevel@tonic-gate */ 318*0Sstevel@tonic-gate if (is_zonedevfs) { 319*0Sstevel@tonic-gate dev_t dev; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate mutex_enter(&lofs_minor_lock); 322*0Sstevel@tonic-gate do { 323*0Sstevel@tonic-gate lofs_minor = (lofs_minor + 1) & MAXMIN32; 324*0Sstevel@tonic-gate dev = makedevice(lofs_major, lofs_minor); 325*0Sstevel@tonic-gate } while (vfs_devismounted(dev)); 326*0Sstevel@tonic-gate mutex_exit(&lofs_minor_lock); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate vfsp->vfs_dev = dev; 329*0Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, dev, lofsfstype); 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate li->li_flag |= LO_ZONEDEVFS; 332*0Sstevel@tonic-gate } else { 333*0Sstevel@tonic-gate vfsp->vfs_dev = li->li_realvfs->vfs_dev; 334*0Sstevel@tonic-gate vfsp->vfs_fsid.val[0] = li->li_realvfs->vfs_fsid.val[0]; 335*0Sstevel@tonic-gate vfsp->vfs_fsid.val[1] = li->li_realvfs->vfs_fsid.val[1]; 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_LOFS_NOSUB, NULL)) { 339*0Sstevel@tonic-gate li->li_flag |= LO_NOSUB; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * Setup the hashtable. If the root of this mount isn't a directory, 344*0Sstevel@tonic-gate * there's no point in allocating a large hashtable. A table with one 345*0Sstevel@tonic-gate * bucket is sufficient. 346*0Sstevel@tonic-gate */ 347*0Sstevel@tonic-gate if (realrootvp->v_type != VDIR) 348*0Sstevel@tonic-gate lsetup(li, 1); 349*0Sstevel@tonic-gate else 350*0Sstevel@tonic-gate lsetup(li, 0); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate /* 353*0Sstevel@tonic-gate * Make the root vnode 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate srootvp = makelonode(realrootvp, li); 356*0Sstevel@tonic-gate srootvp->v_flag |= VROOT; 357*0Sstevel@tonic-gate li->li_rootvp = srootvp; 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate #ifdef LODEBUG 360*0Sstevel@tonic-gate lo_dprint(4, "lo_mount: vfs %p realvfs %p root %p realroot %p li %p\n", 361*0Sstevel@tonic-gate vfsp, li->li_realvfs, srootvp, realrootvp, li); 362*0Sstevel@tonic-gate #endif 363*0Sstevel@tonic-gate return (0); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * Undo loopback mount 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate static int 370*0Sstevel@tonic-gate lo_unmount(struct vfs *vfsp, int flag, struct cred *cr) 371*0Sstevel@tonic-gate { 372*0Sstevel@tonic-gate struct loinfo *li; 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 375*0Sstevel@tonic-gate return (EPERM); 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate /* 378*0Sstevel@tonic-gate * Forced unmount is not supported by this file system 379*0Sstevel@tonic-gate * and thus, ENOTSUP, is being returned. 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate if (flag & MS_FORCE) 382*0Sstevel@tonic-gate return (ENOTSUP); 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate li = vtoli(vfsp); 385*0Sstevel@tonic-gate #ifdef LODEBUG 386*0Sstevel@tonic-gate lo_dprint(4, "lo_unmount(%p) li %p\n", vfsp, li); 387*0Sstevel@tonic-gate #endif 388*0Sstevel@tonic-gate if (li->li_refct != 1 || li->li_rootvp->v_count != 1) { 389*0Sstevel@tonic-gate #ifdef LODEBUG 390*0Sstevel@tonic-gate lo_dprint(4, "refct %d v_ct %d\n", li->li_refct, 391*0Sstevel@tonic-gate li->li_rootvp->v_count); 392*0Sstevel@tonic-gate #endif 393*0Sstevel@tonic-gate return (EBUSY); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate VN_RELE(li->li_rootvp); 396*0Sstevel@tonic-gate return (0); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate /* 400*0Sstevel@tonic-gate * Find root of lofs mount. 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate static int 403*0Sstevel@tonic-gate lo_root(struct vfs *vfsp, struct vnode **vpp) 404*0Sstevel@tonic-gate { 405*0Sstevel@tonic-gate *vpp = vtoli(vfsp)->li_rootvp; 406*0Sstevel@tonic-gate #ifdef LODEBUG 407*0Sstevel@tonic-gate lo_dprint(4, "lo_root(0x%p) = %p\n", vfsp, *vpp); 408*0Sstevel@tonic-gate #endif 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * If the root of the filesystem is a special file, return the specvp 411*0Sstevel@tonic-gate * version of the vnode. We don't save the specvp vnode in our 412*0Sstevel@tonic-gate * hashtable since that's exclusively for lnodes. 413*0Sstevel@tonic-gate */ 414*0Sstevel@tonic-gate if (IS_DEVVP(*vpp)) { 415*0Sstevel@tonic-gate struct vnode *svp; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, kcred); 418*0Sstevel@tonic-gate if (svp == NULL) 419*0Sstevel@tonic-gate return (ENOSYS); 420*0Sstevel@tonic-gate *vpp = svp; 421*0Sstevel@tonic-gate } else { 422*0Sstevel@tonic-gate VN_HOLD(*vpp); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate return (0); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Get file system statistics. 430*0Sstevel@tonic-gate */ 431*0Sstevel@tonic-gate static int 432*0Sstevel@tonic-gate lo_statvfs(register struct vfs *vfsp, struct statvfs64 *sbp) 433*0Sstevel@tonic-gate { 434*0Sstevel@tonic-gate vnode_t *realrootvp; 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate #ifdef LODEBUG 437*0Sstevel@tonic-gate lo_dprint(4, "lostatvfs %p\n", vfsp); 438*0Sstevel@tonic-gate #endif 439*0Sstevel@tonic-gate /* 440*0Sstevel@tonic-gate * Using realrootvp->v_vfsp (instead of the realvfsp that was 441*0Sstevel@tonic-gate * cached) is necessary to make lofs work woth forced UFS unmounts. 442*0Sstevel@tonic-gate * In the case of a forced unmount, UFS stores a set of dummy vfsops 443*0Sstevel@tonic-gate * in all the (i)vnodes in the filesystem. The dummy ops simply 444*0Sstevel@tonic-gate * returns back EIO. 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate (void) lo_realvfs(vfsp, &realrootvp); 447*0Sstevel@tonic-gate if (realrootvp != NULL) 448*0Sstevel@tonic-gate return (VFS_STATVFS(realrootvp->v_vfsp, sbp)); 449*0Sstevel@tonic-gate else 450*0Sstevel@tonic-gate return (EIO); 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* 454*0Sstevel@tonic-gate * LOFS doesn't have any data or metadata to flush, pending I/O on the 455*0Sstevel@tonic-gate * underlying filesystem will be flushed when such filesystem is synched. 456*0Sstevel@tonic-gate */ 457*0Sstevel@tonic-gate /* ARGSUSED */ 458*0Sstevel@tonic-gate static int 459*0Sstevel@tonic-gate lo_sync(struct vfs *vfsp, 460*0Sstevel@tonic-gate short flag, 461*0Sstevel@tonic-gate struct cred *cr) 462*0Sstevel@tonic-gate { 463*0Sstevel@tonic-gate #ifdef LODEBUG 464*0Sstevel@tonic-gate lo_dprint(4, "lo_sync: %p\n", vfsp); 465*0Sstevel@tonic-gate #endif 466*0Sstevel@tonic-gate return (0); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate /* 470*0Sstevel@tonic-gate * Obtain the vnode from the underlying filesystem. 471*0Sstevel@tonic-gate */ 472*0Sstevel@tonic-gate static int 473*0Sstevel@tonic-gate lo_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 474*0Sstevel@tonic-gate { 475*0Sstevel@tonic-gate vnode_t *realrootvp; 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate #ifdef LODEBUG 478*0Sstevel@tonic-gate lo_dprint(4, "lo_vget: %p\n", vfsp); 479*0Sstevel@tonic-gate #endif 480*0Sstevel@tonic-gate (void) lo_realvfs(vfsp, &realrootvp); 481*0Sstevel@tonic-gate if (realrootvp != NULL) 482*0Sstevel@tonic-gate return (VFS_VGET(realrootvp->v_vfsp, vpp, fidp)); 483*0Sstevel@tonic-gate else 484*0Sstevel@tonic-gate return (EIO); 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate /* 488*0Sstevel@tonic-gate * Free mount-specific data. 489*0Sstevel@tonic-gate */ 490*0Sstevel@tonic-gate static void 491*0Sstevel@tonic-gate lo_freevfs(struct vfs *vfsp) 492*0Sstevel@tonic-gate { 493*0Sstevel@tonic-gate struct loinfo *li = vtoli(vfsp); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate ldestroy(li); 496*0Sstevel@tonic-gate kmem_free(li, sizeof (struct loinfo)); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate static int 500*0Sstevel@tonic-gate lofsinit(int fstyp, char *name) 501*0Sstevel@tonic-gate { 502*0Sstevel@tonic-gate static const fs_operation_def_t lo_vfsops_template[] = { 503*0Sstevel@tonic-gate VFSNAME_MOUNT, lo_mount, 504*0Sstevel@tonic-gate VFSNAME_UNMOUNT, lo_unmount, 505*0Sstevel@tonic-gate VFSNAME_ROOT, lo_root, 506*0Sstevel@tonic-gate VFSNAME_STATVFS, lo_statvfs, 507*0Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) lo_sync, 508*0Sstevel@tonic-gate VFSNAME_VGET, lo_vget, 509*0Sstevel@tonic-gate VFSNAME_FREEVFS, (fs_generic_func_p) lo_freevfs, 510*0Sstevel@tonic-gate NULL, NULL 511*0Sstevel@tonic-gate }; 512*0Sstevel@tonic-gate int error; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate error = vfs_setfsops(fstyp, lo_vfsops_template, &lo_vfsops); 515*0Sstevel@tonic-gate if (error != 0) { 516*0Sstevel@tonic-gate cmn_err(CE_WARN, "lofsinit: bad vfs ops template"); 517*0Sstevel@tonic-gate return (error); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate error = vn_make_ops(name, lo_vnodeops_template, &lo_vnodeops); 521*0Sstevel@tonic-gate if (error != 0) { 522*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 523*0Sstevel@tonic-gate cmn_err(CE_WARN, "lofsinit: bad vnode ops template"); 524*0Sstevel@tonic-gate return (error); 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate lofsfstype = fstyp; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate if ((lofs_major = getudev()) == (major_t)-1) { 530*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 531*0Sstevel@tonic-gate cmn_err(CE_WARN, "lofsinit: Can't get unique device number."); 532*0Sstevel@tonic-gate return (ENXIO); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate lofs_minor = 0; 536*0Sstevel@tonic-gate mutex_init(&lofs_minor_lock, NULL, MUTEX_DEFAULT, NULL); 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate return (0); 539*0Sstevel@tonic-gate } 540