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