12621Sllai1 /* 22621Sllai1 * CDDL HEADER START 32621Sllai1 * 42621Sllai1 * The contents of this file are subject to the terms of the 52621Sllai1 * Common Development and Distribution License (the "License"). 62621Sllai1 * You may not use this file except in compliance with the License. 72621Sllai1 * 82621Sllai1 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92621Sllai1 * or http://www.opensolaris.org/os/licensing. 102621Sllai1 * See the License for the specific language governing permissions 112621Sllai1 * and limitations under the License. 122621Sllai1 * 132621Sllai1 * When distributing Covered Code, include this CDDL HEADER in each 142621Sllai1 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152621Sllai1 * If applicable, add the following below this CDDL HEADER, with the 162621Sllai1 * fields enclosed by brackets "[]" replaced with your own identifying 172621Sllai1 * information: Portions Copyright [yyyy] [name of copyright owner] 182621Sllai1 * 192621Sllai1 * CDDL HEADER END 202621Sllai1 */ 212621Sllai1 /* 223843Sjg * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 232621Sllai1 * Use is subject to license terms. 242621Sllai1 */ 252621Sllai1 262621Sllai1 #pragma ident "%Z%%M% %I% %E% SMI" 272621Sllai1 282621Sllai1 /* 292621Sllai1 * This is the /dev (hence, the sdev_ prefix) filesystem. 302621Sllai1 */ 312621Sllai1 322621Sllai1 #include <sys/types.h> 332621Sllai1 #include <sys/param.h> 342621Sllai1 #include <sys/sysmacros.h> 352621Sllai1 #include <sys/systm.h> 362621Sllai1 #include <sys/kmem.h> 372621Sllai1 #include <sys/time.h> 382621Sllai1 #include <sys/pathname.h> 392621Sllai1 #include <sys/vfs.h> 403898Srsb #include <sys/vfs_opreg.h> 412621Sllai1 #include <sys/vnode.h> 422621Sllai1 #include <sys/file.h> 432621Sllai1 #include <sys/stat.h> 442621Sllai1 #include <sys/uio.h> 452621Sllai1 #include <sys/stat.h> 462621Sllai1 #include <sys/errno.h> 472621Sllai1 #include <sys/cmn_err.h> 482621Sllai1 #include <sys/cred.h> 492621Sllai1 #include <sys/statvfs.h> 502621Sllai1 #include <sys/policy.h> 512621Sllai1 #include <sys/mount.h> 522621Sllai1 #include <sys/debug.h> 532621Sllai1 #include <sys/modctl.h> 542621Sllai1 #include <sys/mkdev.h> 552621Sllai1 #include <fs/fs_subr.h> 562621Sllai1 #include <sys/fs/sdev_impl.h> 572621Sllai1 #include <sys/fs/sdev_node.h> 582621Sllai1 #include <sys/fs/snode.h> 592621Sllai1 #include <sys/fs/dv_node.h> 602621Sllai1 #include <sys/sunndi.h> 612621Sllai1 #include <sys/mntent.h> 622621Sllai1 632621Sllai1 /* 642621Sllai1 * /dev vfs operations. 652621Sllai1 */ 662621Sllai1 672621Sllai1 /* 682621Sllai1 * globals 692621Sllai1 */ 702621Sllai1 struct sdev_data *sdev_origins; /* mount info for origins under /dev */ 712729Sllai1 kmutex_t sdev_lock; /* used for mount/unmount/rename synchronization */ 722621Sllai1 732621Sllai1 /* 742621Sllai1 * static 752621Sllai1 */ 762621Sllai1 static major_t devmajor; /* the fictitious major we live on */ 772621Sllai1 static major_t devminor; /* the fictitious minor of this instance */ 782621Sllai1 static struct sdev_data *sdev_mntinfo = NULL; /* linked list of instances */ 793133Sjg 803133Sjg /* LINTED E_STATIC_UNUSED */ /* useful for debugging */ 812621Sllai1 static struct vnode *sdev_stale_attrvp; /* stale root attrvp after remount */ 822621Sllai1 832621Sllai1 static int sdev_mount(struct vfs *, struct vnode *, struct mounta *, 842621Sllai1 struct cred *); 852621Sllai1 static int sdev_unmount(struct vfs *, int, struct cred *); 862621Sllai1 static int sdev_root(struct vfs *, struct vnode **); 872621Sllai1 static int sdev_statvfs(struct vfs *, struct statvfs64 *); 882621Sllai1 static void sdev_insert_mntinfo(struct sdev_data *); 892621Sllai1 static int devinit(int, char *); 902621Sllai1 912621Sllai1 static vfsdef_t sdev_vfssw = { 922621Sllai1 VFSDEF_VERSION, 932621Sllai1 "dev", /* type name string */ 942621Sllai1 devinit, /* init routine */ 952621Sllai1 VSW_CANREMOUNT, /* flags */ 962621Sllai1 NULL /* mount options table prototype */ 972621Sllai1 }; 982621Sllai1 992621Sllai1 1002621Sllai1 /* 1012621Sllai1 * Module linkage information 1022621Sllai1 */ 1032621Sllai1 static struct modlfs modlfs = { 1042621Sllai1 &mod_fsops, "/dev filesystem %I%", &sdev_vfssw 1052621Sllai1 }; 1062621Sllai1 1072621Sllai1 static struct modlinkage modlinkage = { 1082621Sllai1 MODREV_1, (void *)&modlfs, NULL 1092621Sllai1 }; 1102621Sllai1 1112621Sllai1 int 1122621Sllai1 _init(void) 1132621Sllai1 { 1142621Sllai1 int e; 1152621Sllai1 1162621Sllai1 mutex_init(&sdev_lock, NULL, MUTEX_DEFAULT, NULL); 1172621Sllai1 sdev_node_cache_init(); 1182621Sllai1 sdev_devfsadm_lockinit(); 1192621Sllai1 if ((e = mod_install(&modlinkage)) != 0) { 1202621Sllai1 sdev_devfsadm_lockdestroy(); 1212621Sllai1 sdev_node_cache_fini(); 1222621Sllai1 mutex_destroy(&sdev_lock); 1232621Sllai1 return (e); 1242621Sllai1 } 1252621Sllai1 return (0); 1262621Sllai1 } 1272621Sllai1 1282621Sllai1 /* 1292621Sllai1 * dev module remained loaded for the global /dev instance 1302621Sllai1 */ 1312621Sllai1 int 1322621Sllai1 _fini(void) 1332621Sllai1 { 1342621Sllai1 return (EBUSY); 1352621Sllai1 } 1362621Sllai1 1372621Sllai1 int 1382621Sllai1 _info(struct modinfo *modinfop) 1392621Sllai1 { 1402621Sllai1 return (mod_info(&modlinkage, modinfop)); 1412621Sllai1 } 1422621Sllai1 1432621Sllai1 /*ARGSUSED*/ 1442621Sllai1 static int 1452621Sllai1 devinit(int fstype, char *name) 1462621Sllai1 { 1472621Sllai1 static const fs_operation_def_t dev_vfsops_tbl[] = { 1483898Srsb VFSNAME_MOUNT, { .vfs_mount = sdev_mount }, 1493898Srsb VFSNAME_UNMOUNT, { .vfs_unmount = sdev_unmount }, 1503898Srsb VFSNAME_ROOT, { .vfs_root = sdev_root }, 1513898Srsb VFSNAME_STATVFS, { .vfs_statvfs = sdev_statvfs }, 1523898Srsb NULL, NULL 1532621Sllai1 }; 1542621Sllai1 1552621Sllai1 int error; 1562621Sllai1 extern major_t getudev(void); 1572621Sllai1 1582621Sllai1 devtype = fstype; 1592621Sllai1 1602621Sllai1 error = vfs_setfsops(fstype, dev_vfsops_tbl, NULL); 1612621Sllai1 if (error != 0) { 1622621Sllai1 cmn_err(CE_WARN, "devinit: bad vfs ops tbl"); 1632621Sllai1 return (error); 1642621Sllai1 } 1652621Sllai1 1662621Sllai1 error = vn_make_ops("dev", sdev_vnodeops_tbl, &sdev_vnodeops); 1672621Sllai1 if (error != 0) { 1682621Sllai1 (void) vfs_freevfsops_by_type(fstype); 1692621Sllai1 cmn_err(CE_WARN, "devinit: bad vnode ops tbl"); 1702621Sllai1 return (error); 1712621Sllai1 } 1722621Sllai1 1732621Sllai1 if ((devmajor = getudev()) == (major_t)-1) { 1742621Sllai1 cmn_err(CE_WARN, "%s: can't get unique dev", sdev_vfssw.name); 1752621Sllai1 return (1); 1762621Sllai1 } 1772621Sllai1 1782621Sllai1 /* initialize negative cache */ 1792621Sllai1 sdev_ncache_init(); 1802621Sllai1 1812621Sllai1 return (0); 1822621Sllai1 } 1832621Sllai1 1842621Sllai1 /* 1852621Sllai1 * Both mount point and backing store directory name are 1862621Sllai1 * passed in from userland 1872621Sllai1 */ 1882621Sllai1 static int 1892621Sllai1 sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap, 1902621Sllai1 struct cred *cr) 1912621Sllai1 { 1922621Sllai1 struct sdev_data *sdev_data; 1932621Sllai1 struct vnode *avp; 1942621Sllai1 struct sdev_node *dv; 1952621Sllai1 struct sdev_mountargs *args = NULL; 1962621Sllai1 int error = 0; 1972621Sllai1 dev_t devdev; 1982621Sllai1 1992621Sllai1 /* 2002621Sllai1 * security check 2012621Sllai1 */ 2022621Sllai1 if ((secpolicy_fs_mount(cr, mvp, vfsp) != 0) || 2032621Sllai1 (secpolicy_sys_devices(cr) != 0)) 2042621Sllai1 return (EPERM); 2052621Sllai1 2062621Sllai1 /* 2072621Sllai1 * Sanity check the mount point 2082621Sllai1 */ 2092621Sllai1 if (mvp->v_type != VDIR) 2102621Sllai1 return (ENOTDIR); 2112621Sllai1 2122621Sllai1 /* 2132621Sllai1 * Sanity Check for overlay mount. 2142621Sllai1 */ 2152621Sllai1 mutex_enter(&mvp->v_lock); 2162621Sllai1 if ((uap->flags & MS_OVERLAY) == 0 && 2172621Sllai1 (uap->flags & MS_REMOUNT) == 0 && 2182621Sllai1 (mvp->v_count > 1 || (mvp->v_flag & VROOT))) { 2192621Sllai1 mutex_exit(&mvp->v_lock); 2202621Sllai1 return (EBUSY); 2212621Sllai1 } 2222621Sllai1 mutex_exit(&mvp->v_lock); 2232621Sllai1 2242621Sllai1 args = kmem_zalloc(sizeof (*args), KM_SLEEP); 2252621Sllai1 2262621Sllai1 if ((uap->flags & MS_DATA) && 2272621Sllai1 (uap->datalen != 0 && uap->dataptr != NULL)) { 2282621Sllai1 /* copy in the arguments */ 2292621Sllai1 if (error = sdev_copyin_mountargs(uap, args)) 2302621Sllai1 goto cleanup; 2312621Sllai1 } 2322621Sllai1 2332621Sllai1 /* 2342621Sllai1 * Sanity check the backing store 2352621Sllai1 */ 2362621Sllai1 if (args->sdev_attrdir) { 2372621Sllai1 /* user supplied an attribute store */ 2382621Sllai1 if (error = lookupname((char *)(uintptr_t)args->sdev_attrdir, 2392621Sllai1 UIO_USERSPACE, FOLLOW, NULLVPP, &avp)) { 2402621Sllai1 cmn_err(CE_NOTE, "/dev fs: lookup on attribute " 2412621Sllai1 "directory %s failed", 2422621Sllai1 (char *)(uintptr_t)args->sdev_attrdir); 2432621Sllai1 goto cleanup; 2442621Sllai1 } 2452621Sllai1 2462621Sllai1 if (avp->v_type != VDIR) { 2472621Sllai1 VN_RELE(avp); 2482621Sllai1 error = ENOTDIR; 2492621Sllai1 goto cleanup; 2502621Sllai1 } 2512621Sllai1 } else { 2522621Sllai1 /* use mountp as the attribute store */ 2532621Sllai1 avp = mvp; 2542621Sllai1 VN_HOLD(avp); 2552621Sllai1 } 2562621Sllai1 2572621Sllai1 mutex_enter(&sdev_lock); 2582621Sllai1 2592621Sllai1 /* 2602621Sllai1 * handling installation 2612621Sllai1 */ 2622621Sllai1 if (uap->flags & MS_REMOUNT) { 2632621Sllai1 sdev_data = (struct sdev_data *)vfsp->vfs_data; 2642621Sllai1 ASSERT(sdev_data); 2652621Sllai1 2662621Sllai1 dv = sdev_data->sdev_root; 2672621Sllai1 ASSERT(dv == dv->sdev_dotdot); 2682621Sllai1 2692621Sllai1 /* 2702621Sllai1 * mark all existing sdev_nodes (except root node) stale 2712621Sllai1 */ 2722621Sllai1 sdev_stale(dv); 2732621Sllai1 2742621Sllai1 /* Reset previous mountargs */ 2752621Sllai1 if (sdev_data->sdev_mountargs) { 2762621Sllai1 kmem_free(sdev_data->sdev_mountargs, 2772621Sllai1 sizeof (struct sdev_mountargs)); 2782621Sllai1 } 2792621Sllai1 sdev_data->sdev_mountargs = args; 2802621Sllai1 args = NULL; /* so it won't be freed below */ 2812621Sllai1 2822621Sllai1 sdev_stale_attrvp = dv->sdev_attrvp; 2832621Sllai1 dv->sdev_attrvp = avp; 2842621Sllai1 vfsp->vfs_mtime = ddi_get_time(); 2852621Sllai1 2862621Sllai1 mutex_exit(&sdev_lock); 2872621Sllai1 goto cleanup; /* we're done */ 2882621Sllai1 } 2892621Sllai1 2902621Sllai1 /* 2912621Sllai1 * Create and initialize the vfs-private data. 2922621Sllai1 */ 2932621Sllai1 devdev = makedevice(devmajor, devminor); 2942621Sllai1 while (vfs_devismounted(devdev)) { 2952621Sllai1 devminor = (devminor + 1) & MAXMIN32; 2962621Sllai1 2972621Sllai1 /* 2982621Sllai1 * All the minor numbers are used up. 2992621Sllai1 */ 3002621Sllai1 if (devminor == 0) { 3012621Sllai1 mutex_exit(&sdev_lock); 3022621Sllai1 VN_RELE(avp); 3032621Sllai1 error = ENODEV; 3042621Sllai1 goto cleanup; 3052621Sllai1 } 3062621Sllai1 3072621Sllai1 devdev = makedevice(devmajor, devminor); 3082621Sllai1 } 3092621Sllai1 3102621Sllai1 dv = sdev_mkroot(vfsp, devdev, mvp, avp, cr); 3112621Sllai1 sdev_data = kmem_zalloc(sizeof (struct sdev_data), KM_SLEEP); 3122621Sllai1 vfsp->vfs_dev = devdev; 3132621Sllai1 vfsp->vfs_data = (caddr_t)sdev_data; 3142621Sllai1 vfsp->vfs_fstype = devtype; 3152621Sllai1 vfsp->vfs_bsize = DEV_BSIZE; 3162621Sllai1 vfsp->vfs_mtime = ddi_get_time(); 3172621Sllai1 vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, devtype); 3182621Sllai1 3192621Sllai1 ASSERT(dv == dv->sdev_dotdot); 3202621Sllai1 3212621Sllai1 sdev_data->sdev_vfsp = vfsp; 3222621Sllai1 sdev_data->sdev_root = dv; 3232621Sllai1 sdev_data->sdev_mountargs = args; 3242621Sllai1 3252621Sllai1 /* get acl flavor from attribute dir */ 3262621Sllai1 if (VOP_PATHCONF(avp, _PC_ACL_ENABLED, &sdev_data->sdev_acl_flavor, 327*5331Samw kcred, NULL) != 0 || sdev_data->sdev_acl_flavor == 0) 3282621Sllai1 sdev_data->sdev_acl_flavor = _ACL_ACLENT_ENABLED; 3292621Sllai1 3302621Sllai1 args = NULL; /* so it won't be freed below */ 3312621Sllai1 sdev_insert_mntinfo(sdev_data); 3322621Sllai1 mutex_exit(&sdev_lock); 3332621Sllai1 3342621Sllai1 if (!SDEV_IS_GLOBAL(dv)) { 3352621Sllai1 ASSERT(sdev_origins); 3362621Sllai1 dv->sdev_flags &= ~SDEV_GLOBAL; 3372621Sllai1 dv->sdev_origin = sdev_origins->sdev_root; 3382621Sllai1 } else { 3392621Sllai1 sdev_ncache_setup(); 3403843Sjg rw_enter(&dv->sdev_contents, RW_WRITER); 3413843Sjg sdev_filldir_dynamic(dv); 3423843Sjg rw_exit(&dv->sdev_contents); 3432621Sllai1 } 3442621Sllai1 3452621Sllai1 sdev_update_timestamps(dv->sdev_attrvp, 3462621Sllai1 cr, AT_CTIME|AT_MTIME|AT_ATIME); 3472621Sllai1 3482621Sllai1 cleanup: 3492621Sllai1 if (args) 3502621Sllai1 kmem_free(args, sizeof (*args)); 3512621Sllai1 return (error); 3522621Sllai1 } 3532621Sllai1 3542621Sllai1 /* 3552621Sllai1 * unmounting the non-global /dev instances, e.g. when deleting a Kevlar zone. 3562621Sllai1 */ 3572621Sllai1 static int 3582621Sllai1 sdev_unmount(struct vfs *vfsp, int flag, struct cred *cr) 3592621Sllai1 { 3602621Sllai1 struct sdev_node *dv; 3612621Sllai1 int error; 3622621Sllai1 struct sdev_data *sdev_data, *prev, *next; 3632621Sllai1 3642621Sllai1 /* 3652621Sllai1 * enforce the security policies 3662621Sllai1 */ 3672621Sllai1 if ((secpolicy_fs_unmount(cr, vfsp) != 0) || 3682621Sllai1 (secpolicy_sys_devices(cr) != 0)) 3692621Sllai1 return (EPERM); 3702621Sllai1 3712621Sllai1 if (flag & MS_FORCE) 3722621Sllai1 return (ENOTSUP); 3732621Sllai1 3742621Sllai1 mutex_enter(&sdev_lock); 3752621Sllai1 dv = VFSTOSDEVFS(vfsp)->sdev_root; 3762621Sllai1 ASSERT(dv == dv->sdev_dotdot); 3772621Sllai1 if (SDEVTOV(dv)->v_count > 1) { 3782621Sllai1 mutex_exit(&sdev_lock); 3792621Sllai1 return (EBUSY); 3802621Sllai1 } 3812621Sllai1 3822621Sllai1 /* 3832621Sllai1 * global instance remains mounted 3842621Sllai1 */ 3852621Sllai1 if (SDEV_IS_GLOBAL(dv)) { 3862621Sllai1 mutex_exit(&sdev_lock); 3872621Sllai1 return (EBUSY); 3882621Sllai1 } 3892621Sllai1 mutex_exit(&sdev_lock); 3902621Sllai1 3912621Sllai1 /* verify the v_count */ 3922621Sllai1 if ((error = sdev_cleandir(dv, NULL, 0)) != 0) { 3932621Sllai1 return (error); 3942621Sllai1 } 3952621Sllai1 ASSERT(SDEVTOV(dv)->v_count == 1); 3962621Sllai1 3972621Sllai1 /* release hold on root node and destroy it */ 3982621Sllai1 SDEV_RELE(dv); 3992621Sllai1 dv->sdev_nlink -= 2; 4002621Sllai1 sdev_nodedestroy(dv, 0); 4012621Sllai1 4022621Sllai1 sdev_data = (struct sdev_data *)vfsp->vfs_data; 4032621Sllai1 vfsp->vfs_data = (caddr_t)0; 4042621Sllai1 4052621Sllai1 /* 4062621Sllai1 * XXX separate it into sdev_delete_mntinfo() if useful 4072621Sllai1 */ 4082621Sllai1 mutex_enter(&sdev_lock); 4092621Sllai1 prev = sdev_data->sdev_prev; 4102621Sllai1 next = sdev_data->sdev_next; 4112621Sllai1 if (prev) 4122621Sllai1 prev->sdev_next = next; 4132621Sllai1 else 4142621Sllai1 sdev_mntinfo = next; 4152621Sllai1 if (next) 4162621Sllai1 next->sdev_prev = prev; 4172621Sllai1 mutex_exit(&sdev_lock); 4182621Sllai1 4192621Sllai1 if (sdev_data->sdev_mountargs) { 4202621Sllai1 kmem_free(sdev_data->sdev_mountargs, 4212621Sllai1 sizeof (struct sdev_mountargs)); 4222621Sllai1 } 4232621Sllai1 kmem_free(sdev_data, sizeof (struct sdev_data)); 4242621Sllai1 return (0); 4252621Sllai1 } 4262621Sllai1 4272621Sllai1 /* 4282621Sllai1 * return root vnode for given vfs 4292621Sllai1 */ 4302621Sllai1 static int 4312621Sllai1 sdev_root(struct vfs *vfsp, struct vnode **vpp) 4322621Sllai1 { 4332621Sllai1 *vpp = SDEVTOV(VFSTOSDEVFS(vfsp)->sdev_root); 4342621Sllai1 VN_HOLD(*vpp); 4352621Sllai1 return (0); 4362621Sllai1 } 4372621Sllai1 4382621Sllai1 /* 4392621Sllai1 * return 'generic superblock' information to userland. 4402621Sllai1 * 4412621Sllai1 * not much that we can usefully admit to here 4422621Sllai1 */ 4432621Sllai1 static int 4442621Sllai1 sdev_statvfs(struct vfs *vfsp, struct statvfs64 *sbp) 4452621Sllai1 { 4462621Sllai1 dev32_t d32; 4472621Sllai1 4482621Sllai1 bzero(sbp, sizeof (*sbp)); 4492621Sllai1 sbp->f_frsize = sbp->f_bsize = vfsp->vfs_bsize; 4502621Sllai1 sbp->f_files = kmem_cache_stat(sdev_node_cache, "alloc"); 4512621Sllai1 4522621Sllai1 /* no illusions that free/avail files is relevant to dev */ 4532621Sllai1 sbp->f_ffree = 0; 4542621Sllai1 sbp->f_favail = 0; 4552621Sllai1 4562621Sllai1 /* no illusions that blocks are relevant to devfs */ 4572621Sllai1 sbp->f_bfree = 0; 4582621Sllai1 sbp->f_bavail = 0; 4592621Sllai1 sbp->f_blocks = 0; 4602621Sllai1 4612621Sllai1 (void) cmpldev(&d32, vfsp->vfs_dev); 4622621Sllai1 sbp->f_fsid = d32; 4632621Sllai1 (void) strcpy(sbp->f_basetype, vfssw[devtype].vsw_name); 4642621Sllai1 sbp->f_flag = vf_to_stf(vfsp->vfs_flag); 4652621Sllai1 sbp->f_namemax = MAXNAMELEN - 1; 4662621Sllai1 (void) strcpy(sbp->f_fstr, "dev"); 4672621Sllai1 4682621Sllai1 return (0); 4692621Sllai1 } 4702621Sllai1 4712621Sllai1 int 4722621Sllai1 sdev_module_register(char *mod_name, struct devname_ops *dev_ops) 4732621Sllai1 { 4742621Sllai1 struct devname_nsmap *map = NULL; 4752621Sllai1 4762621Sllai1 if (strcmp(mod_name, DEVNAME_NSCONFIG) == 0) { 4772621Sllai1 devname_ns_ops = dev_ops; 4782621Sllai1 return (0); 4792621Sllai1 } 4802621Sllai1 4812621Sllai1 map = sdev_get_nsmap_by_module(mod_name); 4822621Sllai1 if (map == NULL) 4832621Sllai1 return (EFAULT); 4842621Sllai1 4852621Sllai1 rw_enter(&map->dir_lock, RW_WRITER); 4862621Sllai1 map->dir_ops = dev_ops; 4872621Sllai1 rw_exit(&map->dir_lock); 4882621Sllai1 return (0); 4892621Sllai1 } 4902621Sllai1 4912621Sllai1 static void 4922621Sllai1 sdev_insert_mntinfo(struct sdev_data *data) 4932621Sllai1 { 4942621Sllai1 ASSERT(mutex_owned(&sdev_lock)); 4952621Sllai1 data->sdev_next = sdev_mntinfo; 4962621Sllai1 data->sdev_prev = NULL; 4972621Sllai1 if (sdev_mntinfo) { 4982621Sllai1 sdev_mntinfo->sdev_prev = data; 4992621Sllai1 } else { 5002621Sllai1 sdev_origins = data; 5012621Sllai1 } 5022621Sllai1 sdev_mntinfo = data; 5032621Sllai1 } 5042621Sllai1 5052621Sllai1 struct sdev_data * 5062621Sllai1 sdev_find_mntinfo(char *mntpt) 5072621Sllai1 { 5082621Sllai1 struct sdev_data *mntinfo; 5092621Sllai1 5102621Sllai1 mutex_enter(&sdev_lock); 5112621Sllai1 mntinfo = sdev_mntinfo; 5122621Sllai1 while (mntinfo) { 5132621Sllai1 if (strcmp(mntpt, mntinfo->sdev_root->sdev_name) == 0) { 5142621Sllai1 SDEVTOV(mntinfo->sdev_root)->v_count++; 5152621Sllai1 break; 5162621Sllai1 } 5172621Sllai1 mntinfo = mntinfo->sdev_next; 5182621Sllai1 } 5192621Sllai1 mutex_exit(&sdev_lock); 5202621Sllai1 return (mntinfo); 5212621Sllai1 } 5222621Sllai1 5232621Sllai1 void 5242621Sllai1 sdev_mntinfo_rele(struct sdev_data *mntinfo) 5252621Sllai1 { 5262621Sllai1 mutex_enter(&sdev_lock); 5272621Sllai1 SDEVTOV(mntinfo->sdev_root)->v_count--; 5282621Sllai1 mutex_exit(&sdev_lock); 5292621Sllai1 } 530