xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_vfsops.c (revision 5331:3047ad28a67b)
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