xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_vfsops.c (revision 2621:4ea88858d952)
1*2621Sllai1 /*
2*2621Sllai1  * CDDL HEADER START
3*2621Sllai1  *
4*2621Sllai1  * The contents of this file are subject to the terms of the
5*2621Sllai1  * Common Development and Distribution License (the "License").
6*2621Sllai1  * You may not use this file except in compliance with the License.
7*2621Sllai1  *
8*2621Sllai1  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2621Sllai1  * or http://www.opensolaris.org/os/licensing.
10*2621Sllai1  * See the License for the specific language governing permissions
11*2621Sllai1  * and limitations under the License.
12*2621Sllai1  *
13*2621Sllai1  * When distributing Covered Code, include this CDDL HEADER in each
14*2621Sllai1  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2621Sllai1  * If applicable, add the following below this CDDL HEADER, with the
16*2621Sllai1  * fields enclosed by brackets "[]" replaced with your own identifying
17*2621Sllai1  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2621Sllai1  *
19*2621Sllai1  * CDDL HEADER END
20*2621Sllai1  */
21*2621Sllai1 /*
22*2621Sllai1  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*2621Sllai1  * Use is subject to license terms.
24*2621Sllai1  */
25*2621Sllai1 
26*2621Sllai1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*2621Sllai1 
28*2621Sllai1 /*
29*2621Sllai1  * This is the /dev (hence, the sdev_ prefix) filesystem.
30*2621Sllai1  */
31*2621Sllai1 
32*2621Sllai1 #include <sys/types.h>
33*2621Sllai1 #include <sys/param.h>
34*2621Sllai1 #include <sys/sysmacros.h>
35*2621Sllai1 #include <sys/systm.h>
36*2621Sllai1 #include <sys/kmem.h>
37*2621Sllai1 #include <sys/time.h>
38*2621Sllai1 #include <sys/pathname.h>
39*2621Sllai1 #include <sys/vfs.h>
40*2621Sllai1 #include <sys/vnode.h>
41*2621Sllai1 #include <sys/file.h>
42*2621Sllai1 #include <sys/stat.h>
43*2621Sllai1 #include <sys/uio.h>
44*2621Sllai1 #include <sys/stat.h>
45*2621Sllai1 #include <sys/errno.h>
46*2621Sllai1 #include <sys/cmn_err.h>
47*2621Sllai1 #include <sys/cred.h>
48*2621Sllai1 #include <sys/statvfs.h>
49*2621Sllai1 #include <sys/policy.h>
50*2621Sllai1 #include <sys/mount.h>
51*2621Sllai1 #include <sys/debug.h>
52*2621Sllai1 #include <sys/modctl.h>
53*2621Sllai1 #include <sys/mkdev.h>
54*2621Sllai1 #include <fs/fs_subr.h>
55*2621Sllai1 #include <sys/fs/sdev_impl.h>
56*2621Sllai1 #include <sys/fs/sdev_node.h>
57*2621Sllai1 #include <sys/fs/snode.h>
58*2621Sllai1 #include <sys/fs/dv_node.h>
59*2621Sllai1 #include <sys/sunndi.h>
60*2621Sllai1 #include <sys/mntent.h>
61*2621Sllai1 
62*2621Sllai1 /*
63*2621Sllai1  * /dev vfs operations.
64*2621Sllai1  */
65*2621Sllai1 
66*2621Sllai1 /*
67*2621Sllai1  * globals
68*2621Sllai1  */
69*2621Sllai1 struct sdev_data *sdev_origins; /* mount info for origins under /dev */
70*2621Sllai1 
71*2621Sllai1 /*
72*2621Sllai1  * static
73*2621Sllai1  */
74*2621Sllai1 static kmutex_t sdev_lock;	/* protects global data */
75*2621Sllai1 static major_t devmajor;	/* the fictitious major we live on */
76*2621Sllai1 static major_t devminor;	/* the fictitious minor of this instance */
77*2621Sllai1 static struct sdev_data *sdev_mntinfo = NULL;	/* linked list of instances */
78*2621Sllai1 static struct vnode *sdev_stale_attrvp; /* stale root attrvp after remount */
79*2621Sllai1 static int sdev_mntinfo_cnt;	/* mntinfo reference count */
80*2621Sllai1 
81*2621Sllai1 static int sdev_mount(struct vfs *, struct vnode *, struct mounta *,
82*2621Sllai1     struct cred *);
83*2621Sllai1 static int sdev_unmount(struct vfs *, int, struct cred *);
84*2621Sllai1 static int sdev_root(struct vfs *, struct vnode **);
85*2621Sllai1 static int sdev_statvfs(struct vfs *, struct statvfs64 *);
86*2621Sllai1 static void sdev_insert_mntinfo(struct sdev_data *);
87*2621Sllai1 static int devinit(int, char *);
88*2621Sllai1 
89*2621Sllai1 static vfsdef_t sdev_vfssw = {
90*2621Sllai1 	VFSDEF_VERSION,
91*2621Sllai1 	"dev",		/* type name string */
92*2621Sllai1 	devinit,	/* init routine */
93*2621Sllai1 	VSW_CANREMOUNT,	/* flags */
94*2621Sllai1 	NULL		/* mount options table prototype */
95*2621Sllai1 };
96*2621Sllai1 
97*2621Sllai1 
98*2621Sllai1 /*
99*2621Sllai1  * Module linkage information
100*2621Sllai1  */
101*2621Sllai1 static struct modlfs modlfs = {
102*2621Sllai1 	&mod_fsops, "/dev filesystem %I%", &sdev_vfssw
103*2621Sllai1 };
104*2621Sllai1 
105*2621Sllai1 static struct modlinkage modlinkage = {
106*2621Sllai1 	MODREV_1, (void *)&modlfs, NULL
107*2621Sllai1 };
108*2621Sllai1 
109*2621Sllai1 int
110*2621Sllai1 _init(void)
111*2621Sllai1 {
112*2621Sllai1 	int e;
113*2621Sllai1 
114*2621Sllai1 	mutex_init(&sdev_lock, NULL, MUTEX_DEFAULT, NULL);
115*2621Sllai1 	sdev_node_cache_init();
116*2621Sllai1 	sdev_devfsadm_lockinit();
117*2621Sllai1 	if ((e = mod_install(&modlinkage)) != 0) {
118*2621Sllai1 		sdev_devfsadm_lockdestroy();
119*2621Sllai1 		sdev_node_cache_fini();
120*2621Sllai1 		mutex_destroy(&sdev_lock);
121*2621Sllai1 		return (e);
122*2621Sllai1 	}
123*2621Sllai1 	return (0);
124*2621Sllai1 }
125*2621Sllai1 
126*2621Sllai1 /*
127*2621Sllai1  * dev module remained loaded for the global /dev instance
128*2621Sllai1  */
129*2621Sllai1 int
130*2621Sllai1 _fini(void)
131*2621Sllai1 {
132*2621Sllai1 	return (EBUSY);
133*2621Sllai1 }
134*2621Sllai1 
135*2621Sllai1 int
136*2621Sllai1 _info(struct modinfo *modinfop)
137*2621Sllai1 {
138*2621Sllai1 	return (mod_info(&modlinkage, modinfop));
139*2621Sllai1 }
140*2621Sllai1 
141*2621Sllai1 /*ARGSUSED*/
142*2621Sllai1 static int
143*2621Sllai1 devinit(int fstype, char *name)
144*2621Sllai1 {
145*2621Sllai1 	static const fs_operation_def_t dev_vfsops_tbl[] = {
146*2621Sllai1 		VFSNAME_MOUNT, sdev_mount,	/* mount file system */
147*2621Sllai1 		VFSNAME_UNMOUNT, sdev_unmount,	/* unmount file system */
148*2621Sllai1 		VFSNAME_ROOT, sdev_root,	/* get root vnode */
149*2621Sllai1 		VFSNAME_STATVFS, sdev_statvfs,	/* get file system statistics */
150*2621Sllai1 		NULL, NULL
151*2621Sllai1 	};
152*2621Sllai1 
153*2621Sllai1 	int	error;
154*2621Sllai1 	extern major_t getudev(void);
155*2621Sllai1 
156*2621Sllai1 	devtype = fstype;
157*2621Sllai1 
158*2621Sllai1 	error = vfs_setfsops(fstype, dev_vfsops_tbl, NULL);
159*2621Sllai1 	if (error != 0) {
160*2621Sllai1 		cmn_err(CE_WARN, "devinit: bad vfs ops tbl");
161*2621Sllai1 		return (error);
162*2621Sllai1 	}
163*2621Sllai1 
164*2621Sllai1 	error = vn_make_ops("dev", sdev_vnodeops_tbl, &sdev_vnodeops);
165*2621Sllai1 	if (error != 0) {
166*2621Sllai1 		(void) vfs_freevfsops_by_type(fstype);
167*2621Sllai1 		cmn_err(CE_WARN, "devinit: bad vnode ops tbl");
168*2621Sllai1 		return (error);
169*2621Sllai1 	}
170*2621Sllai1 
171*2621Sllai1 	if ((devmajor = getudev()) == (major_t)-1) {
172*2621Sllai1 		cmn_err(CE_WARN, "%s: can't get unique dev", sdev_vfssw.name);
173*2621Sllai1 		return (1);
174*2621Sllai1 	}
175*2621Sllai1 
176*2621Sllai1 	/* initialize negative cache */
177*2621Sllai1 	sdev_ncache_init();
178*2621Sllai1 
179*2621Sllai1 	return (0);
180*2621Sllai1 }
181*2621Sllai1 
182*2621Sllai1 /*
183*2621Sllai1  * Both mount point and backing store directory name are
184*2621Sllai1  * passed in from userland
185*2621Sllai1  */
186*2621Sllai1 static int
187*2621Sllai1 sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
188*2621Sllai1     struct cred *cr)
189*2621Sllai1 {
190*2621Sllai1 	struct sdev_data *sdev_data;
191*2621Sllai1 	struct vnode *avp;
192*2621Sllai1 	struct sdev_node *dv;
193*2621Sllai1 	struct sdev_mountargs *args = NULL;
194*2621Sllai1 	int	error = 0;
195*2621Sllai1 	dev_t	devdev;
196*2621Sllai1 
197*2621Sllai1 	/*
198*2621Sllai1 	 * security check
199*2621Sllai1 	 */
200*2621Sllai1 	if ((secpolicy_fs_mount(cr, mvp, vfsp) != 0) ||
201*2621Sllai1 	    (secpolicy_sys_devices(cr) != 0))
202*2621Sllai1 		return (EPERM);
203*2621Sllai1 
204*2621Sllai1 	/*
205*2621Sllai1 	 * Sanity check the mount point
206*2621Sllai1 	 */
207*2621Sllai1 	if (mvp->v_type != VDIR)
208*2621Sllai1 		return (ENOTDIR);
209*2621Sllai1 
210*2621Sllai1 	/*
211*2621Sllai1 	 * Sanity Check for overlay mount.
212*2621Sllai1 	 */
213*2621Sllai1 	mutex_enter(&mvp->v_lock);
214*2621Sllai1 	if ((uap->flags & MS_OVERLAY) == 0 &&
215*2621Sllai1 	    (uap->flags & MS_REMOUNT) == 0 &&
216*2621Sllai1 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT))) {
217*2621Sllai1 		mutex_exit(&mvp->v_lock);
218*2621Sllai1 		return (EBUSY);
219*2621Sllai1 	}
220*2621Sllai1 	mutex_exit(&mvp->v_lock);
221*2621Sllai1 
222*2621Sllai1 	args = kmem_zalloc(sizeof (*args), KM_SLEEP);
223*2621Sllai1 
224*2621Sllai1 	if ((uap->flags & MS_DATA) &&
225*2621Sllai1 	    (uap->datalen != 0 && uap->dataptr != NULL)) {
226*2621Sllai1 		/* copy in the arguments */
227*2621Sllai1 		if (error = sdev_copyin_mountargs(uap, args))
228*2621Sllai1 			goto cleanup;
229*2621Sllai1 	}
230*2621Sllai1 
231*2621Sllai1 	/*
232*2621Sllai1 	 * Sanity check the backing store
233*2621Sllai1 	 */
234*2621Sllai1 	if (args->sdev_attrdir) {
235*2621Sllai1 		/* user supplied an attribute store */
236*2621Sllai1 		if (error = lookupname((char *)(uintptr_t)args->sdev_attrdir,
237*2621Sllai1 		    UIO_USERSPACE, FOLLOW, NULLVPP, &avp)) {
238*2621Sllai1 			cmn_err(CE_NOTE, "/dev fs: lookup on attribute "
239*2621Sllai1 			    "directory %s failed",
240*2621Sllai1 			    (char *)(uintptr_t)args->sdev_attrdir);
241*2621Sllai1 			goto cleanup;
242*2621Sllai1 		}
243*2621Sllai1 
244*2621Sllai1 		if (avp->v_type != VDIR) {
245*2621Sllai1 			VN_RELE(avp);
246*2621Sllai1 			error = ENOTDIR;
247*2621Sllai1 			goto cleanup;
248*2621Sllai1 		}
249*2621Sllai1 	} else {
250*2621Sllai1 		/* use mountp as the attribute store */
251*2621Sllai1 		avp = mvp;
252*2621Sllai1 		VN_HOLD(avp);
253*2621Sllai1 	}
254*2621Sllai1 
255*2621Sllai1 	mutex_enter(&sdev_lock);
256*2621Sllai1 
257*2621Sllai1 	/*
258*2621Sllai1 	 * handling installation
259*2621Sllai1 	 */
260*2621Sllai1 	if (uap->flags & MS_REMOUNT) {
261*2621Sllai1 		sdev_data = (struct sdev_data *)vfsp->vfs_data;
262*2621Sllai1 		ASSERT(sdev_data);
263*2621Sllai1 
264*2621Sllai1 		dv = sdev_data->sdev_root;
265*2621Sllai1 		ASSERT(dv == dv->sdev_dotdot);
266*2621Sllai1 
267*2621Sllai1 		/*
268*2621Sllai1 		 * mark all existing sdev_nodes (except root node) stale
269*2621Sllai1 		 */
270*2621Sllai1 		sdev_stale(dv);
271*2621Sllai1 
272*2621Sllai1 		/* Reset previous mountargs */
273*2621Sllai1 		if (sdev_data->sdev_mountargs) {
274*2621Sllai1 			kmem_free(sdev_data->sdev_mountargs,
275*2621Sllai1 			    sizeof (struct sdev_mountargs));
276*2621Sllai1 		}
277*2621Sllai1 		sdev_data->sdev_mountargs = args;
278*2621Sllai1 		args = NULL;		/* so it won't be freed below */
279*2621Sllai1 
280*2621Sllai1 		sdev_stale_attrvp = dv->sdev_attrvp;
281*2621Sllai1 		dv->sdev_attrvp = avp;
282*2621Sllai1 		vfsp->vfs_mtime = ddi_get_time();
283*2621Sllai1 
284*2621Sllai1 		mutex_exit(&sdev_lock);
285*2621Sllai1 		goto cleanup;				/* we're done */
286*2621Sllai1 	}
287*2621Sllai1 
288*2621Sllai1 	/*
289*2621Sllai1 	 * Create and initialize the vfs-private data.
290*2621Sllai1 	 */
291*2621Sllai1 	devdev = makedevice(devmajor, devminor);
292*2621Sllai1 	while (vfs_devismounted(devdev)) {
293*2621Sllai1 		devminor = (devminor + 1) & MAXMIN32;
294*2621Sllai1 
295*2621Sllai1 		/*
296*2621Sllai1 		 * All the minor numbers are used up.
297*2621Sllai1 		 */
298*2621Sllai1 		if (devminor == 0) {
299*2621Sllai1 			mutex_exit(&sdev_lock);
300*2621Sllai1 			VN_RELE(avp);
301*2621Sllai1 			error = ENODEV;
302*2621Sllai1 			goto cleanup;
303*2621Sllai1 		}
304*2621Sllai1 
305*2621Sllai1 		devdev = makedevice(devmajor, devminor);
306*2621Sllai1 	}
307*2621Sllai1 
308*2621Sllai1 	dv = sdev_mkroot(vfsp, devdev, mvp, avp, cr);
309*2621Sllai1 	sdev_data = kmem_zalloc(sizeof (struct sdev_data), KM_SLEEP);
310*2621Sllai1 	vfsp->vfs_dev = devdev;
311*2621Sllai1 	vfsp->vfs_data = (caddr_t)sdev_data;
312*2621Sllai1 	vfsp->vfs_fstype = devtype;
313*2621Sllai1 	vfsp->vfs_bsize = DEV_BSIZE;
314*2621Sllai1 	vfsp->vfs_mtime = ddi_get_time();
315*2621Sllai1 	vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, devtype);
316*2621Sllai1 
317*2621Sllai1 	ASSERT(dv == dv->sdev_dotdot);
318*2621Sllai1 
319*2621Sllai1 	sdev_data->sdev_vfsp = vfsp;
320*2621Sllai1 	sdev_data->sdev_root = dv;
321*2621Sllai1 	sdev_data->sdev_mountargs = args;
322*2621Sllai1 
323*2621Sllai1 	/* get acl flavor from attribute dir */
324*2621Sllai1 	if (VOP_PATHCONF(avp, _PC_ACL_ENABLED, &sdev_data->sdev_acl_flavor,
325*2621Sllai1 	    kcred) != 0 || sdev_data->sdev_acl_flavor == 0)
326*2621Sllai1 		sdev_data->sdev_acl_flavor = _ACL_ACLENT_ENABLED;
327*2621Sllai1 
328*2621Sllai1 	args = NULL;			/* so it won't be freed below */
329*2621Sllai1 	sdev_insert_mntinfo(sdev_data);
330*2621Sllai1 	mutex_exit(&sdev_lock);
331*2621Sllai1 
332*2621Sllai1 	if (!SDEV_IS_GLOBAL(dv)) {
333*2621Sllai1 		ASSERT(sdev_origins);
334*2621Sllai1 		dv->sdev_flags &= ~SDEV_GLOBAL;
335*2621Sllai1 		dv->sdev_origin = sdev_origins->sdev_root;
336*2621Sllai1 	} else {
337*2621Sllai1 		sdev_ncache_setup();
338*2621Sllai1 	}
339*2621Sllai1 
340*2621Sllai1 	sdev_update_timestamps(dv->sdev_attrvp,
341*2621Sllai1 		cr, AT_CTIME|AT_MTIME|AT_ATIME);
342*2621Sllai1 
343*2621Sllai1 cleanup:
344*2621Sllai1 	if (args)
345*2621Sllai1 		kmem_free(args, sizeof (*args));
346*2621Sllai1 	return (error);
347*2621Sllai1 }
348*2621Sllai1 
349*2621Sllai1 /*
350*2621Sllai1  * unmounting the non-global /dev instances, e.g. when deleting a Kevlar zone.
351*2621Sllai1  */
352*2621Sllai1 static int
353*2621Sllai1 sdev_unmount(struct vfs *vfsp, int flag, struct cred *cr)
354*2621Sllai1 {
355*2621Sllai1 	struct sdev_node *dv;
356*2621Sllai1 	int error;
357*2621Sllai1 	struct sdev_data *sdev_data, *prev, *next;
358*2621Sllai1 
359*2621Sllai1 	/*
360*2621Sllai1 	 * enforce the security policies
361*2621Sllai1 	 */
362*2621Sllai1 	if ((secpolicy_fs_unmount(cr, vfsp) != 0) ||
363*2621Sllai1 	    (secpolicy_sys_devices(cr) != 0))
364*2621Sllai1 		return (EPERM);
365*2621Sllai1 
366*2621Sllai1 	if (flag & MS_FORCE)
367*2621Sllai1 		return (ENOTSUP);
368*2621Sllai1 
369*2621Sllai1 	mutex_enter(&sdev_lock);
370*2621Sllai1 	dv = VFSTOSDEVFS(vfsp)->sdev_root;
371*2621Sllai1 	ASSERT(dv == dv->sdev_dotdot);
372*2621Sllai1 	if (SDEVTOV(dv)->v_count > 1) {
373*2621Sllai1 		mutex_exit(&sdev_lock);
374*2621Sllai1 		return (EBUSY);
375*2621Sllai1 	}
376*2621Sllai1 
377*2621Sllai1 	/*
378*2621Sllai1 	 * global instance remains mounted
379*2621Sllai1 	 */
380*2621Sllai1 	if (SDEV_IS_GLOBAL(dv)) {
381*2621Sllai1 		mutex_exit(&sdev_lock);
382*2621Sllai1 		return (EBUSY);
383*2621Sllai1 	}
384*2621Sllai1 	mutex_exit(&sdev_lock);
385*2621Sllai1 
386*2621Sllai1 	/* verify the v_count */
387*2621Sllai1 	if ((error = sdev_cleandir(dv, NULL, 0)) != 0) {
388*2621Sllai1 		return (error);
389*2621Sllai1 	}
390*2621Sllai1 	ASSERT(SDEVTOV(dv)->v_count == 1);
391*2621Sllai1 
392*2621Sllai1 	/* release hold on root node and destroy it */
393*2621Sllai1 	SDEV_RELE(dv);
394*2621Sllai1 	dv->sdev_nlink -= 2;
395*2621Sllai1 	sdev_nodedestroy(dv, 0);
396*2621Sllai1 
397*2621Sllai1 	sdev_data = (struct sdev_data *)vfsp->vfs_data;
398*2621Sllai1 	vfsp->vfs_data = (caddr_t)0;
399*2621Sllai1 
400*2621Sllai1 	/*
401*2621Sllai1 	 * XXX separate it into sdev_delete_mntinfo() if useful
402*2621Sllai1 	 */
403*2621Sllai1 	mutex_enter(&sdev_lock);
404*2621Sllai1 	prev = sdev_data->sdev_prev;
405*2621Sllai1 	next = sdev_data->sdev_next;
406*2621Sllai1 	if (prev)
407*2621Sllai1 		prev->sdev_next = next;
408*2621Sllai1 	else
409*2621Sllai1 		sdev_mntinfo = next;
410*2621Sllai1 	if (next)
411*2621Sllai1 		next->sdev_prev = prev;
412*2621Sllai1 	mutex_exit(&sdev_lock);
413*2621Sllai1 
414*2621Sllai1 	if (sdev_data->sdev_mountargs) {
415*2621Sllai1 		kmem_free(sdev_data->sdev_mountargs,
416*2621Sllai1 		    sizeof (struct sdev_mountargs));
417*2621Sllai1 	}
418*2621Sllai1 	kmem_free(sdev_data, sizeof (struct sdev_data));
419*2621Sllai1 	return (0);
420*2621Sllai1 }
421*2621Sllai1 
422*2621Sllai1 /*
423*2621Sllai1  * return root vnode for given vfs
424*2621Sllai1  */
425*2621Sllai1 static int
426*2621Sllai1 sdev_root(struct vfs *vfsp, struct vnode **vpp)
427*2621Sllai1 {
428*2621Sllai1 	*vpp = SDEVTOV(VFSTOSDEVFS(vfsp)->sdev_root);
429*2621Sllai1 	VN_HOLD(*vpp);
430*2621Sllai1 	return (0);
431*2621Sllai1 }
432*2621Sllai1 
433*2621Sllai1 /*
434*2621Sllai1  * return 'generic superblock' information to userland.
435*2621Sllai1  *
436*2621Sllai1  * not much that we can usefully admit to here
437*2621Sllai1  */
438*2621Sllai1 static int
439*2621Sllai1 sdev_statvfs(struct vfs *vfsp, struct statvfs64 *sbp)
440*2621Sllai1 {
441*2621Sllai1 	dev32_t d32;
442*2621Sllai1 
443*2621Sllai1 	bzero(sbp, sizeof (*sbp));
444*2621Sllai1 	sbp->f_frsize = sbp->f_bsize = vfsp->vfs_bsize;
445*2621Sllai1 	sbp->f_files = kmem_cache_stat(sdev_node_cache, "alloc");
446*2621Sllai1 
447*2621Sllai1 	/* no illusions that free/avail files is relevant to dev */
448*2621Sllai1 	sbp->f_ffree = 0;
449*2621Sllai1 	sbp->f_favail = 0;
450*2621Sllai1 
451*2621Sllai1 	/* no illusions that blocks are relevant to devfs */
452*2621Sllai1 	sbp->f_bfree = 0;
453*2621Sllai1 	sbp->f_bavail = 0;
454*2621Sllai1 	sbp->f_blocks = 0;
455*2621Sllai1 
456*2621Sllai1 	(void) cmpldev(&d32, vfsp->vfs_dev);
457*2621Sllai1 	sbp->f_fsid = d32;
458*2621Sllai1 	(void) strcpy(sbp->f_basetype, vfssw[devtype].vsw_name);
459*2621Sllai1 	sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
460*2621Sllai1 	sbp->f_namemax = MAXNAMELEN - 1;
461*2621Sllai1 	(void) strcpy(sbp->f_fstr, "dev");
462*2621Sllai1 
463*2621Sllai1 	return (0);
464*2621Sllai1 }
465*2621Sllai1 
466*2621Sllai1 int
467*2621Sllai1 sdev_module_register(char *mod_name, struct devname_ops *dev_ops)
468*2621Sllai1 {
469*2621Sllai1 	struct devname_nsmap *map = NULL;
470*2621Sllai1 
471*2621Sllai1 	if (strcmp(mod_name, DEVNAME_NSCONFIG) == 0) {
472*2621Sllai1 		devname_ns_ops = dev_ops;
473*2621Sllai1 		return (0);
474*2621Sllai1 	}
475*2621Sllai1 
476*2621Sllai1 	map = sdev_get_nsmap_by_module(mod_name);
477*2621Sllai1 	if (map == NULL)
478*2621Sllai1 		return (EFAULT);
479*2621Sllai1 
480*2621Sllai1 	rw_enter(&map->dir_lock, RW_WRITER);
481*2621Sllai1 	map->dir_ops = dev_ops;
482*2621Sllai1 	rw_exit(&map->dir_lock);
483*2621Sllai1 	return (0);
484*2621Sllai1 }
485*2621Sllai1 
486*2621Sllai1 static void
487*2621Sllai1 sdev_insert_mntinfo(struct sdev_data *data)
488*2621Sllai1 {
489*2621Sllai1 	ASSERT(mutex_owned(&sdev_lock));
490*2621Sllai1 	data->sdev_next = sdev_mntinfo;
491*2621Sllai1 	data->sdev_prev = NULL;
492*2621Sllai1 	if (sdev_mntinfo) {
493*2621Sllai1 		sdev_mntinfo->sdev_prev = data;
494*2621Sllai1 	} else {
495*2621Sllai1 		sdev_origins = data;
496*2621Sllai1 	}
497*2621Sllai1 	sdev_mntinfo = data;
498*2621Sllai1 }
499*2621Sllai1 
500*2621Sllai1 struct sdev_data *
501*2621Sllai1 sdev_find_mntinfo(char *mntpt)
502*2621Sllai1 {
503*2621Sllai1 	struct sdev_data *mntinfo;
504*2621Sllai1 
505*2621Sllai1 	mutex_enter(&sdev_lock);
506*2621Sllai1 	mntinfo = sdev_mntinfo;
507*2621Sllai1 	while (mntinfo) {
508*2621Sllai1 		if (strcmp(mntpt, mntinfo->sdev_root->sdev_name) == 0) {
509*2621Sllai1 			SDEVTOV(mntinfo->sdev_root)->v_count++;
510*2621Sllai1 			break;
511*2621Sllai1 		}
512*2621Sllai1 		mntinfo = mntinfo->sdev_next;
513*2621Sllai1 	}
514*2621Sllai1 	mutex_exit(&sdev_lock);
515*2621Sllai1 	return (mntinfo);
516*2621Sllai1 }
517*2621Sllai1 
518*2621Sllai1 void
519*2621Sllai1 sdev_mntinfo_rele(struct sdev_data *mntinfo)
520*2621Sllai1 {
521*2621Sllai1 	mutex_enter(&sdev_lock);
522*2621Sllai1 	SDEVTOV(mntinfo->sdev_root)->v_count--;
523*2621Sllai1 	mutex_exit(&sdev_lock);
524*2621Sllai1 }
525