xref: /titanic_44/usr/src/uts/common/fs/namefs/namevfs.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI" /* from S5R4 1.28 */
32 
33 /*
34  * This file supports the vfs operations for the NAMEFS file system.
35  */
36 
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/debug.h>
41 #include <sys/errno.h>
42 #include <sys/kmem.h>
43 #include <sys/inline.h>
44 #include <sys/file.h>
45 #include <sys/proc.h>
46 #include <sys/stat.h>
47 #include <sys/statvfs.h>
48 #include <sys/mount.h>
49 #include <sys/sysmacros.h>
50 #include <sys/var.h>
51 #include <sys/vfs.h>
52 #include <sys/vnode.h>
53 #include <sys/mode.h>
54 #include <sys/pcb.h>
55 #include <sys/signal.h>
56 #include <sys/user.h>
57 #include <sys/uio.h>
58 #include <sys/cred.h>
59 #include <sys/fs/namenode.h>
60 #include <sys/stream.h>
61 #include <sys/strsubr.h>
62 #include <sys/cmn_err.h>
63 #include <sys/modctl.h>
64 #include <fs/fs_subr.h>
65 #include <sys/policy.h>
66 #include <sys/vmem.h>
67 
68 #define	NM_INOQUANT		(64 * 1024)
69 
70 /*
71  * Define global data structures.
72  */
73 dev_t	namedev;
74 int	namefstype;
75 struct	namenode *nm_filevp_hash[NM_FILEVP_HASH_SIZE];
76 struct	vfs namevfs;
77 kmutex_t ntable_lock;
78 
79 static vmem_t	*nm_inoarena;	/* vmem arena to allocate inode no's from */
80 static kmutex_t	nm_inolock;
81 
82 /*
83  * Functions to allocate node id's starting from 1. Based on vmem routines.
84  * The vmem arena is extended in NM_INOQUANT chunks.
85  */
86 uint64_t
87 namenodeno_alloc(void)
88 {
89 	uint64_t nno;
90 
91 	mutex_enter(&nm_inolock);
92 	nno = (uint64_t)(uintptr_t)
93 	    vmem_alloc(nm_inoarena, 1, VM_NOSLEEP + VM_FIRSTFIT);
94 	if (nno == 0) {
95 		(void) vmem_add(nm_inoarena, (void *)(vmem_size(nm_inoarena,
96 		    VMEM_ALLOC | VMEM_FREE) + 1), NM_INOQUANT, VM_SLEEP);
97 		nno = (uint64_t)(uintptr_t)
98 		    vmem_alloc(nm_inoarena, 1, VM_SLEEP + VM_FIRSTFIT);
99 		ASSERT(nno != 0);
100 	}
101 	mutex_exit(&nm_inolock);
102 	ASSERT32(nno <= ULONG_MAX);
103 	return (nno);
104 }
105 
106 static void
107 namenodeno_init(void)
108 {
109 	nm_inoarena = vmem_create("namefs_inodes", (void *)1, NM_INOQUANT, 1,
110 	    NULL, NULL, NULL, 1, VM_SLEEP);
111 	mutex_init(&nm_inolock, NULL, MUTEX_DEFAULT, NULL);
112 }
113 
114 void
115 namenodeno_free(uint64_t nn)
116 {
117 	void *vaddr = (void *)(uintptr_t)nn;
118 
119 	ASSERT32((uint64_t)(uintptr_t)vaddr == nn);
120 
121 	mutex_enter(&nm_inolock);
122 	vmem_free(nm_inoarena, vaddr, 1);
123 	mutex_exit(&nm_inolock);
124 }
125 
126 /*
127  * Insert a namenode into the nm_filevp_hash table.
128  *
129  * Each link has a unique namenode with a unique nm_mountvp field.
130  * The nm_filevp field of the namenode need not be unique, since a
131  * file descriptor may be mounted to multiple nodes at the same time.
132  * We hash on nm_filevp since that's what discriminates the searches
133  * in namefind() and nm_unmountall().
134  */
135 void
136 nameinsert(struct namenode *nodep)
137 {
138 	struct namenode **bucket;
139 
140 	ASSERT(MUTEX_HELD(&ntable_lock));
141 
142 	bucket = NM_FILEVP_HASH(nodep->nm_filevp);
143 	nodep->nm_nextp = *bucket;
144 	*bucket = nodep;
145 }
146 
147 /*
148  * Remove a namenode from the hash table, if present.
149  */
150 void
151 nameremove(struct namenode *nodep)
152 {
153 	struct namenode *np, **npp;
154 
155 	ASSERT(MUTEX_HELD(&ntable_lock));
156 
157 	for (npp = NM_FILEVP_HASH(nodep->nm_filevp); (np = *npp) != NULL;
158 	    npp = &np->nm_nextp) {
159 		if (np == nodep) {
160 			*npp = np->nm_nextp;
161 			return;
162 		}
163 	}
164 }
165 
166 /*
167  * Search for a namenode that has a nm_filevp == vp and nm_mountpt == mnt.
168  * If mnt is NULL, return the first link with nm_filevp of vp.
169  * Returns namenode pointer on success, NULL on failure.
170  */
171 struct namenode *
172 namefind(vnode_t *vp, vnode_t *mnt)
173 {
174 	struct namenode *np;
175 
176 	ASSERT(MUTEX_HELD(&ntable_lock));
177 	for (np = *NM_FILEVP_HASH(vp); np != NULL; np = np->nm_nextp)
178 		if (np->nm_filevp == vp &&
179 		    (mnt == NULL || np->nm_mountpt == mnt))
180 			break;
181 	return (np);
182 }
183 
184 /*
185  * Force the unmouting of a file descriptor from ALL of the nodes
186  * that it was mounted to.
187  * At the present time, the only usage for this routine is in the
188  * event one end of a pipe was mounted. At the time the unmounted
189  * end gets closed down, the mounted end is forced to be unmounted.
190  *
191  * This routine searches the namenode hash list for all namenodes
192  * that have a nm_filevp field equal to vp. Each time one is found,
193  * the dounmount() routine is called. This causes the nm_unmount()
194  * routine to be called and thus, the file descriptor is unmounted
195  * from the node.
196  *
197  * At the start of this routine, the reference count for vp is
198  * incremented to protect the vnode from being released in the
199  * event the mount was the only thing keeping the vnode active.
200  * If that is the case, the VOP_CLOSE operation is applied to
201  * the vnode, prior to it being released.
202  */
203 static int
204 nm_umountall(vnode_t *vp, cred_t *crp)
205 {
206 	vfs_t *vfsp;
207 	struct namenode *nodep;
208 	int error = 0;
209 	int realerr = 0;
210 
211 	/*
212 	 * For each namenode that is associated with the file:
213 	 * If the v_vfsp field is not namevfs, dounmount it.  Otherwise,
214 	 * it was created in nm_open() and will be released in time.
215 	 * The following loop replicates some code from nm_find.  That
216 	 * routine can't be used as is since the list isn't strictly
217 	 * consumed as it is traversed.
218 	 */
219 	mutex_enter(&ntable_lock);
220 	nodep = *NM_FILEVP_HASH(vp);
221 	while (nodep) {
222 		if (nodep->nm_filevp == vp &&
223 		    (vfsp = NMTOV(nodep)->v_vfsp) != NULL && vfsp != &namevfs) {
224 
225 			/*
226 			 * If the vn_vfswlock fails, skip the vfs since
227 			 * somebody else may be unmounting it.
228 			 */
229 			if (vn_vfswlock(vfsp->vfs_vnodecovered)) {
230 				realerr = EBUSY;
231 				nodep = nodep->nm_nextp;
232 				continue;
233 			}
234 
235 			/*
236 			 * Can't hold ntable_lock across call to do_unmount
237 			 * because nm_unmount tries to acquire it.  This means
238 			 * there is a window where another mount of vp can
239 			 * happen so it is possible that after nm_unmountall
240 			 * there are still some mounts.  This situation existed
241 			 * without MT locking because dounmount can sleep
242 			 * so another mount could happen during that time.
243 			 * This situation is unlikely and doesn't really cause
244 			 * any problems.
245 			 */
246 			mutex_exit(&ntable_lock);
247 			if ((error = dounmount(vfsp, 0, crp)) != 0)
248 				realerr = error;
249 			mutex_enter(&ntable_lock);
250 			/*
251 			 * Since we dropped the ntable_lock, we
252 			 * have to start over from the beginning.
253 			 * If for some reasons dounmount() fails,
254 			 * start from beginning means that we will keep on
255 			 * trying unless another thread unmounts it for us.
256 			 */
257 			nodep = *NM_FILEVP_HASH(vp);
258 		} else
259 			nodep = nodep->nm_nextp;
260 	}
261 	mutex_exit(&ntable_lock);
262 	return (realerr);
263 }
264 
265 /*
266  * Force the unmouting of a file descriptor from ALL of the nodes
267  * that it was mounted to.  XXX: fifo_close() calls this routine.
268  *
269  * nm_umountall() may return EBUSY.
270  * nm_unmountall() will keep on trying until it succeeds.
271  */
272 int
273 nm_unmountall(vnode_t *vp, cred_t *crp)
274 {
275 	int error;
276 
277 	/*
278 	 * Nm_umuontall() returns only if it succeeds or
279 	 * return with error EBUSY.  If EBUSY, that means
280 	 * it cannot acquire the lock on the covered vnode,
281 	 * and we will keep on trying.
282 	 */
283 	for (;;) {
284 		error = nm_umountall(vp, crp);
285 		if (error != EBUSY)
286 			break;
287 		delay(1);	/* yield cpu briefly, then try again */
288 	}
289 	return (error);
290 }
291 
292 /*
293  * Mount a file descriptor onto the node in the file system.
294  * Create a new vnode, update the attributes with info from the
295  * file descriptor and the mount point.  The mask, mode, uid, gid,
296  * atime, mtime and ctime are taken from the mountpt.  Link count is
297  * set to one, the file system id is namedev and nodeid is unique
298  * for each mounted object.  Other attributes are taken from mount point.
299  * Make sure user is owner (or root) with write permissions on mount point.
300  * Hash the new vnode and return 0.
301  * Upon entry to this routine, the file descriptor is in the
302  * fd field of a struct namefd.  Copy that structure from user
303  * space and retrieve the file descriptor.
304  */
305 static int
306 nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
307 {
308 	struct namefd namefdp;
309 	struct vnode *filevp;		/* file descriptor vnode */
310 	struct file *fp;
311 	struct vnode *newvp;		/* vnode representing this mount */
312 	struct namenode *nodep;		/* namenode for this mount */
313 	struct vattr filevattr;		/* attributes of file dec.  */
314 	struct vattr *vattrp;		/* attributes of this mount */
315 	char *resource_name;
316 	char *resource_nodetype;
317 	statvfs64_t *svfsp;
318 	int error = 0;
319 
320 	/*
321 	 * Get the file descriptor from user space.
322 	 * Make sure the file descriptor is valid and has an
323 	 * associated file pointer.
324 	 * If so, extract the vnode from the file pointer.
325 	 */
326 	if (uap->datalen != sizeof (struct namefd))
327 		return (EINVAL);
328 
329 	if (copyin(uap->dataptr, &namefdp, uap->datalen))
330 		return (EFAULT);
331 
332 	if ((fp = getf(namefdp.fd)) == NULL)
333 		return (EBADF);
334 
335 	/*
336 	 * If the mount point already has something mounted
337 	 * on it, disallow this mount.  (This restriction may
338 	 * be removed in a later release).
339 	 * Or unmount has completed but the namefs ROOT vnode
340 	 * count has not decremented to zero, disallow this mount.
341 	 */
342 	mutex_enter(&mvp->v_lock);
343 	if ((mvp->v_flag & VROOT) || (mvp->v_vfsp == &namevfs)) {
344 		mutex_exit(&mvp->v_lock);
345 		releasef(namefdp.fd);
346 		return (EBUSY);
347 	}
348 	mutex_exit(&mvp->v_lock);
349 
350 	filevp = fp->f_vnode;
351 	if (filevp->v_type == VDIR || filevp->v_type == VPORT) {
352 		releasef(namefdp.fd);
353 		return (EINVAL);
354 	}
355 
356 	/*
357 	 * If the fd being mounted refers to neither a door nor a stream,
358 	 * make sure the caller is privileged.
359 	 */
360 	if (filevp->v_type != VDOOR && filevp->v_stream == NULL) {
361 		if (secpolicy_fs_mount(crp, filevp, vfsp) != 0) {
362 			/* fd is neither a stream nor a door */
363 			releasef(namefdp.fd);
364 			return (EINVAL);
365 		}
366 	}
367 
368 	/*
369 	 * Make sure the file descriptor is not the root of some
370 	 * file system.
371 	 * If it's not, create a reference and allocate a namenode
372 	 * to represent this mount request.
373 	 */
374 	if (filevp->v_flag & VROOT) {
375 		releasef(namefdp.fd);
376 		return (EBUSY);
377 	}
378 
379 	nodep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);
380 
381 	mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
382 	vattrp = &nodep->nm_vattr;
383 	vattrp->va_mask = AT_ALL;
384 	if (error = VOP_GETATTR(mvp, vattrp, 0, crp))
385 		goto out;
386 
387 	filevattr.va_mask = AT_ALL;
388 	if (error = VOP_GETATTR(filevp, &filevattr, 0, crp))
389 		goto out;
390 	/*
391 	 * Make sure the user is the owner of the mount point
392 	 * or has sufficient privileges.
393 	 */
394 	if (error = secpolicy_vnode_owner(crp, vattrp->va_uid))
395 		goto out;
396 
397 	/*
398 	 * Make sure the user has write permissions on the
399 	 * mount point (or has sufficient privileges).
400 	 */
401 	if (!(vattrp->va_mode & VWRITE) &&
402 	    secpolicy_vnode_access(crp, mvp, vattrp->va_uid, VWRITE) != 0) {
403 		error = EACCES;
404 		goto out;
405 	}
406 
407 	/*
408 	 * If the file descriptor has file/record locking, don't
409 	 * allow the mount to succeed.
410 	 */
411 	if (vn_has_flocks(filevp)) {
412 		error = EACCES;
413 		goto out;
414 	}
415 
416 	/*
417 	 * Initialize the namenode.
418 	 */
419 	if (filevp->v_stream) {
420 		struct stdata *stp = filevp->v_stream;
421 		mutex_enter(&stp->sd_lock);
422 		stp->sd_flag |= STRMOUNT;
423 		mutex_exit(&stp->sd_lock);
424 	}
425 	nodep->nm_filevp = filevp;
426 	mutex_enter(&fp->f_tlock);
427 	fp->f_count++;
428 	mutex_exit(&fp->f_tlock);
429 
430 	releasef(namefdp.fd);
431 	nodep->nm_filep = fp;
432 	nodep->nm_mountpt = mvp;
433 
434 	/*
435 	 * The attributes for the mounted file descriptor were initialized
436 	 * above by applying VOP_GETATTR to the mount point.  Some of
437 	 * the fields of the attributes structure will be overwritten
438 	 * by the attributes from the file descriptor.
439 	 */
440 	vattrp->va_type    = filevattr.va_type;
441 	vattrp->va_fsid    = namedev;
442 	vattrp->va_nodeid  = namenodeno_alloc();
443 	vattrp->va_nlink   = 1;
444 	vattrp->va_size    = filevattr.va_size;
445 	vattrp->va_rdev    = filevattr.va_rdev;
446 	vattrp->va_blksize = filevattr.va_blksize;
447 	vattrp->va_nblocks = filevattr.va_nblocks;
448 	vattrp->va_seq	   = 0;
449 
450 	/*
451 	 * Initialize new vnode structure for the mounted file descriptor.
452 	 */
453 	nodep->nm_vnode = vn_alloc(KM_SLEEP);
454 	newvp = NMTOV(nodep);
455 
456 	newvp->v_flag = filevp->v_flag | VROOT | VNOMAP | VNOSWAP;
457 	vn_setops(newvp, nm_vnodeops);
458 	newvp->v_vfsp = vfsp;
459 	newvp->v_stream = filevp->v_stream;
460 	newvp->v_type = filevp->v_type;
461 	newvp->v_rdev = filevp->v_rdev;
462 	newvp->v_data = (caddr_t)nodep;
463 	vn_exists(newvp);
464 
465 	/*
466 	 * Initialize the vfs structure.
467 	 */
468 	vfsp->vfs_vnodecovered = NULL;
469 	vfsp->vfs_flag |= VFS_UNLINKABLE;
470 	vfsp->vfs_bsize = 1024;
471 	vfsp->vfs_fstype = namefstype;
472 	vfs_make_fsid(&vfsp->vfs_fsid, namedev, namefstype);
473 	vfsp->vfs_data = (caddr_t)nodep;
474 	vfsp->vfs_dev = namedev;
475 	vfsp->vfs_bcount = 0;
476 
477 	/*
478 	 * Set the name we mounted from.
479 	 */
480 	switch (filevp->v_type) {
481 	case VPROC:	/* VOP_GETATTR() translates this to VREG */
482 	case VREG:	resource_nodetype = "file"; break;
483 	case VDIR:	resource_nodetype = "directory"; break;
484 	case VBLK:	resource_nodetype = "device"; break;
485 	case VCHR:	resource_nodetype = "device"; break;
486 	case VLNK:	resource_nodetype = "link"; break;
487 	case VFIFO:	resource_nodetype = "fifo"; break;
488 	case VDOOR:	resource_nodetype = "door"; break;
489 	case VSOCK:	resource_nodetype = "socket"; break;
490 	default:	resource_nodetype = "resource"; break;
491 	}
492 
493 #define	RESOURCE_NAME_SZ 128 /* Maximum length of the resource name */
494 	resource_name = kmem_alloc(RESOURCE_NAME_SZ, KM_SLEEP);
495 	svfsp = kmem_alloc(sizeof (statvfs64_t), KM_SLEEP);
496 
497 	error = VFS_STATVFS(filevp->v_vfsp, svfsp);
498 	if (error == 0) {
499 		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
500 		    "unspecified_%s_%s", svfsp->f_basetype, resource_nodetype);
501 	} else {
502 		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
503 		    "unspecified_%s", resource_nodetype);
504 	}
505 
506 	vfs_setresource(vfsp, resource_name);
507 
508 	kmem_free(svfsp, sizeof (statvfs64_t));
509 	kmem_free(resource_name, RESOURCE_NAME_SZ);
510 #undef RESOURCE_NAME_SZ
511 
512 	/*
513 	 * Insert the namenode.
514 	 */
515 	mutex_enter(&ntable_lock);
516 	nameinsert(nodep);
517 	mutex_exit(&ntable_lock);
518 	return (0);
519 out:
520 	releasef(namefdp.fd);
521 	kmem_free(nodep, sizeof (struct namenode));
522 	return (error);
523 }
524 
525 /*
526  * Unmount a file descriptor from a node in the file system.
527  * If the user is not the owner of the file and is not privileged,
528  * the request is denied.
529  * Otherwise, remove the namenode from the hash list.
530  * If the mounted file descriptor was that of a stream and this
531  * was the last mount of the stream, turn off the STRMOUNT flag.
532  * If the rootvp is referenced other than through the mount,
533  * nm_inactive will clean up.
534  */
535 static int
536 nm_unmount(vfs_t *vfsp, int flag, cred_t *crp)
537 {
538 	struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
539 	vnode_t *vp, *thisvp;
540 	struct file *fp = NULL;
541 
542 	ASSERT((nodep->nm_flag & NMNMNT) == 0);
543 
544 	/*
545 	 * forced unmount is not supported by this file system
546 	 * and thus, ENOTSUP, is being returned.
547 	 */
548 	if (flag & MS_FORCE) {
549 		return (ENOTSUP);
550 	}
551 
552 	vp = nodep->nm_filevp;
553 	mutex_enter(&nodep->nm_lock);
554 	if (secpolicy_vnode_owner(crp, nodep->nm_vattr.va_uid) != 0) {
555 		mutex_exit(&nodep->nm_lock);
556 		return (EPERM);
557 	}
558 
559 	mutex_exit(&nodep->nm_lock);
560 
561 	mutex_enter(&ntable_lock);
562 	nameremove(nodep);
563 	thisvp = NMTOV(nodep);
564 	mutex_enter(&thisvp->v_lock);
565 	if (thisvp->v_count-- == 1) {
566 		fp = nodep->nm_filep;
567 		mutex_exit(&thisvp->v_lock);
568 		vn_invalid(thisvp);
569 		vn_free(thisvp);
570 		namenodeno_free(nodep->nm_vattr.va_nodeid);
571 		kmem_free(nodep, sizeof (struct namenode));
572 	} else {
573 		thisvp->v_flag &= ~VROOT;
574 		thisvp->v_vfsp = &namevfs;
575 		mutex_exit(&thisvp->v_lock);
576 	}
577 	if (namefind(vp, NULLVP) == NULL && vp->v_stream) {
578 		struct stdata *stp = vp->v_stream;
579 		mutex_enter(&stp->sd_lock);
580 		stp->sd_flag &= ~STRMOUNT;
581 		mutex_exit(&stp->sd_lock);
582 	}
583 	mutex_exit(&ntable_lock);
584 	if (fp != NULL)
585 		(void) closef(fp);
586 	return (0);
587 }
588 
589 /*
590  * Create a reference to the root of a mounted file descriptor.
591  * This routine is called from lookupname() in the event a path
592  * is being searched that has a mounted file descriptor in it.
593  */
594 static int
595 nm_root(vfs_t *vfsp, vnode_t **vpp)
596 {
597 	struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
598 	struct vnode *vp = NMTOV(nodep);
599 
600 	VN_HOLD(vp);
601 	*vpp = vp;
602 	return (0);
603 }
604 
605 /*
606  * Return in sp the status of this file system.
607  */
608 static int
609 nm_statvfs(vfs_t *vfsp, struct statvfs64 *sp)
610 {
611 	dev32_t d32;
612 
613 	bzero(sp, sizeof (*sp));
614 	sp->f_bsize	= 1024;
615 	sp->f_frsize	= 1024;
616 	(void) cmpldev(&d32, vfsp->vfs_dev);
617 	sp->f_fsid = d32;
618 	(void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
619 	sp->f_flag	= vf_to_stf(vfsp->vfs_flag);
620 	return (0);
621 }
622 
623 /*
624  * Since this file system has no disk blocks of its own, apply
625  * the VOP_FSYNC operation on the mounted file descriptor.
626  */
627 static int
628 nm_sync(vfs_t *vfsp, short flag, cred_t *crp)
629 {
630 	struct namenode *nodep;
631 
632 	if (vfsp == NULL)
633 		return (0);
634 
635 	nodep = (struct namenode *)vfsp->vfs_data;
636 	if (flag & SYNC_CLOSE)
637 		return (nm_umountall(nodep->nm_filevp, crp));
638 
639 	return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp));
640 }
641 
642 /*
643  * File system initialization routine. Save the file system type,
644  * establish a file system device number and initialize nm_filevp_hash[].
645  */
646 int
647 nameinit(int fstype, char *name)
648 {
649 	static const fs_operation_def_t nm_vfsops_template[] = {
650 		VFSNAME_MOUNT, nm_mount,
651 		VFSNAME_UNMOUNT, nm_unmount,
652 		VFSNAME_ROOT, nm_root,
653 		VFSNAME_STATVFS, nm_statvfs,
654 		VFSNAME_SYNC, (fs_generic_func_p) nm_sync,
655 		NULL, NULL
656 	};
657 	static const fs_operation_def_t nm_dummy_vfsops_template[] = {
658 		VFSNAME_STATVFS, nm_statvfs,
659 		VFSNAME_SYNC, (fs_generic_func_p) nm_sync,
660 		NULL, NULL
661 	};
662 	int error;
663 	int dev;
664 	vfsops_t *namefs_vfsops;
665 	vfsops_t *dummy_vfsops;
666 
667 	error = vfs_setfsops(fstype, nm_vfsops_template, &namefs_vfsops);
668 	if (error != 0) {
669 		cmn_err(CE_WARN, "nameinit: bad vfs ops template");
670 		return (error);
671 	}
672 
673 	error = vfs_makefsops(nm_dummy_vfsops_template, &dummy_vfsops);
674 	if (error != 0) {
675 		(void) vfs_freevfsops_by_type(fstype);
676 		cmn_err(CE_WARN, "nameinit: bad dummy vfs ops template");
677 		return (error);
678 	}
679 
680 	error = vn_make_ops(name, nm_vnodeops_template, &nm_vnodeops);
681 	if (error != 0) {
682 		(void) vfs_freevfsops_by_type(fstype);
683 		vfs_freevfsops(dummy_vfsops);
684 		cmn_err(CE_WARN, "nameinit: bad vnode ops template");
685 		return (error);
686 	}
687 
688 	namefstype = fstype;
689 
690 	if ((dev = getudev()) == (major_t)-1) {
691 		cmn_err(CE_WARN, "nameinit: can't get unique device");
692 		dev = 0;
693 	}
694 	mutex_init(&ntable_lock, NULL, MUTEX_DEFAULT, NULL);
695 	namedev = makedevice(dev, 0);
696 	bzero(nm_filevp_hash, sizeof (nm_filevp_hash));
697 	vfs_setops(&namevfs, dummy_vfsops);
698 	namevfs.vfs_vnodecovered = NULL;
699 	namevfs.vfs_bsize = 1024;
700 	namevfs.vfs_fstype = namefstype;
701 	vfs_make_fsid(&namevfs.vfs_fsid, namedev, namefstype);
702 	namevfs.vfs_dev = namedev;
703 	return (0);
704 }
705 
706 static mntopts_t nm_mntopts = {
707 	NULL,
708 	0
709 };
710 
711 static vfsdef_t vfw = {
712 	VFSDEF_VERSION,
713 	"namefs",
714 	nameinit,
715 	VSW_HASPROTO,
716 	&nm_mntopts
717 };
718 
719 /*
720  * Module linkage information for the kernel.
721  */
722 static struct modlfs modlfs = {
723 	&mod_fsops, "filesystem for namefs", &vfw
724 };
725 
726 static struct modlinkage modlinkage = {
727 	MODREV_1, (void *)&modlfs, NULL
728 };
729 
730 int
731 _init(void)
732 {
733 	namenodeno_init();
734 	return (mod_install(&modlinkage));
735 }
736 
737 int
738 _fini(void)
739 {
740 	return (EBUSY);
741 }
742 
743 int
744 _info(struct modinfo *modinfop)
745 {
746 	return (mod_info(&modlinkage, modinfop));
747 }
748