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