Home | History | Annotate | Download | only in namefs
      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 2008 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 /*
     31  * This file supports the vfs operations for the NAMEFS file system.
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/debug.h>
     38 #include <sys/errno.h>
     39 #include <sys/kmem.h>
     40 #include <sys/inline.h>
     41 #include <sys/file.h>
     42 #include <sys/proc.h>
     43 #include <sys/stat.h>
     44 #include <sys/statvfs.h>
     45 #include <sys/mount.h>
     46 #include <sys/sysmacros.h>
     47 #include <sys/var.h>
     48 #include <sys/vfs.h>
     49 #include <sys/vfs_opreg.h>
     50 #include <sys/vnode.h>
     51 #include <sys/mode.h>
     52 #include <sys/pcb.h>
     53 #include <sys/signal.h>
     54 #include <sys/user.h>
     55 #include <sys/uio.h>
     56 #include <sys/cred.h>
     57 #include <sys/fs/namenode.h>
     58 #include <sys/stream.h>
     59 #include <sys/strsubr.h>
     60 #include <sys/cmn_err.h>
     61 #include <sys/modctl.h>
     62 #include <fs/fs_subr.h>
     63 #include <sys/policy.h>
     64 #include <sys/vmem.h>
     65 #include <sys/fs/sdev_impl.h>
     66 
     67 #define	NM_INOQUANT		(64 * 1024)
     68 
     69 /*
     70  * Define global data structures.
     71  */
     72 dev_t	namedev;
     73 int	namefstype;
     74 struct	namenode *nm_filevp_hash[NM_FILEVP_HASH_SIZE];
     75 struct	vfs namevfs;
     76 kmutex_t ntable_lock;
     77 
     78 static vmem_t	*nm_inoarena;	/* vmem arena to allocate inode no's from */
     79 static kmutex_t	nm_inolock;
     80 
     81 vfsops_t *namefs_vfsops;
     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 &&
    224 		    vfsp != &namevfs && (NMTOV(nodep)->v_flag & VROOT)) {
    225 
    226 			/*
    227 			 * If the vn_vfswlock fails, skip the vfs since
    228 			 * somebody else may be unmounting it.
    229 			 */
    230 			if (vn_vfswlock(vfsp->vfs_vnodecovered)) {
    231 				realerr = EBUSY;
    232 				nodep = nodep->nm_nextp;
    233 				continue;
    234 			}
    235 
    236 			/*
    237 			 * Can't hold ntable_lock across call to do_unmount
    238 			 * because nm_unmount tries to acquire it.  This means
    239 			 * there is a window where another mount of vp can
    240 			 * happen so it is possible that after nm_unmountall
    241 			 * there are still some mounts.  This situation existed
    242 			 * without MT locking because dounmount can sleep
    243 			 * so another mount could happen during that time.
    244 			 * This situation is unlikely and doesn't really cause
    245 			 * any problems.
    246 			 */
    247 			mutex_exit(&ntable_lock);
    248 			if ((error = dounmount(vfsp, 0, crp)) != 0)
    249 				realerr = error;
    250 			mutex_enter(&ntable_lock);
    251 			/*
    252 			 * Since we dropped the ntable_lock, we
    253 			 * have to start over from the beginning.
    254 			 * If for some reasons dounmount() fails,
    255 			 * start from beginning means that we will keep on
    256 			 * trying unless another thread unmounts it for us.
    257 			 */
    258 			nodep = *NM_FILEVP_HASH(vp);
    259 		} else
    260 			nodep = nodep->nm_nextp;
    261 	}
    262 	mutex_exit(&ntable_lock);
    263 	return (realerr);
    264 }
    265 
    266 /*
    267  * Force the unmouting of a file descriptor from ALL of the nodes
    268  * that it was mounted to.  XXX: fifo_close() calls this routine.
    269  *
    270  * nm_umountall() may return EBUSY.
    271  * nm_unmountall() will keep on trying until it succeeds.
    272  */
    273 int
    274 nm_unmountall(vnode_t *vp, cred_t *crp)
    275 {
    276 	int error;
    277 
    278 	/*
    279 	 * Nm_umuontall() returns only if it succeeds or
    280 	 * return with error EBUSY.  If EBUSY, that means
    281 	 * it cannot acquire the lock on the covered vnode,
    282 	 * and we will keep on trying.
    283 	 */
    284 	for (;;) {
    285 		error = nm_umountall(vp, crp);
    286 		if (error != EBUSY)
    287 			break;
    288 		delay(1);	/* yield cpu briefly, then try again */
    289 	}
    290 	return (error);
    291 }
    292 
    293 /*
    294  * Mount a file descriptor onto the node in the file system.
    295  * Create a new vnode, update the attributes with info from the
    296  * file descriptor and the mount point.  The mask, mode, uid, gid,
    297  * atime, mtime and ctime are taken from the mountpt.  Link count is
    298  * set to one, the file system id is namedev and nodeid is unique
    299  * for each mounted object.  Other attributes are taken from mount point.
    300  * Make sure user is owner (or root) with write permissions on mount point.
    301  * Hash the new vnode and return 0.
    302  * Upon entry to this routine, the file descriptor is in the
    303  * fd field of a struct namefd.  Copy that structure from user
    304  * space and retrieve the file descriptor.
    305  */
    306 static int
    307 nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
    308 {
    309 	struct namefd namefdp;
    310 	struct vnode *filevp;		/* file descriptor vnode */
    311 	struct file *fp;
    312 	struct vnode *newvp;		/* vnode representing this mount */
    313 	struct vnode *rvp;		/* realvp (if any) for the mountpt */
    314 	struct namenode *nodep;		/* namenode for this mount */
    315 	struct vattr filevattr;		/* attributes of file dec.  */
    316 	struct vattr *vattrp;		/* attributes of this mount */
    317 	char *resource_name;
    318 	char *resource_nodetype;
    319 	statvfs64_t *svfsp;
    320 	int error = 0;
    321 
    322 	/*
    323 	 * Get the file descriptor from user space.
    324 	 * Make sure the file descriptor is valid and has an
    325 	 * associated file pointer.
    326 	 * If so, extract the vnode from the file pointer.
    327 	 */
    328 	if (uap->datalen != sizeof (struct namefd))
    329 		return (EINVAL);
    330 
    331 	if (copyin(uap->dataptr, &namefdp, uap->datalen))
    332 		return (EFAULT);
    333 
    334 	if ((fp = getf(namefdp.fd)) == NULL)
    335 		return (EBADF);
    336 
    337 	/*
    338 	 * If the mount point already has something mounted
    339 	 * on it, disallow this mount.  (This restriction may
    340 	 * be removed in a later release).
    341 	 * Or unmount has completed but the namefs ROOT vnode
    342 	 * count has not decremented to zero, disallow this mount.
    343 	 */
    344 
    345 	mutex_enter(&mvp->v_lock);
    346 	if ((mvp->v_flag & VROOT) ||
    347 	    vfs_matchops(mvp->v_vfsp, namefs_vfsops)) {
    348 		mutex_exit(&mvp->v_lock);
    349 		releasef(namefdp.fd);
    350 		return (EBUSY);
    351 	}
    352 	mutex_exit(&mvp->v_lock);
    353 
    354 	/*
    355 	 * Cannot allow users to fattach() in /dev/pts.
    356 	 * First, there is no need for doing so and secondly
    357 	 * we cannot allow arbitrary users to park on a node in
    358 	 * /dev/pts or /dev/vt.
    359 	 */
    360 	rvp = NULLVP;
    361 	if (vn_matchops(mvp, spec_getvnodeops()) &&
    362 	    VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
    363 	    (vn_matchops(rvp, devpts_getvnodeops()) ||
    364 	    vn_matchops(rvp, devvt_getvnodeops()))) {
    365 		releasef(namefdp.fd);
    366 		return (ENOTSUP);
    367 	}
    368 
    369 	filevp = fp->f_vnode;
    370 	if (filevp->v_type == VDIR || filevp->v_type == VPORT) {
    371 		releasef(namefdp.fd);
    372 		return (EINVAL);
    373 	}
    374 
    375 	/*
    376 	 * If the fd being mounted refers to neither a door nor a stream,
    377 	 * make sure the caller is privileged.
    378 	 */
    379 	if (filevp->v_type != VDOOR && filevp->v_stream == NULL) {
    380 		if (secpolicy_fs_mount(crp, filevp, vfsp) != 0) {
    381 			/* fd is neither a stream nor a door */
    382 			releasef(namefdp.fd);
    383 			return (EINVAL);
    384 		}
    385 	}
    386 
    387 	/*
    388 	 * Make sure the file descriptor is not the root of some
    389 	 * file system.
    390 	 * If it's not, create a reference and allocate a namenode
    391 	 * to represent this mount request.
    392 	 */
    393 	if (filevp->v_flag & VROOT) {
    394 		releasef(namefdp.fd);
    395 		return (EBUSY);
    396 	}
    397 
    398 	nodep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);
    399 
    400 	mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
    401 	vattrp = &nodep->nm_vattr;
    402 	vattrp->va_mask = AT_ALL;
    403 	if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL))
    404 		goto out;
    405 
    406 	filevattr.va_mask = AT_ALL;
    407 	if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL))
    408 		goto out;
    409 	/*
    410 	 * Make sure the user is the owner of the mount point
    411 	 * or has sufficient privileges.
    412 	 */
    413 	if (error = secpolicy_vnode_owner(crp, vattrp->va_uid))
    414 		goto out;
    415 
    416 	/*
    417 	 * Make sure the user has write permissions on the
    418 	 * mount point (or has sufficient privileges).
    419 	 */
    420 	if (!(vattrp->va_mode & VWRITE) &&
    421 	    secpolicy_vnode_access(crp, mvp, vattrp->va_uid, VWRITE) != 0) {
    422 		error = EACCES;
    423 		goto out;
    424 	}
    425 
    426 	/*
    427 	 * If the file descriptor has file/record locking, don't
    428 	 * allow the mount to succeed.
    429 	 */
    430 	if (vn_has_flocks(filevp)) {
    431 		error = EACCES;
    432 		goto out;
    433 	}
    434 
    435 	/*
    436 	 * Initialize the namenode.
    437 	 */
    438 	if (filevp->v_stream) {
    439 		struct stdata *stp = filevp->v_stream;
    440 		mutex_enter(&stp->sd_lock);
    441 		stp->sd_flag |= STRMOUNT;
    442 		mutex_exit(&stp->sd_lock);
    443 	}
    444 	nodep->nm_filevp = filevp;
    445 	mutex_enter(&fp->f_tlock);
    446 	fp->f_count++;
    447 	mutex_exit(&fp->f_tlock);
    448 
    449 	releasef(namefdp.fd);
    450 	nodep->nm_filep = fp;
    451 	nodep->nm_mountpt = mvp;
    452 
    453 	/*
    454 	 * The attributes for the mounted file descriptor were initialized
    455 	 * above by applying VOP_GETATTR to the mount point.  Some of
    456 	 * the fields of the attributes structure will be overwritten
    457 	 * by the attributes from the file descriptor.
    458 	 */
    459 	vattrp->va_type    = filevattr.va_type;
    460 	vattrp->va_fsid    = namedev;
    461 	vattrp->va_nodeid  = namenodeno_alloc();
    462 	vattrp->va_nlink   = 1;
    463 	vattrp->va_size    = filevattr.va_size;
    464 	vattrp->va_rdev    = filevattr.va_rdev;
    465 	vattrp->va_blksize = filevattr.va_blksize;
    466 	vattrp->va_nblocks = filevattr.va_nblocks;
    467 	vattrp->va_seq	   = 0;
    468 
    469 	/*
    470 	 * Initialize new vnode structure for the mounted file descriptor.
    471 	 */
    472 	nodep->nm_vnode = vn_alloc(KM_SLEEP);
    473 	newvp = NMTOV(nodep);
    474 
    475 	newvp->v_flag = filevp->v_flag | VROOT | VNOMAP | VNOSWAP;
    476 	vn_setops(newvp, nm_vnodeops);
    477 	newvp->v_vfsp = vfsp;
    478 	newvp->v_stream = filevp->v_stream;
    479 	newvp->v_type = filevp->v_type;
    480 	newvp->v_rdev = filevp->v_rdev;
    481 	newvp->v_data = (caddr_t)nodep;
    482 	VFS_HOLD(vfsp);
    483 	vn_exists(newvp);
    484 
    485 	/*
    486 	 * Initialize the vfs structure.
    487 	 */
    488 	vfsp->vfs_vnodecovered = NULL;
    489 	vfsp->vfs_flag |= VFS_UNLINKABLE;
    490 	vfsp->vfs_bsize = 1024;
    491 	vfsp->vfs_fstype = namefstype;
    492 	vfs_make_fsid(&vfsp->vfs_fsid, namedev, namefstype);
    493 	vfsp->vfs_data = (caddr_t)nodep;
    494 	vfsp->vfs_dev = namedev;
    495 	vfsp->vfs_bcount = 0;
    496 
    497 	/*
    498 	 * Set the name we mounted from.
    499 	 */
    500 	switch (filevp->v_type) {
    501 	case VPROC:	/* VOP_GETATTR() translates this to VREG */
    502 	case VREG:	resource_nodetype = "file"; break;
    503 	case VDIR:	resource_nodetype = "directory"; break;
    504 	case VBLK:	resource_nodetype = "device"; break;
    505 	case VCHR:	resource_nodetype = "device"; break;
    506 	case VLNK:	resource_nodetype = "link"; break;
    507 	case VFIFO:	resource_nodetype = "fifo"; break;
    508 	case VDOOR:	resource_nodetype = "door"; break;
    509 	case VSOCK:	resource_nodetype = "socket"; break;
    510 	default:	resource_nodetype = "resource"; break;
    511 	}
    512 
    513 #define	RESOURCE_NAME_SZ 128 /* Maximum length of the resource name */
    514 	resource_name = kmem_alloc(RESOURCE_NAME_SZ, KM_SLEEP);
    515 	svfsp = kmem_alloc(sizeof (statvfs64_t), KM_SLEEP);
    516 
    517 	error = VFS_STATVFS(filevp->v_vfsp, svfsp);
    518 	if (error == 0) {
    519 		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
    520 		    "unspecified_%s_%s", svfsp->f_basetype, resource_nodetype);
    521 	} else {
    522 		(void) snprintf(resource_name, RESOURCE_NAME_SZ,
    523 		    "unspecified_%s", resource_nodetype);
    524 	}
    525 
    526 	vfs_setresource(vfsp, resource_name);
    527 
    528 	kmem_free(svfsp, sizeof (statvfs64_t));
    529 	kmem_free(resource_name, RESOURCE_NAME_SZ);
    530 #undef RESOURCE_NAME_SZ
    531 
    532 	/*
    533 	 * Insert the namenode.
    534 	 */
    535 	mutex_enter(&ntable_lock);
    536 	nameinsert(nodep);
    537 	mutex_exit(&ntable_lock);
    538 	return (0);
    539 out:
    540 	releasef(namefdp.fd);
    541 	kmem_free(nodep, sizeof (struct namenode));
    542 	return (error);
    543 }
    544 
    545 /*
    546  * Unmount a file descriptor from a node in the file system.
    547  * If the user is not the owner of the file and is not privileged,
    548  * the request is denied.
    549  * Otherwise, remove the namenode from the hash list.
    550  * If the mounted file descriptor was that of a stream and this
    551  * was the last mount of the stream, turn off the STRMOUNT flag.
    552  * If the rootvp is referenced other than through the mount,
    553  * nm_inactive will clean up.
    554  */
    555 static int
    556 nm_unmount(vfs_t *vfsp, int flag, cred_t *crp)
    557 {
    558 	struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
    559 	vnode_t *vp, *thisvp;
    560 	struct file *fp = NULL;
    561 
    562 	ASSERT((nodep->nm_flag & NMNMNT) == 0);
    563 
    564 	/*
    565 	 * forced unmount is not supported by this file system
    566 	 * and thus, ENOTSUP, is being returned.
    567 	 */
    568 	if (flag & MS_FORCE) {
    569 		return (ENOTSUP);
    570 	}
    571 
    572 	vp = nodep->nm_filevp;
    573 	mutex_enter(&nodep->nm_lock);
    574 	if (secpolicy_vnode_owner(crp, nodep->nm_vattr.va_uid) != 0) {
    575 		mutex_exit(&nodep->nm_lock);
    576 		return (EPERM);
    577 	}
    578 
    579 	mutex_exit(&nodep->nm_lock);
    580 
    581 	mutex_enter(&ntable_lock);
    582 	nameremove(nodep);
    583 	thisvp = NMTOV(nodep);
    584 	mutex_enter(&thisvp->v_lock);
    585 	if (thisvp->v_count-- == 1) {
    586 		fp = nodep->nm_filep;
    587 		mutex_exit(&thisvp->v_lock);
    588 		vn_invalid(thisvp);
    589 		vn_free(thisvp);
    590 		VFS_RELE(vfsp);
    591 		namenodeno_free(nodep->nm_vattr.va_nodeid);
    592 		kmem_free(nodep, sizeof (struct namenode));
    593 	} else {
    594 		thisvp->v_flag &= ~VROOT;
    595 		mutex_exit(&thisvp->v_lock);
    596 	}
    597 	if (namefind(vp, NULLVP) == NULL && vp->v_stream) {
    598 		struct stdata *stp = vp->v_stream;
    599 		mutex_enter(&stp->sd_lock);
    600 		stp->sd_flag &= ~STRMOUNT;
    601 		mutex_exit(&stp->sd_lock);
    602 	}
    603 	mutex_exit(&ntable_lock);
    604 	if (fp != NULL)
    605 		(void) closef(fp);
    606 	return (0);
    607 }
    608 
    609 /*
    610  * Create a reference to the root of a mounted file descriptor.
    611  * This routine is called from lookupname() in the event a path
    612  * is being searched that has a mounted file descriptor in it.
    613  */
    614 static int
    615 nm_root(vfs_t *vfsp, vnode_t **vpp)
    616 {
    617 	struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
    618 	struct vnode *vp = NMTOV(nodep);
    619 
    620 	VN_HOLD(vp);
    621 	*vpp = vp;
    622 	return (0);
    623 }
    624 
    625 /*
    626  * Return in sp the status of this file system.
    627  */
    628 static int
    629 nm_statvfs(vfs_t *vfsp, struct statvfs64 *sp)
    630 {
    631 	dev32_t d32;
    632 
    633 	bzero(sp, sizeof (*sp));
    634 	sp->f_bsize	= 1024;
    635 	sp->f_frsize	= 1024;
    636 	(void) cmpldev(&d32, vfsp->vfs_dev);
    637 	sp->f_fsid = d32;
    638 	(void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
    639 	sp->f_flag	= vf_to_stf(vfsp->vfs_flag);
    640 	return (0);
    641 }
    642 
    643 /*
    644  * Since this file system has no disk blocks of its own, apply
    645  * the VOP_FSYNC operation on the mounted file descriptor.
    646  */
    647 static int
    648 nm_sync(vfs_t *vfsp, short flag, cred_t *crp)
    649 {
    650 	struct namenode *nodep;
    651 
    652 	if (vfsp == NULL)
    653 		return (0);
    654 
    655 	nodep = (struct namenode *)vfsp->vfs_data;
    656 	if (flag & SYNC_CLOSE)
    657 		return (nm_umountall(nodep->nm_filevp, crp));
    658 
    659 	return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, NULL));
    660 }
    661 
    662 /*
    663  * File system initialization routine. Save the file system type,
    664  * establish a file system device number and initialize nm_filevp_hash[].
    665  */
    666 int
    667 nameinit(int fstype, char *name)
    668 {
    669 	static const fs_operation_def_t nm_vfsops_template[] = {
    670 		VFSNAME_MOUNT,		{ .vfs_mount = nm_mount },
    671 		VFSNAME_UNMOUNT,	{ .vfs_unmount = nm_unmount },
    672 		VFSNAME_ROOT,		{ .vfs_root = nm_root },
    673 		VFSNAME_STATVFS,	{ .vfs_statvfs = nm_statvfs },
    674 		VFSNAME_SYNC,		{ .vfs_sync = nm_sync },
    675 		NULL,			NULL
    676 	};
    677 	static const fs_operation_def_t nm_dummy_vfsops_template[] = {
    678 		VFSNAME_STATVFS,	{ .vfs_statvfs = nm_statvfs },
    679 		VFSNAME_SYNC,		{ .vfs_sync = nm_sync },
    680 		NULL,			NULL
    681 	};
    682 	int error;
    683 	int dev;
    684 	vfsops_t *dummy_vfsops;
    685 
    686 	error = vfs_setfsops(fstype, nm_vfsops_template, &namefs_vfsops);
    687 	if (error != 0) {
    688 		cmn_err(CE_WARN, "nameinit: bad vfs ops template");
    689 		return (error);
    690 	}
    691 
    692 	error = vfs_makefsops(nm_dummy_vfsops_template, &dummy_vfsops);
    693 	if (error != 0) {
    694 		(void) vfs_freevfsops_by_type(fstype);
    695 		cmn_err(CE_WARN, "nameinit: bad dummy vfs ops template");
    696 		return (error);
    697 	}
    698 
    699 	error = vn_make_ops(name, nm_vnodeops_template, &nm_vnodeops);
    700 	if (error != 0) {
    701 		(void) vfs_freevfsops_by_type(fstype);
    702 		vfs_freevfsops(dummy_vfsops);
    703 		cmn_err(CE_WARN, "nameinit: bad vnode ops template");
    704 		return (error);
    705 	}
    706 
    707 	namefstype = fstype;
    708 
    709 	if ((dev = getudev()) == (major_t)-1) {
    710 		cmn_err(CE_WARN, "nameinit: can't get unique device");
    711 		dev = 0;
    712 	}
    713 	mutex_init(&ntable_lock, NULL, MUTEX_DEFAULT, NULL);
    714 	namedev = makedevice(dev, 0);
    715 	bzero(nm_filevp_hash, sizeof (nm_filevp_hash));
    716 	vfs_setops(&namevfs, dummy_vfsops);
    717 	namevfs.vfs_vnodecovered = NULL;
    718 	namevfs.vfs_bsize = 1024;
    719 	namevfs.vfs_fstype = namefstype;
    720 	vfs_make_fsid(&namevfs.vfs_fsid, namedev, namefstype);
    721 	namevfs.vfs_dev = namedev;
    722 	return (0);
    723 }
    724 
    725 static mntopts_t nm_mntopts = {
    726 	NULL,
    727 	0
    728 };
    729 
    730 static vfsdef_t vfw = {
    731 	VFSDEF_VERSION,
    732 	"namefs",
    733 	nameinit,
    734 	VSW_HASPROTO,
    735 	&nm_mntopts
    736 };
    737 
    738 /*
    739  * Module linkage information for the kernel.
    740  */
    741 static struct modlfs modlfs = {
    742 	&mod_fsops, "filesystem for namefs", &vfw
    743 };
    744 
    745 static struct modlinkage modlinkage = {
    746 	MODREV_1, (void *)&modlfs, NULL
    747 };
    748 
    749 int
    750 _init(void)
    751 {
    752 	namenodeno_init();
    753 	return (mod_install(&modlinkage));
    754 }
    755 
    756 int
    757 _fini(void)
    758 {
    759 	return (EBUSY);
    760 }
    761 
    762 int
    763 _info(struct modinfo *modinfop)
    764 {
    765 	return (mod_info(&modlinkage, modinfop));
    766 }
    767