10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1488Srsb * Common Development and Distribution License (the "License"). 6*1488Srsb * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1488Srsb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/errno.h> 300Sstevel@tonic-gate #include <sys/vfs.h> 310Sstevel@tonic-gate #include <sys/vnode.h> 320Sstevel@tonic-gate #include <sys/uio.h> 330Sstevel@tonic-gate #include <sys/pathname.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/cred.h> 360Sstevel@tonic-gate #include <sys/statvfs.h> 370Sstevel@tonic-gate #include <sys/fs/lofs_info.h> 380Sstevel@tonic-gate #include <sys/fs/lofs_node.h> 390Sstevel@tonic-gate #include <sys/mount.h> 400Sstevel@tonic-gate #include <sys/mntent.h> 410Sstevel@tonic-gate #include <sys/mkdev.h> 420Sstevel@tonic-gate #include <sys/sysmacros.h> 430Sstevel@tonic-gate #include <sys/systm.h> 440Sstevel@tonic-gate #include <sys/cmn_err.h> 450Sstevel@tonic-gate #include <sys/policy.h> 460Sstevel@tonic-gate #include "fs/fs_subr.h" 470Sstevel@tonic-gate 480Sstevel@tonic-gate /* 490Sstevel@tonic-gate * This is the loadable module wrapper. 500Sstevel@tonic-gate */ 510Sstevel@tonic-gate #include <sys/modctl.h> 520Sstevel@tonic-gate 530Sstevel@tonic-gate static mntopts_t lofs_mntopts; 540Sstevel@tonic-gate 550Sstevel@tonic-gate static int lofsinit(int, char *); 560Sstevel@tonic-gate 570Sstevel@tonic-gate static vfsdef_t vfw = { 580Sstevel@tonic-gate VFSDEF_VERSION, 590Sstevel@tonic-gate "lofs", 600Sstevel@tonic-gate lofsinit, 61*1488Srsb VSW_HASPROTO|VSW_STATS, 620Sstevel@tonic-gate &lofs_mntopts 630Sstevel@tonic-gate }; 640Sstevel@tonic-gate 650Sstevel@tonic-gate /* 660Sstevel@tonic-gate * Stuff needed to support "zonedevfs" mode. 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate static major_t lofs_major; 690Sstevel@tonic-gate static minor_t lofs_minor; 700Sstevel@tonic-gate static kmutex_t lofs_minor_lock; 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * LOFS mount options table 740Sstevel@tonic-gate */ 750Sstevel@tonic-gate static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 760Sstevel@tonic-gate static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 770Sstevel@tonic-gate static char *zonedevfs_cancel[] = { MNTOPT_LOFS_NOZONEDEVFS, NULL }; 780Sstevel@tonic-gate static char *nozonedevfs_cancel[] = { MNTOPT_LOFS_ZONEDEVFS, NULL }; 790Sstevel@tonic-gate static char *sub_cancel[] = { MNTOPT_LOFS_NOSUB, NULL }; 800Sstevel@tonic-gate static char *nosub_cancel[] = { MNTOPT_LOFS_SUB, NULL }; 810Sstevel@tonic-gate 820Sstevel@tonic-gate static mntopt_t mntopts[] = { 830Sstevel@tonic-gate /* 840Sstevel@tonic-gate * option name cancel option default arg flags 850Sstevel@tonic-gate * private data 860Sstevel@tonic-gate */ 870Sstevel@tonic-gate { MNTOPT_XATTR, xattr_cancel, NULL, 0, 880Sstevel@tonic-gate (void *)0 }, 890Sstevel@tonic-gate { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 900Sstevel@tonic-gate (void *)0 }, 910Sstevel@tonic-gate { MNTOPT_LOFS_ZONEDEVFS, zonedevfs_cancel, NULL, 0, 920Sstevel@tonic-gate (void *)0 }, 930Sstevel@tonic-gate { MNTOPT_LOFS_NOZONEDEVFS, nozonedevfs_cancel, NULL, 0, 940Sstevel@tonic-gate (void *)0 }, 950Sstevel@tonic-gate { MNTOPT_LOFS_SUB, sub_cancel, NULL, 0, 960Sstevel@tonic-gate (void *)0 }, 970Sstevel@tonic-gate { MNTOPT_LOFS_NOSUB, nosub_cancel, NULL, 0, 980Sstevel@tonic-gate (void *)0 }, 990Sstevel@tonic-gate }; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate static mntopts_t lofs_mntopts = { 1020Sstevel@tonic-gate sizeof (mntopts) / sizeof (mntopt_t), 1030Sstevel@tonic-gate mntopts 1040Sstevel@tonic-gate }; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * Module linkage information for the kernel. 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate static struct modlfs modlfs = { 1110Sstevel@tonic-gate &mod_fsops, "filesystem for lofs", &vfw 1120Sstevel@tonic-gate }; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate static struct modlinkage modlinkage = { 1150Sstevel@tonic-gate MODREV_1, (void *)&modlfs, NULL 1160Sstevel@tonic-gate }; 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /* 1190Sstevel@tonic-gate * This is the module initialization routine. 1200Sstevel@tonic-gate */ 1210Sstevel@tonic-gate int 1220Sstevel@tonic-gate _init() 1230Sstevel@tonic-gate { 1240Sstevel@tonic-gate int status; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate lofs_subrinit(); 1270Sstevel@tonic-gate status = mod_install(&modlinkage); 1280Sstevel@tonic-gate if (status != 0) { 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * Cleanup previously initialized work. 1310Sstevel@tonic-gate */ 1320Sstevel@tonic-gate lofs_subrfini(); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate return (status); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* 1390Sstevel@tonic-gate * Don't allow the lofs module to be unloaded for now. 1400Sstevel@tonic-gate * There is a memory leak if it gets unloaded. 1410Sstevel@tonic-gate */ 1420Sstevel@tonic-gate int 1430Sstevel@tonic-gate _fini() 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate return (EBUSY); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate int 1490Sstevel@tonic-gate _info(struct modinfo *modinfop) 1500Sstevel@tonic-gate { 1510Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate static int lofsfstype; 1560Sstevel@tonic-gate vfsops_t *lo_vfsops; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * lo mount vfsop 1600Sstevel@tonic-gate * Set up mount info record and attach it to vfs struct. 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate /*ARGSUSED*/ 1630Sstevel@tonic-gate static int 1640Sstevel@tonic-gate lo_mount(struct vfs *vfsp, 1650Sstevel@tonic-gate struct vnode *vp, 1660Sstevel@tonic-gate struct mounta *uap, 1670Sstevel@tonic-gate struct cred *cr) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate int error; 1700Sstevel@tonic-gate struct vnode *srootvp = NULL; /* the server's root */ 1710Sstevel@tonic-gate struct vnode *realrootvp; 1720Sstevel@tonic-gate struct loinfo *li; 1730Sstevel@tonic-gate int is_zonedevfs = 0; 1740Sstevel@tonic-gate int nodev; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate nodev = vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate if ((error = secpolicy_fs_mount(cr, vp, vfsp)) != 0) 1790Sstevel@tonic-gate return (EPERM); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * Loopback devices which get "nodevices" added can be done without 1830Sstevel@tonic-gate * "nodevices" set because we cannot import devices into a zone 1840Sstevel@tonic-gate * with loopback. Note that we have all zone privileges when 1850Sstevel@tonic-gate * this happens; if not, we'd have gotten "nosuid". 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate if (!nodev && vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 1880Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_DEVICES, NULL, VFS_NODISPLAY); 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * We must ensure that only the global zone applies the 'zonedevfs' 1920Sstevel@tonic-gate * option; we don't want non-global zones to be able to establish 1930Sstevel@tonic-gate * lofs mounts using the special dev_t we use to ensure that the 1940Sstevel@tonic-gate * contents of a zone's /dev cannot be victim to link(2) or rename(2). 1950Sstevel@tonic-gate * See below, where we set all of this up. 1960Sstevel@tonic-gate * 1970Sstevel@tonic-gate * Since this is more like a privilege check, we use crgetzoneid(cr) 1980Sstevel@tonic-gate * instead of getzoneid(). 1990Sstevel@tonic-gate */ 2000Sstevel@tonic-gate is_zonedevfs = vfs_optionisset(vfsp, MNTOPT_LOFS_ZONEDEVFS, NULL); 2010Sstevel@tonic-gate if (crgetzoneid(cr) != GLOBAL_ZONEID && is_zonedevfs) 2020Sstevel@tonic-gate return (EPERM); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate mutex_enter(&vp->v_lock); 2050Sstevel@tonic-gate if (!(uap->flags & MS_OVERLAY) && 2060Sstevel@tonic-gate (vp->v_count != 1 || (vp->v_flag & VROOT))) { 2070Sstevel@tonic-gate mutex_exit(&vp->v_lock); 2080Sstevel@tonic-gate return (EBUSY); 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate mutex_exit(&vp->v_lock); 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Find real root, and make vfs point to real vfs 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate if (error = lookupname(uap->spec, (uap->flags & MS_SYSSPACE) ? 2160Sstevel@tonic-gate UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, 2170Sstevel@tonic-gate &realrootvp)) 2180Sstevel@tonic-gate return (error); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* 2210Sstevel@tonic-gate * realrootvp may be an AUTOFS node, in which case we 2220Sstevel@tonic-gate * perform a VOP_ACCESS() to trigger the mount of the 2230Sstevel@tonic-gate * intended filesystem, so we loopback mount the intended 2240Sstevel@tonic-gate * filesystem instead of the AUTOFS filesystem. 2250Sstevel@tonic-gate */ 2260Sstevel@tonic-gate (void) VOP_ACCESS(realrootvp, 0, 0, cr); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* 2290Sstevel@tonic-gate * We're interested in the top most filesystem. 2300Sstevel@tonic-gate * This is specially important when uap->spec is a trigger 2310Sstevel@tonic-gate * AUTOFS node, since we're really interested in mounting the 2320Sstevel@tonic-gate * filesystem AUTOFS mounted as result of the VOP_ACCESS() 2330Sstevel@tonic-gate * call not the AUTOFS node itself. 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate if (vn_mountedvfs(realrootvp) != NULL) { 2360Sstevel@tonic-gate if (error = traverse(&realrootvp)) { 2370Sstevel@tonic-gate VN_RELE(realrootvp); 2380Sstevel@tonic-gate return (error); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * Allocate a vfs info struct and attach it 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate li = kmem_zalloc(sizeof (struct loinfo), KM_SLEEP); 2460Sstevel@tonic-gate li->li_realvfs = realrootvp->v_vfsp; 2470Sstevel@tonic-gate li->li_mountvfs = vfsp; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* 2500Sstevel@tonic-gate * Set mount flags to be inherited by loopback vfs's 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) { 2530Sstevel@tonic-gate li->li_mflag |= VFS_RDONLY; 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { 2560Sstevel@tonic-gate li->li_mflag |= (VFS_NOSETUID|VFS_NODEVICES); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) { 2590Sstevel@tonic-gate li->li_mflag |= VFS_NODEVICES; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) { 2620Sstevel@tonic-gate li->li_mflag |= VFS_NOSETUID; 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate /* 2650Sstevel@tonic-gate * Permissive flags are added to the "deny" bitmap. 2660Sstevel@tonic-gate */ 2670Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) { 2680Sstevel@tonic-gate li->li_dflag |= VFS_XATTR; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) { 2710Sstevel@tonic-gate li->li_dflag |= VFS_NBMAND; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * Propagate inheritable mount flags from the real vfs. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_RDONLY) && 2780Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_RO, NULL)) 2790Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 2800Sstevel@tonic-gate VFS_NODISPLAY); 2810Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_NOSETUID) && 2820Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) 2830Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 2840Sstevel@tonic-gate VFS_NODISPLAY); 2850Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_NODEVICES) && 2860Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 2870Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 2880Sstevel@tonic-gate VFS_NODISPLAY); 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * Permissive flags such as VFS_XATTR, as opposed to restrictive flags 2910Sstevel@tonic-gate * such as VFS_RDONLY, are handled differently. An explicit 2920Sstevel@tonic-gate * MNTOPT_NOXATTR should override the underlying filesystem's VFS_XATTR. 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_XATTR) && 2950Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL) && 2960Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) 2970Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_XATTR, NULL, 2980Sstevel@tonic-gate VFS_NODISPLAY); 2990Sstevel@tonic-gate if ((li->li_realvfs->vfs_flag & VFS_NBMAND) && 3000Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL) && 3010Sstevel@tonic-gate !vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) 3020Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_NBMAND, NULL, 3030Sstevel@tonic-gate VFS_NODISPLAY); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate li->li_refct = 0; 3060Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)li; 3070Sstevel@tonic-gate vfsp->vfs_bcount = 0; 3080Sstevel@tonic-gate vfsp->vfs_fstype = lofsfstype; 3090Sstevel@tonic-gate vfsp->vfs_bsize = li->li_realvfs->vfs_bsize; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * Test to see if we need to be in "zone /dev" mode. In zonedevfs 3130Sstevel@tonic-gate * mode, we pull a nasty trick; we make sure that the lofs dev_t does 3140Sstevel@tonic-gate * *not* reflect the underlying device, so that no renames or links 3150Sstevel@tonic-gate * can occur to or from the /dev hierarchy. 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate if (is_zonedevfs) { 3180Sstevel@tonic-gate dev_t dev; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate mutex_enter(&lofs_minor_lock); 3210Sstevel@tonic-gate do { 3220Sstevel@tonic-gate lofs_minor = (lofs_minor + 1) & MAXMIN32; 3230Sstevel@tonic-gate dev = makedevice(lofs_major, lofs_minor); 3240Sstevel@tonic-gate } while (vfs_devismounted(dev)); 3250Sstevel@tonic-gate mutex_exit(&lofs_minor_lock); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate vfsp->vfs_dev = dev; 3280Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, dev, lofsfstype); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate li->li_flag |= LO_ZONEDEVFS; 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate vfsp->vfs_dev = li->li_realvfs->vfs_dev; 3330Sstevel@tonic-gate vfsp->vfs_fsid.val[0] = li->li_realvfs->vfs_fsid.val[0]; 3340Sstevel@tonic-gate vfsp->vfs_fsid.val[1] = li->li_realvfs->vfs_fsid.val[1]; 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_LOFS_NOSUB, NULL)) { 3380Sstevel@tonic-gate li->li_flag |= LO_NOSUB; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * Setup the hashtable. If the root of this mount isn't a directory, 3430Sstevel@tonic-gate * there's no point in allocating a large hashtable. A table with one 3440Sstevel@tonic-gate * bucket is sufficient. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate if (realrootvp->v_type != VDIR) 3470Sstevel@tonic-gate lsetup(li, 1); 3480Sstevel@tonic-gate else 3490Sstevel@tonic-gate lsetup(li, 0); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate /* 3520Sstevel@tonic-gate * Make the root vnode 3530Sstevel@tonic-gate */ 354324Sowenr srootvp = makelonode(realrootvp, li, 0); 3550Sstevel@tonic-gate srootvp->v_flag |= VROOT; 3560Sstevel@tonic-gate li->li_rootvp = srootvp; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate #ifdef LODEBUG 3590Sstevel@tonic-gate lo_dprint(4, "lo_mount: vfs %p realvfs %p root %p realroot %p li %p\n", 3600Sstevel@tonic-gate vfsp, li->li_realvfs, srootvp, realrootvp, li); 3610Sstevel@tonic-gate #endif 3620Sstevel@tonic-gate return (0); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * Undo loopback mount 3670Sstevel@tonic-gate */ 3680Sstevel@tonic-gate static int 3690Sstevel@tonic-gate lo_unmount(struct vfs *vfsp, int flag, struct cred *cr) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate struct loinfo *li; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 3740Sstevel@tonic-gate return (EPERM); 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * Forced unmount is not supported by this file system 3780Sstevel@tonic-gate * and thus, ENOTSUP, is being returned. 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate if (flag & MS_FORCE) 3810Sstevel@tonic-gate return (ENOTSUP); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate li = vtoli(vfsp); 3840Sstevel@tonic-gate #ifdef LODEBUG 3850Sstevel@tonic-gate lo_dprint(4, "lo_unmount(%p) li %p\n", vfsp, li); 3860Sstevel@tonic-gate #endif 3870Sstevel@tonic-gate if (li->li_refct != 1 || li->li_rootvp->v_count != 1) { 3880Sstevel@tonic-gate #ifdef LODEBUG 3890Sstevel@tonic-gate lo_dprint(4, "refct %d v_ct %d\n", li->li_refct, 3900Sstevel@tonic-gate li->li_rootvp->v_count); 3910Sstevel@tonic-gate #endif 3920Sstevel@tonic-gate return (EBUSY); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate VN_RELE(li->li_rootvp); 3950Sstevel@tonic-gate return (0); 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate /* 3990Sstevel@tonic-gate * Find root of lofs mount. 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate static int 4020Sstevel@tonic-gate lo_root(struct vfs *vfsp, struct vnode **vpp) 4030Sstevel@tonic-gate { 4040Sstevel@tonic-gate *vpp = vtoli(vfsp)->li_rootvp; 4050Sstevel@tonic-gate #ifdef LODEBUG 4060Sstevel@tonic-gate lo_dprint(4, "lo_root(0x%p) = %p\n", vfsp, *vpp); 4070Sstevel@tonic-gate #endif 4080Sstevel@tonic-gate /* 4090Sstevel@tonic-gate * If the root of the filesystem is a special file, return the specvp 4100Sstevel@tonic-gate * version of the vnode. We don't save the specvp vnode in our 4110Sstevel@tonic-gate * hashtable since that's exclusively for lnodes. 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate if (IS_DEVVP(*vpp)) { 4140Sstevel@tonic-gate struct vnode *svp; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, kcred); 4170Sstevel@tonic-gate if (svp == NULL) 4180Sstevel@tonic-gate return (ENOSYS); 4190Sstevel@tonic-gate *vpp = svp; 4200Sstevel@tonic-gate } else { 4210Sstevel@tonic-gate VN_HOLD(*vpp); 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate return (0); 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate * Get file system statistics. 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate static int 4310Sstevel@tonic-gate lo_statvfs(register struct vfs *vfsp, struct statvfs64 *sbp) 4320Sstevel@tonic-gate { 4330Sstevel@tonic-gate vnode_t *realrootvp; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate #ifdef LODEBUG 4360Sstevel@tonic-gate lo_dprint(4, "lostatvfs %p\n", vfsp); 4370Sstevel@tonic-gate #endif 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * Using realrootvp->v_vfsp (instead of the realvfsp that was 4400Sstevel@tonic-gate * cached) is necessary to make lofs work woth forced UFS unmounts. 4410Sstevel@tonic-gate * In the case of a forced unmount, UFS stores a set of dummy vfsops 4420Sstevel@tonic-gate * in all the (i)vnodes in the filesystem. The dummy ops simply 4430Sstevel@tonic-gate * returns back EIO. 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate (void) lo_realvfs(vfsp, &realrootvp); 4460Sstevel@tonic-gate if (realrootvp != NULL) 4470Sstevel@tonic-gate return (VFS_STATVFS(realrootvp->v_vfsp, sbp)); 4480Sstevel@tonic-gate else 4490Sstevel@tonic-gate return (EIO); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /* 4530Sstevel@tonic-gate * LOFS doesn't have any data or metadata to flush, pending I/O on the 4540Sstevel@tonic-gate * underlying filesystem will be flushed when such filesystem is synched. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate /* ARGSUSED */ 4570Sstevel@tonic-gate static int 4580Sstevel@tonic-gate lo_sync(struct vfs *vfsp, 4590Sstevel@tonic-gate short flag, 4600Sstevel@tonic-gate struct cred *cr) 4610Sstevel@tonic-gate { 4620Sstevel@tonic-gate #ifdef LODEBUG 4630Sstevel@tonic-gate lo_dprint(4, "lo_sync: %p\n", vfsp); 4640Sstevel@tonic-gate #endif 4650Sstevel@tonic-gate return (0); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * Obtain the vnode from the underlying filesystem. 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate static int 4720Sstevel@tonic-gate lo_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 4730Sstevel@tonic-gate { 4740Sstevel@tonic-gate vnode_t *realrootvp; 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate #ifdef LODEBUG 4770Sstevel@tonic-gate lo_dprint(4, "lo_vget: %p\n", vfsp); 4780Sstevel@tonic-gate #endif 4790Sstevel@tonic-gate (void) lo_realvfs(vfsp, &realrootvp); 4800Sstevel@tonic-gate if (realrootvp != NULL) 4810Sstevel@tonic-gate return (VFS_VGET(realrootvp->v_vfsp, vpp, fidp)); 4820Sstevel@tonic-gate else 4830Sstevel@tonic-gate return (EIO); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * Free mount-specific data. 4880Sstevel@tonic-gate */ 4890Sstevel@tonic-gate static void 4900Sstevel@tonic-gate lo_freevfs(struct vfs *vfsp) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate struct loinfo *li = vtoli(vfsp); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate ldestroy(li); 4950Sstevel@tonic-gate kmem_free(li, sizeof (struct loinfo)); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate static int 4990Sstevel@tonic-gate lofsinit(int fstyp, char *name) 5000Sstevel@tonic-gate { 5010Sstevel@tonic-gate static const fs_operation_def_t lo_vfsops_template[] = { 5020Sstevel@tonic-gate VFSNAME_MOUNT, lo_mount, 5030Sstevel@tonic-gate VFSNAME_UNMOUNT, lo_unmount, 5040Sstevel@tonic-gate VFSNAME_ROOT, lo_root, 5050Sstevel@tonic-gate VFSNAME_STATVFS, lo_statvfs, 5060Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) lo_sync, 5070Sstevel@tonic-gate VFSNAME_VGET, lo_vget, 5080Sstevel@tonic-gate VFSNAME_FREEVFS, (fs_generic_func_p) lo_freevfs, 5090Sstevel@tonic-gate NULL, NULL 5100Sstevel@tonic-gate }; 5110Sstevel@tonic-gate int error; 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate error = vfs_setfsops(fstyp, lo_vfsops_template, &lo_vfsops); 5140Sstevel@tonic-gate if (error != 0) { 5150Sstevel@tonic-gate cmn_err(CE_WARN, "lofsinit: bad vfs ops template"); 5160Sstevel@tonic-gate return (error); 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate error = vn_make_ops(name, lo_vnodeops_template, &lo_vnodeops); 5200Sstevel@tonic-gate if (error != 0) { 5210Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 5220Sstevel@tonic-gate cmn_err(CE_WARN, "lofsinit: bad vnode ops template"); 5230Sstevel@tonic-gate return (error); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate lofsfstype = fstyp; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate if ((lofs_major = getudev()) == (major_t)-1) { 5290Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstyp); 5300Sstevel@tonic-gate cmn_err(CE_WARN, "lofsinit: Can't get unique device number."); 5310Sstevel@tonic-gate return (ENXIO); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate lofs_minor = 0; 5350Sstevel@tonic-gate mutex_init(&lofs_minor_lock, NULL, MUTEX_DEFAULT, NULL); 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate return (0); 5380Sstevel@tonic-gate } 539